SEO-Monitoring mit R, AWS und Shiny


Dies ist der vorläufig letzte Teil der Serie über SEO mit R und AWS. Im ersten Teil hatten wir die AWS-Instanz mit RStudio vorbereitet, im zweiten Teil eine kleine SEO-Analyse durchgeführt, im dritten Teil ging es um die Erstellung eines Sichtbarkeitsindexes und eines “actionable Reportings”. In diesem Teil geht es darum, dass es selbst dem hartgesottensten Data Scientist zu anstrengend ist, die einzelnen Skripte täglich durch RStudio laufen zu lassen. Das SEO Monitoring soll also über eine ansprechende Oberfläche laufen.

GUI-Entwicklung mit Shiny

Die Entwickler von RStudio haben mit Shiny ein Framework zur Verfügung gestellt, welches Interaktion mit Daten ermöglicht, und das mit wenigen Zeilen Code. Glücklicherweise wird Shiny in dem AMI, das wir in Teil 1 dieser Serie installiert hatten, gleich mitgeliefert.

Der Code unterteilt sich in zwei Teile, dem Server-Code und dem UI-Code; beide Teile können in eine Datei, die dann als app.R in einen speziellen Ordner in RStudio abgelegt wird. In dem Server-Teil werden die einzelnen Funktionen genutzt, die wir für die ersten Teile dieser Serie verwendet haben (darum ist hier auch nicht der ganze Code zu finden).

`
server <- function(input, output, session) {

get data from db and create dropdown-items

sites <- unique(results$website)
output$moreControls <- renderUI({
selectInput(“moreControls”, “Website auswählen”, choices=sites)
output$sviPlot <- renderPlot({

Sichtbarkeitsindex-Code

})
output$actions <- renderTable({

Actionable Daten-Code

})
}
`

Im UI-Teil wird dann einfach nur das UI zusammengeschraubt:

<br /> ui <- fluidPage(<br /> title = "Tom's SEO Tool",<br /> uiOutput("moreControls"),<br /> hr(),<br /> plotOutput("sviPlot"),<br /> tableOutput("actions")<br /> )<br />

Und zum Schluß wird die App dann gestartet:

`

Run the application

shinyApp(ui = ui, server = server)
`

Das wars. Simpel und einfach:

Nicht unbedingt schön für einen Kunden, aber vollkommen ausreichend, um ein Reporting für sich selbst zu bauen. Links oben wähle ich die Webseite aus, für die ich das Reporting haben möchte, und nachdem die Skripte durchgelaufen sind, erscheint der Sichtbarkeitsindex-Plot sowie die Tabelle mit den größten Ranking-Verlusten. Das Erstellen dieses Dashboards hat gerade mal 20 Minuten gedauert (ok, fairerweise hatte ich auch schon mal andere Dashboards mit Shiny gebaut, so dass ich etwas Erfahrung hatte

Nächste Schritte

In meinem gegenwärtigen Setup habe ich einfach nur den Code genutzt, den ich bisher verwendet hatte, was aber auch bedeutet, dass es erst mal dauert, bis etwas zu sehen ist. Besser wäre es, wenn die Daten jeden Tag automatisch ausgewertet werden und das Dashboard dann einfach nur die aggregierten Daten abruft. Steht auf meiner Aufgabenliste.

Dann wäre es schön, wenn man in der Tabelle auf einen Eintrag klicken könnte, um dann diesen weiter zu analysieren. Steht auch auf meiner Aufgabenliste.

Eine Verbindung zu Google Analytics wäre toll.

Nicht jedes Keyword ist interessant und sollte in den Report kommen.

Alles gute Punkte, die ich beizeiten mal angehen könnte, und vor allem guter Stoff für weitere Posts Und ich bin immer offen für weitere Ideen

Fazit

Mit etwas Gehirnschmalz, wenig Code und der Hilfe von Amazon Web Services und R haben wir ein automatisiertes und kostenloses SEO-Reporting gebaut. Natürlich bieten Sistrix & Co noch mehr Funktionen. In diesem Ansatz geht es vor allem darum, die kostenlos zur Verfügung stehenden Daten aus der Webmaster Console besser zu nutzen. Denn sind wir mal ehrlich: Daten haben wir in der Regel genug. Wir machen nur meistens nicht viel daraus.

Diese Vorgehensweise hat noch einen Vorteil: Die Daten aus der Search Console sind nach 90 Tagen weg. Man kann nicht weiter zurück schauen. Hier aber bauen wir ein Archiv auf und können uns auch längerfristige Entwicklungen ansehen.

Ein eigener Sichtbarkeitsindex mit R und AWS


In der dritten Folge über Suchmaschinenoptimierung mit R und AWS geht es um das Erstellen eines eigenen Sichtbarkeitsindex, um eine aggregierte Übersicht über das Ranking vieler Keywords zu erhalten. Im ersten Teil hatten wir uns angeschaut, wie man mit R und einer AWS Free Tier EC2-Instanz automatisiert Daten aus der Webmaster Console zieht, im zweiten Teil ging es um erste Analysen anhand von Klickraten auf Positionen.

Was macht ein Sichtbarkeitsindex?

Dazu schauen wir erst einmal, was ein Sichtbarkeitsindex überhaupt leisten soll. Bei Sistrix ist der Sichtbarkeitsindex unabhängig von saisonalen Effekten, was ganz charmant ist, denn so weiß man schon im Sommer, ob man mit winterreifen.de einen Blumentopf gewinnen kann. Sowas kann zum Beispiel dadurch gelöst werden, dass man die durchschnittliche Anzahl von Suchen aus dem AdWords Keyword Planner nutzt. Dumm nur, dass dieses Tool nur noch dann einigermaßen nützliche Werte ausspuckt, wenn man auch ausreichend Budget in Google AdWords ausgibt. Dieser Ansatz fällt schon mal flach, denn wir wollen unser Monitoring so günstig wie möglich, bestenfalls kostenlos halten.

Sistrix hat den Nachteil, dass es a) für Studenten, die meine SEO-Kurse besuchen, trotz des günstigen Preises immer noch zu teuer ist und b) meine kleinen Nischengeschichten eben nicht immer vorhanden sind in der Sistrix-Keyword-Datenbank. Sistrix und Co. sind vor allem dann spannend, wenn man eine Seite mit anderen Seiten vergleichen will (idealerweise aus der gleichen Industrie mit dem gleichen Portfolio). Eine abstrakte Zahl wie ein Sichtbarkeitsindex von 2 ist ansonsten ziemlich sinnfrei. Diese Zahl ergibt nur dann Sinn, wenn ich sie in Bezug zu anderen Webseiten setzen kann und/oder wenn ich daraus die Entwicklung meiner eigenen Webseiten-Rankings im Zeitverlauf verfolgen kann. Die Zahl selbst ist dabei immer noch nicht aussagekräftig, denn in was für einer Metrik wird gemessen? Wenn ich 2 Kilo abnehme, dann ist die Metrik klar. Aber 0,002 SI abnehmen? Wie viele Besucher sind das?

Wir wollen uns einen Index bauen, der es uns ermöglicht zu schauen, ob sich unser Ranking über sehr viele Keywords im Zeitverlauf verändert. Wie sich unsere Marktbegleiter entwickeln, das ließe sich nur ablesen, wenn man Google scrapte, und das ist nicht erlaubt.

Sichtbarkeitsindex auf Basis der Webmaster Console

Offensichtlich ist es besser, mit einem Suchbegriff auf Platz 3 zu ranken, der 100 Mal am Tag gesucht wird als für einen Suchbegriff auf Platz 1, der nur 2 Mal am Tag gesucht wird. Die Anzahl der Suchen sollte also eine Rolle spielen in unserem Sichtbarkeitsindex. Das Suchvolumen über den AdWords Keyword Planner schließen wir aus den oben genannten Gründen aus, die einzige Quelle, die uns bleibt, sind die Impressions aus der Webmaster Console. Sobald wir auf der ersten Seite sind und weit genug oben (ich bin nicht sicher, ob es als Impression zählt, wenn man auf Platz 10 ist und nie im sichtbaren Bereich war), sollten wir die Anzahl der Impressions aus der Webmaster Console nutzen können, und das sogar auf Tagesbasis!

Kleiner Health-Check für das Keyword “Scalable Capital Erfahrungen” (AdWords / reale Daten aus der Webmaster Console):

  • 2400 / 1795 (September, aber nur halber Monat)
  • 5400 / 5438 (Oktober)
  • 1000 / 1789 (November)

Für September und Oktober sieht das gut aus, nur im November ist es etwas seltsam, dass ich knapp 80% mehr Impressions hatte als es angeblich Suchen gab. Irgendetwas muß ausserdem im September/Oktober passiert sein, dass Scalable Capital plötzlich so viele Suchen hatte. Tatsächlich war das auch im Traffic auf meiner Seite zu sehen. Den ersten Punkt kriegen wir nicht geklärt und akzeptieren, dass auch die AdWords-Zahlen nicht perfekt sind.

Wie unterschiedlich die Sichtbarkeits-Indices sind je nach Gewichtung, wird in den folgenden Abbildungen deutlich:

  • Im einfachsten Modell wird einfach nur 11 minus Position gerechnet, alles oberhalb von (größer als) Position 10 bekommt dann 1 Punkt. Pro Ergebnis werden die Daten für jeden Tag zusammengerechnet. Dieses Modell hat den Nachteil, dass ich ganz schnell nach oben klettern kann, selbst wenn ich nur Begriffe auf Platz 1 bin, die nur einmal im Monat gesucht werden.
  • Im zweiten Modell wird das gleiche Vorgehen gewählt, nur dass hier der Wert mit den Impressions multipliziert wird
  • Im dritten Modell wird die durchschnittliche CTR auf der SERP aus dem zweiten Teil dieser Serie mit den Impressions multipliziert.

Schaut man sich nun den tatsächlichen Traffic an, so sieht man, dass das 3. Modell dem Traffic schon sehr nahe kommt. Die Ausschläge im echten Traffic sind nicht ganz so stark wie im Index, und zum Schluss bekomme ich nicht so viel Traffic, allerdings kann das daran liegen, dass die tatsächliche CTR unter der erwarteten CTR liegt.

Alternativer Ansatz mit der Webmaster Console

Wenn man sich die Plots anschaut, dann wird aber klar, dass dieser Ansatz mit dem Impressions auf Tagesbasis wenig Sinn ergibt. Denn wenn die Kurve nach unten geht, dann bedeutet das nicht, dass ich auch etwas tun kann, denn eventuell wird nun mal einfach nur weniger nach diesem Thema gesucht und meine Rankings haben sich gar nicht geändert (normalerweise schreibt man ja nur darüber, was funktioniert, aber ich finde auch die Misserfolge spannend, denn daraus kann man eine Menge lernen :-)). Genau deswegen wird Sistrix wohl auch die saisonalen Schwankungen rausrechnen.

Alternativ könnte man einfach den Durchschnitt über alle Impression-Daten eines Keyword-Landing-Page-Paares bilden und diesen Durchschnitt zur Berechnung nutzen, wieder mit der gewichteten CTR pro Position. Das Gute an diesem Ansatz ist, dass sich saisonale oder temporäre Ausschläge ausgleichen. Geplottet sieht das wie folgt aus:

Dieser Plot sieht dem ersten Plot sehr ähnlich, was aber nicht bedeutet, dass das immer so sein muss. Doch wenn ich mir die Sistrix-Werte anschaue (auch wenn ich da auf einem ganz niedrigen Niveau unterwegs bin), dann sieht das schon sehr ähnlich aus.

Von Daten zur Handlungsrelevanz

Nun haben wir einen Plot, der uns die gewichtete Entwicklung unserer Rankings anzeigt, aber was machen wir nun damit? So richtig “actionable” ist das nicht. Spannend wird es erst, wenn wir uns zusätzlich anschauen, welche Rankings sich am meisten verändert und einen Einfluss auf unseren Sichtbarkeitsindex haben. Dazu nehmen wir uns wieder für jedes Keyword-Landing-Page-Paar zunächst das minimalste Ranking (minimal weil niedrig, und niedriger als Platz 1 gehts nicht) und dann das aktuelle Ranking. Zum Schluss berechnen wir das Delta und sortieren danach:

Je höher das Delta, desto größer ist sozusagen der Verlust an Ranking-Plätzen. Und desto größer der Handlungsbedarf, vorausgesetzt, dass das Keyword auch wirklich interessant ist. In meinem Beispiel fände ich es zum Beispiel nicht schlecht für “seo monitoring” zu ranken, schließlich sind die Artikel aus dieser Reihe relevant dafür. Man könnte nun noch gewichten anhand der Impressions oder dem Sichtbarkeitsindex, den wir vorher gewählt haben:

Das sieht schon spannender aus: Tatsächlich sind einige Suchanfragen oben (nach “Actionability” sortiert), die ich ganz interessant finde. Und nun könnte man das mit den Daten aus dem zweiten Teil verbinden und ein Dashboard bauen… dazu mehr im vierten Teil

Warum die durchschnittliche Sitzungsdauer in Analytics kompletter Quatsch ist


Ich beschäftige mich seit über 20 Jahren mit Webanalyse, angefangen mit Serverlogfiles und heute mit zum Teil abgefahrenen Implementierungen von Tracking-Systemen. Die Möglichkeiten werden immer besser, aber nicht alles ist besser geworden. Denn ein Aberglaube ist einfach nicht totzukriegen, nämlich dass Time on Site oder die “durchschnittliche Sitzungsdauer” eine gute Metrik ist, beziehungsweise dass die angegebenen Werte überhaupt stimmen, Darum hier einmal schwarz auf weiß: In einer Standardimplementierung wird die Time on Site nicht richtig gemessen, egal ob in Adobe Analytics oder Google Analytics oder Piwik oder sonstwas.

Warum die durchschnittliche Sitzungsdauer nicht richtig gemessen wird

Die Erklärung, warum die Zeitangaben nicht stimmen können, ist ganz einfach. In einer Standardinstallation von Google/Adobe Analytics/[place your system here] wird jedes Mal eine Messung durchgeführt, wenn der Nutzer eine Aktion auslöst. Er kommt zum Beispiel um 13:00 Uhr auf eine Website, und dann wird das erste Mal das Tracking-Pixel ausgelöst. Der Nutzer schaut sich ein wenig um und klickt dann um 13:01 auf einen Link, so dass er auf eine weitere Seite der gleichen Website kommt, wo wieder der Tracking-Pixel gefeuert wird. Nun können wir ausrechnen, dass er bisher 1 Minute auf der Website verbracht hat, denn wir haben zwei Messpunkte mit unterschiedlichen Zeitstempeln. Wir messen Zeit hier mit der zeitlichen Distanz zwischen zwei Seiten.

Auf der zweiten Seite, auf der er sich nun befindet, hält sich der Nutzer länger auf, denn hier findet er das, wonach er gesucht hat. Er liest einen Text, und um 13:05, also nach 4 Minuten, ist sein Informationsbedürfnis befriedigt, so dass er die Seite verlässt. Er war nun also insgesamt 5 Minuten auf der Website. Analytics weiß aber nur von der 1. Minute und wird auch nur diese 1 Minute in die Statistik aufnehmen. Denn beim Verlassen der Seite wird nichts mehr gefeuert. Wie oben geschrieben: Wir messen Zeit mit der zeitlichen Distanz zwischen zwei Seiten. Zeitliche Distanz zwischen 1. und 2. Seite: 1 Minute. Zeitliche Distanz zwischen 2. und Exit: Nicht messbar, denn es fehlt die nächste Seite. Und das ist den meisten Anwendern nicht klar. Die Zeit, die ein Nutzer auf der letzten Seite verbringt, wird nicht gemessen.

Kann Analytics nicht messen, wenn ein Nutzer die Seite verlässt? Nein, kann es nicht, egal welches System. Zumindest nicht in der Standard-Installation. Diese kann man natürlich anpassen. Ansonsten: Kommt ein Nutzer auf eine Webseite und schaut sich nur eine Seite an, dann wird keine Zeit gemessen. Auch wenn er 10 Minuten auf dieser einen Seite verbringt, es fließt nicht ein in die durchschnittliche Sitzungsdauer. Da ein Eine-Seiten-Besuch nicht selten ist, fehlen also ziemlich viele Daten.

Ist das denn wirklich so schlimm?

Macht das denn wirklich so viel aus? Ja, macht es. Häufig heißt es vom erstaunten Anwender, dass man mit den angegebenen Zahlen doch wenigstens einen Anhaltspunkt hätte. Was kann man mit einem Anhaltspunkt anfangen, der komplett falsch ist? Natürlich mag sich niemand gerne eingestehen, dass alle bisherigen Daten falsch waren und die darauf basierenden Entscheidungen ebenso.

Um die Unterschiede zu verdeutlichen, hier ein paar Datenpunkte. Bis August 2017 betrug die durchschnittliche Sitzungsdauer auf meiner Seite im Durchschnitt 1 Minute (rote Linie, hier im Vergleich zum Vorjahr). Ab dem August 2017 steigt die durchschnittliche Sitzungsdauer auf 5 Minuten (blaue Linie). Die Time on site hat sich verfünffacht und wirkt auch viel realistischer, da die meisten Inhalte auf meiner Seite nicht in 1 Minute gelesen werden können. Allerdings sind selbst diese 5 Minuten nicht die tatsächliche durchschnittliche Sitzungszeit, sondern nur eine Annäherung.

Wie kommt man zu besseren Zahlen?

Wie kommt es überhaupt, dass nun mehr von der Zeit gemessen wird? In einem anderen Artikel hatte ich über das Messen der Scrolltiefe geschrieben, und hier wird beim Erreichen von 25%, 50%, 75% und 100% der Seitenlänge ein Event gefeuert. Mit jedem dieser Event wird auch ein Zeitstempel mitgesendet. Scrollt ein Nutzer herunter, so wird also auch von der letzten Seite eines Besuchs eine Zeitspanne gemessen, und zwar bis zum Auslösen des letzten Events. Es ist nicht unwahrscheinlich, dass die Nutzer sogar noch mehr Zeit auf dieser Seite verbringen, denn vielleicht lesen Sie noch etwas im unteren Abschnitt, scrollen aber nicht mehr weiter.

Warum, könnte die Frage nun lauten, wird nicht einfach jede Sekunde ein Event ausgelöst, solange der Nutzer auf der Seite ist? Dann hätte man doch eine genaue Sitzungsdauer. Technisch ist das tatsächlich möglich, aber bei Google Analytics zum Beispiel erlaubt die kostenlose Version maximal 10 Millionen Hits pro Monat (Hit = Server Call), bei Adobe wird jeder einzelne Hit abgerechnet. Ich dürfte mir bei Google Analytics pro Tag also 333.333 Hits erlauben, und wenn wir von einer tatsächlichen durchschnittlichen Sitzungsdauer von 6 Minuten (360 Sekunden) ausgehen, dann dürfte ich weniger als 1.000 Nutzer täglich haben, damit mir nicht der Saft abgedreht wird. Und damit haben wir noch nichts anderes gemessen. Selbst bei der Scrolltiefen-Messung wären bei vielen Seiten schon so viele Server Calls ausgelöst, dass man sich das schlichtweg nicht leisten kann. Hier kann aber zumindest bei einem Random Sample von Nutzern gemessen werden, um zumindest eine Annäherung zu erhalten, die diesen Namen verdient.

Warum überhaupt die durchschnittliche Sitzungsdauer verwenden?

Diese Metrik wird häufig dann verwendet, wenn keine “harten” Conversions existieren, zum Beispiel wenn Awareness eines der Marketing-Ziele ist und zunächst einmal nur Nutzer auf die Seite kommen sollen. Vielleicht wird aber auch nur deswegen viel Zeit verplempert, weil die gewünschten Informationen nicht gefunden, aber dringend benötigt werden (schon mal einen Treiber auf hp.com gesucht?); mit anderen Worten, vielleicht ist eine kürzere Zeit sogar besser?

Wie immer ist es eine Frage, wie gut segmentiert wird. Bei hp.com wäre eine Metrik wie “time to download” gut, bei einer reinen Content-Seite wäre die Scrolltiefe gepaart mit der auf der Seite verbrachten Zeit ein guter Indikator dafür, wie gut mit dem Content interagiert wird. Dazu müsste noch einbezogen werden, wie viel Inhalt auf einer Seite vorhanden ist. Dies kann zum Beispiel mit Custom Dimensions abgefrühstückt werden. Mein Lieblingsspruch dazu: Jede Minute, die ein Nutzer auf der Seite meines Kunden verbringt, kann er nicht auf der Webseite seines Marktbegleiters verbringen.

Spannend ist die echte durchschnittliche Sitzungsdauer aber auch, weil das Konzept von holistischen Landingpages immer weitere Kreise zieht. Da Google zum Teil auch Signale erhält, wie lange jemand auf einer Seite war (zum Beispiel durch Rückkehr auf eine Suchergebnisseite), sollte es auch jeden Suchmaschinenoptimierer interessieren, wie lange jemand tatsächlich auf einer Seite war und welche Teile des holistischen Contents tatsächlich gelesen wurden (schließlich wird der Content ja für Nutzer geschrieben und nicht für den GoogleBot… oder?

Fazit

Die durchschnittliche Sitzungsdauer oder Time on Site in jedem Analytics-System liefert in einer Standard-Installation falsche Zahlen, was den wenigsten Anwendern klar ist. Abhilfe schafft hier das Auslösen von Events, zum Beispiel zum Scroll Tracking. Wie so oft: A Fool with a Tool ist still a Fool. Solange man sich nicht damit auseinander setzt, wie ein Tool etwas misst, darf man sich nicht wundern, wenn die daraus gewonnenen Schlüsse falsch sind. Das gilt für Analytics genau so wie für Google Trends oder Similar Web

“Actionable” SEO-Reporting mit R und AWS


In dem ersten Teil ging es darum, wie mit R und einer zunächst kostenlosen AWS-Instanz ein automatisiertes SEO-Monitoring erstellt wird. Dabei wird die Webmaster Console per API jeden Tag abgefragt, und die Daten werden in eine Datenbank geschrieben. Das Datensammeln allein bringt natürlich nichts, irgendwas sollten wir damit auch anfangen, und mein Mantra, das jeder Student in meinen Veranstaltungen mehrmals pro Tag hört, ist “Daten – Information – Aktion”. In den meisten Abhandlungen steht Wissen an der Stelle von Aktion, denn die Verarbeitung von Informationen erst schafft Wissen. Im Bereich der Datenanalyse oder sogar Data Science aber geht es häufiger darum, nicht nur zu wissen, sondern mit dem Wissen auch etwas zu tun, idealerweise zu wissen, was zu tun ist. Der Grund, warum die meisten Reportings nicht gelesen werden, ist in der Regel, dass keine Aktion abgeleitet werden kann. 5 Likes mehr diese Woche. Ja und? Was mache ich jetzt morgen anders? Wir wollen also nicht einfach nur ein SEO-Reporting bauen, sondern ein SEO-Reporting erstellen, das uns sagt, wo etwas zu tun ist und was man tun sollte. “Actionable” heißt es auf Neudeutsch, und eine richtig schöne Übersetzung gibt es tatsächlich nicht im Deutschen. “Handlungsrelevant”? Ist irgendwie nicht das Gleiche. Leben wir also zunächst mit diesem Begriff.

Der Mehrwert der Webmaster Console-API

Schauen wir uns erst einmal die Daten an, die wir aus der Webmaster Console bekommen haben. Hier ist nämlich schon eine Besonderheit zu sehen, die wir im Interface nicht bekommen. Dort bekommen wir entweder die Suchanfragen oder die Seiten, auf die die Nutzer nach dem Klick auf ein Suchergebnis kamen, aber nicht beides gleichzeitig. Das ist schon ein Mehrwert, denn wir können sozusagen Pärchen bilden aus Keyword und Landing Page. Eine Landing Page kann mehrere Keywords haben, umgekehrt übrigens auch, wenn für ein Keyword mehrere Seiten von einem Host ranken. Wir nutzen für unsere Auswertung diese Pärchen, um einen unique Identifier zu haben, zum Beispiel indem wir beides zusammenpacken und daraus einen MD5-Hash basteln (dem genauen Beobachter wird auffallen, dass die gleiche Kombination zwei Mal an einem Tag auftritt, aber das sieht nur so aus, denn die eine Version der URL hat noch ein /amp/ dahinter, was aber in der Tabelle nicht zu sehen ist).

Sollten wir das nicht schon beim Schreiben in die Tabelle getan haben, so tun wir es jetzt:

library(digest)<br /> i <- 1<br /> newResults <- results<br /> newResults["Hash"] <- NA<br /> for (i in i:nrow(newResults)) {<br /> newResults$Hash[i] <- digest(paste(newResults$query[i],newResults$page[i],sep=""))<br /> i <- i+1<br /> }

Sicherlich geht das mit apply noch hübscher, aber wir sind gerade im Hacker-Modus, nicht im Schön-Programmier-Modus

Eine weitere Besonderheit ist, dass wir uns wahrscheinlich im Interface nicht die Mühe machen werden, uns die Daten für jeden Tag einzeln anzuschauen. Das ist aber extrem hilfreich, denn die Voreinstellung in der Webmaster Console sind die letzten 28 Tage, und hier wird ein Durchschnitt für die einzelnen Werte berechnet. Die, die mich näher kennen, werden jetzt betreten auf den Boden schauen, denn ich sage hier immer wieder dasselbe: Der Durchschnitt, und zwar das arithmetische Mittel, ist der Feind der Statistik. Denn diese Art des Durschnitts zeigt uns nicht die Ausschläge. Dazu ein andermal mehr, wenn ich das Skript zur Datenanalyse-Veranstaltung mal online stelle. Der Punkt ist hier, dass ich im arithmetischen Mittel des Interfaces sehe, dass ein Keyword auf einer bestimmten Position gewesen ist in den letzten 28 Tagen, aber tatsächlich ist die Range pro Tag viel interessanter, denn wenn ich sie pro Tag abgreife, dann kann ich genauere Trends abbilden. Zu guter Letzt schenkt uns die Webmaster Console auch Impressions sowie Keywörter, die nicht in den Datenbanken der gängigen Tools zu finden sind. Sistrix, so sehr ich es auch liebgewonnen habe, findet mich nicht für “Cookidoo” oder “Scalable Capital”. Klar, ich könnte Sistrix meine Webmaster Console-Daten zur Verfügung stellen, aber das darf ich leider nicht bei jedem Projekt tun.

Da wir die Daten jeden Tag abfragen, können wir nun durch die Tabelle laufen und uns die Werte für den erstellten Identifer holen, so dass wir alle Werte für eine Keyword-Landingpage-Kombination erhalten und diese plotten können. Auf der x-Achse haben wir den Zeitverlauf, auf der y-Achse die Position. Hier sind übrigens zwei kleine R-Tricks zu sehen. R plottet nämlich normalerweise auf der Y-Achse vom niedrigen Wert nach oben zu einem höheren Wert. Und dann wird genau der Bereich erwischt, der für uns interessant ist, nämlich nicht alle Positionen von 1 bis 100, sondern nur der Bereich, wofür gerankt wurde. Der Plot benötigt nur wenige Zeilen Code:

maxValue <- max(currentQuery$position)<br /> minValue <- min(currentQuery$position)<br /> x <- minValue:maxValue<br /> query <- currentQuery$query[1]<br /> plot(df$Date,df$Position,ylim = rev(range(x)))<br /> title(main=query)

Wir sehen auf unserem Plot die Entwicklung des Rankings für ein Keyword, aber so richtig “actionable” ist es noch nicht. Wir schauen uns nun einmal daneben die CTR an:

Je höher die Position, desto höher die Klickrate. Das ist offensichtlich. Aber in diesen beiden Plots sieht man, dass zuerst die Klickrate runterging und dann die Position. Nicht dass die Klickrate der einzige Rankingfaktor wäre, aber eine schlechte Klickrate auf ein Ergebnis zeugt von einer suboptimalen wahrgenommenen Relevanz, und keine Suchmaschine möchte, dass die Ergebnisse als weniger relevant wahrgenommen werden. Hier wäre also ein Blick auf Titel und Description eine gute Handlungsempfehlung. Aber woher wissen wir eigentlich, was eine gute CTR für eine Position ist? Dazu können wir zum Beispiel einen Plot aus den eigenen Rankings nehmen:

Und diesen könnten wir vergleichen mit den Ergebnissen von Advanced Web Ranking, die Plots aus den Webmaster Console-Daten der Vielzahl ihrer Kunden erstellen. Jedes Land und jede Industrie ist anders, auch hängt die CTR von der SERP ab, ob vielleicht noch andere Elemente vorhanden sind, die die CTR beeinflussen. Aber allein aus dem Plot sieht man, dass bestimmte CTRs auf bestimmte Ergebnisse suboptimal sind. Hier müsste also “nur” noch ein Report erstellt werden, welche Keyword-Landingpage-Kombinationen unterdurchschnittlich sind.

Schauen wir uns den Plot mit den CTRs pro Position noch einmal genauer an, dann sehen wir ein paar ungewöhnliche Dinge. Zum einen gibt es immer ein paar Ergebnisse, wo ich egal auf welcher Position immer 100% CTR habe. Und dann gibt es zwischen den Positionen 1, 2, 3 und so weiter ganz viel Rauschen. Letzteres erklärt sich ganz leicht, denn die API gibt uns wie oben beschrieben durchschnittliche Positionen mit Nachkommastellen. Wir müssten also nur runden, um tatsächliche Positionen zu erhalten. Die 100% CTR betrifft vor allem Ergebnisse mit wenig Impressions. Werden zum Beispiel alle Ergebnisse rausgefiltert, die weniger als 10 Impressions pro Tag hatten, dann sieht das Bild schon anders aus:

Und siehe da, ich habe gar nicht so viele Nummer 1-Platzierungen mit mehr als einer homöopathischen Dosis an Impressions. Aber wenn ich die Augen etwas zukneife, so könnte ich eine Linie sehen. Und tatsächlich, berechnen wir die Mittelwerte (hier mit Summary), dann sehe ich eine nicht-lineare absteigende Kurve im Mean:<br /> Position 1:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.2143 0.3971 0.4929 0.4828 0.5786 0.7059<br /> Position 2:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.0000 0.2667 0.4118 0.3744 0.5000 0.7692<br /> Position 3:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.0000 0.1176 0.1818 0.2217 0.3205 0.5769<br /> Position 4:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.00000 0.08333 0.18182 0.17266 0.26667 0.45454<br /> Position 5:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.0000 0.1240 0.1579 0.1584 0.2053 0.3200<br /> Position 6:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.00000 0.06977 0.11765 0.12223 0.16667 0.30769<br /> Position 7:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.00000 0.05043 0.09091 0.09246 0.13229 0.22222<br /> Position 8:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.00000 0.00000 0.03880 0.04594 0.08052 0.19048<br /> Position 9:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.00000 0.00000 0.00000 0.01412 0.01205 0.16514<br /> Position 10:<br /> Min. 1st Qu. Median Mean 3rd Qu. Max.<br /> 0.000000 0.000000 0.000000 0.010284 0.004045 0.093023

Im nächsten Schritt müssen wir also “nur” noch auswerten, welches Ergebnis unter einer bestimmten Grenze der CTR liegt. Glücklicherweise existiert in der Statistik eine Maßzahl, die uns hilft, die Streuung um einen Mittelwert zu identifizieren, die Standardabweichung. Diese wird hier jetzt nicht erklärt (aber im Skript zur Datenanalyse-Veranstaltung). Aber auf dem Weg zur Standardabweichung sollten wir uns eine Übersicht über die Verteilung der CTRs ansehen. Wie man schön sehen kann, sieht das nach einer Normalverteilung aus. Nun berechnen wir guten Gewissens die Standardabweichung pro Position:

<br /> [1] 0.139202<br /> [2] 0.1691641<br /> [3] 0.1405702<br /> [4] 0.1116699<br /> [5] 0.07492808<br /> [6] 0.07420478<br /> [7] 0.05702427<br /> [8] 0.05028635<br /> [9] 0.03001044<br /> [10] 0.02134183

Für die Position 1 könnten wir also rechnen Mittelwert minus Standardabweichung gleich Ergebnis mit Klickrate, das Beachtung verdient, hier

0.4828 - 0.139202 = 0.3436019

Alle Ergebnisse mit einer gerundeten Position 1 und einer CTR von 0.43… verdienen also Beachtung. In meinem Fall sind das die Suchanfragen für scalable capital erfahrung und cookidoo. Zwar gibt es auch CTRs an manchen Tagen über dem Durchschnitt, aber manchmal fallen sie drunter. Dies wird dann für jede Position wiederholt.

Zu viele Daten?

Wir haben nun ein Problem. Denn mein Blog ist noch eine relativ kleine Seite. Was machen wir mit einer Seite mit vielen Keywords und vielen Rankings? Dazu kommen wir beim nächsten Mal, indem wir einen eigenen Sichtbarkeitsindex erstellen.

Kostenloses und automatisiertes SEO-Monitoring mit R und AWS


Langsam hält R Einzug in die Welt der Suchmaschinenoptimierung, und auch wenn R am Anfang etwas verwirrend sein mag (funktionale Programmierung anstatt prozedural), so kann man mit wenigen Zeilen Code coole Sachen bauen. Als Beispiel soll hier ein kostenloses SEO-Monitoring dienen, das natürlich kein bisschen mit Sistrix und Co mithalten kann, aber wenn man nur seine eigenen Rankings verfolgen will, dann ist dies eine tolle und vor allem kostenlose Lösung.

Fangen wir mit der Infrastruktur an, wir benötigen nur drei Komponenten:

  • Eine (kostenlose) EC2-Instanz
  • Einen Google Webmaster-Account
  • Einen Google API-Service Account

Amazon bietet EC2-Instanzen im “free tier” (kostenlosen Kontingent) an, nach 12 Monaten wird hier zwar eine Gebühr fällig, aber die ist eher im homöopathischen Bereich. Die t2.micro-Instanz ist relativ schwach auf der Brust mit ihrer einen vCPU, 1GB RAM und 30GB SSD, aber für unsere Zwecke reicht sie vollkommen aus. R ist natürlich nicht von vornherein vorhanden, ABER Luis Aslett bietet kostenlose AMIs (Amazon Machine Images) an, wo RStudio Server bereits vorkonfiguriert ist. Matt erklärt sehr gut, wie man mit diesen AMIs seine eigene RStudio-Instanz auf AWS installiert. Das alles dauert maximal 15 Minuten, schon hat man seinen eigenen kostenlosen RStudio Server-Rechner in der AWS-Cloud. Große Berechnungen sind damit nicht möglich, aber ist man erst einmal auf den Geschmack gekommen, so findet man sich schnell in der Situation wieder, dass mal kurz eine Instanz mit viel Speicher für größere Rechenaufgaben genutzt wird. Ein Klick, ein paar Euro am Tag, und schon hat man ein ganzes Cluster mit 16 Prozessoren und 128 GB RAM für sich. Aber ich schweife ab.

Im nächsten Schritt nehmen wir das R Package searchConsoleR von Mark Edmonson. Dies ist der elementare Grundstein unseres SEO-Monitoring. In Marks Beispiel schreibt er die Daten einfach auf Platte, aber wir wollen die Daten lieber in eine Datenbank schreiben (wie man MySQL auf unserer frisch erworbenen EC2-Instanz installiert steht hier. Bitte beachten, dass man nur einen Nutzer “ubuntu” hat, d.h. man muss alles mit sudo erledigen; ansonsten kann man kostenpflichtig auch eine RDS-Instanz buchen). Um von einem Server auf die Webmaster Console-Daten zugreifen zu können, wird ein Service Account benötigt. Dieser ist nicht ganz so einfach aufzusetzen, aber das würde den Rahmen dieses Artikels sprengen. Wichtig ist, dass die Mail-Adresse des Service Accounts als ganzer Nutzer in der Webmaster Console eingetragen wird. Und hier ist nun der Code:

library(jsonlite) library(googleAuthR) library(searchConsoleR) library(RMySQL) options(googleAuthR.scopes.selected=“https://www.googleapis.com/auth/webmasters“)` gar_auth_service( json_file = “/home/rstudio/XXXXXXX.json”, scope = “https://www.googleapis.com/auth/webmasters” )

Wir holen uns die Daten von vor 5 Tagen, dann sind sie auf jeden Fall in der Webmaster Console vorhanden:

delay <- 5 start <- Sys.Date() – delay end <- Sys.Date() – delay

Hier nun die Abfrage:

website <;- “XXXXX” download_dimensions <- c(‘query’,‘page’) type <- c(‘web’) sc_data <- search_analytics(siteURL = website, startDate = start, endDate = end, dimensions = download_dimensions, searchType = type)

Wir fügen noch ein Datum und die Webseite hinzu (falls wir mehrere Webseiten abfragen)

sc_data7 <- website sc_data8 <- start colnames(sc_data)7 <- “website” colnames(sc_data)8 <- “date”

Jetzt schreiben wir den Dataframe in die Datenbank (die DB und die Tabelle haben wir vorher bereits hinzugefügt):

mydb = dbConnect(MySQL(), user=‘XXXXX’, password=‘XXXXX’, host=‘XXXXX’) dbSendQuery(mydb, “USE XXXXX”) dbWriteTable(mydb, value = sc_data, name = “rankings”, append = TRUE, row.names = FALSE) dbDisconnect(mydb)

Nun fehlt uns nur noch ein Cronjob, der täglich diese Abfrage durchführt. Dazu nutze ich zunächst ein kleines Shell-Skript, das dann das R-Skript aufruft:

cd /home/rstudio/SearchConsole/ Rscript /home/rstudio/SearchConsole/rankings.R

Dann wird mit sudo crontab -e der Cronjob eingerichtet, mein Cronjob startet jeden Tag um 10:30, bzw 11:30, denn die Instanz ist in einer anderen Zeitzone:

30 10 * * * /home/rstudio/SearchConsole/rankings.sh 2>&1 | /usr/bin/logger -t rstudio

Wichtig: Newline nach der letzten Zeile, sonst meckert cron. Fertig ist das automatische und kostenlose SEO-Monitoring! In einem der nächsten Postings zeige ich, wie man die Daten dann auswerten kann.

mv: argument list too long – Millionen von Dateien verarbeiten


Aufgrund meiner Vergesslichkeit hatte ein cron job mehr als 3 Millionen Dateien in einem Verzeichnis angesammelt, die ich nun verarbeiten wollte. Damit mein Skript nicht tagelang daran arbeitet (mehr 60 GB an Daten!), sollten die Dateien in kleinere Häppchen verteilt werden. Leider kam mv nicht damit klar, es beschwerte sich mit “argument list too long”. Die Abhilfe schafft eine Kombination von Kommandozeilen-Befehlen:

find ordner1/ -name ‘2017-07*’ -exec mv {} ordner2 ;

Wird mein Content gelesen? Scroll-Tiefe pro Artikel als Conversion


Im September 2017 hatte ich noch darüber geschrieben, dass die Scrolltiefe ein besserer Indikator dafür wäre, ob ein Inhalt gelesen wurde als die reine Sitzungsdauer, die eh Quatsch ist. Einen Monat später veröffentlichte Google dann eine neue Funktion im Google Tag Manager, einen Trigger für die Sichtbarkeit von Elementen (in der deutschen Version der Release Notes fehlte der Hinweis). Damit lassen sich einige Nachteile des Scrolltiefen-Ansatzes kompensieren, vor allem die Einschränkung, dass nicht jede Seite gleich lang ist und “75% gelesen” nicht immer bedeuten muss, dass der Inhalt auch bis zum Ende gelesen wurde (75% wurde deswegen gewählt, weil viele Seiten einen immensen Footer haben und die Nutzer daher nicht zu 100% runterscrollen). Eine Seite bei mir hat so viele Kommentare, dass sie mehr als die Hälfte des Inhalts ausmachen. „Wird mein Content gelesen? Scroll-Tiefe pro Artikel als Conversion“ weiterlesen

Woher kommen die SimilarWeb-Daten?


[Dies ist die Neuauflage eines älteren Artikels]

Wie bei Google Trends bin ich immer wieder überrascht, wie schnell Rückschlüsse aus Daten gezogen werden, ohne dass einmal überlegt wird, woher die Daten eigentlich kommen und wie plausibel sie sind. Vor allem bei Similar Web ist das erstaunlich, denn Google hat ja die Suchdaten und kann Trends daraus ablesen, aber woher kann eigentlich Similar Web Daten darüber haben, wie viele Besucher eine Webseite oder eine App hat? Wie zuverlässig sind diese Daten? Ist die Zuverlässigkeit ausreichend, um daraus wichtige Business-Entscheidungen zu treffen?

Der Vorfahr von SimilarWeb

2006 hatte mein früherer Kollege Matt Cutts einmal untersucht, wie zuverlässig die Daten von Alexa sind (Alexa war früher mal ein Amazon-Service, der nichts mit Spracherkennung zu tun hatte). Dieser Dienst sammelte Daten mit einer Browser-Toolbar (sowas gibts heute auch nicht mehr), d.h. es wurde jede Seite protokolliert, die ein Nutzer sich ansah. Da die Alexa-Daten vor allem für Webmaster interessant war, hatten vor allem diese die Toolbar installiert, und so wurden also vor allem Seiten protokolliert, die für Webmaster interessant waren. Sie waren verzerrt.

Wenn man den Traffic von Nutzern mitschneidet, dann muss man auch irgendwie zusehen, dass die Nutzerschaft irgendwie der Netzpopulation entspricht, über die man etwas herausfinden will. Das heißt nicht, dass die Similar Web-Daten komplett wertlos wären. Wenn man zwei Modeseiten miteinander vergleicht, dann sind diese eventuell gleich “uninteressant” für die Webmaster-Population (ein Vorurteil, ich weiß), und dann könnte man zumindest diese miteinander vergleichen. Aber man könnte nicht eine Modeseite mit einer Webmaster-Tool-Seite vergleichen. Aber selbst das sind nur Vermutungen, genau weiß man es nicht. Für ein so teures Tool eigentlich unglaublich.

Woher aber bekommt nun Similar Web die Daten? Auf ihrer Webseite geben sie 4 Quellen an:

  • Ein internationales Panel
  • Crawling
  • ISP-Daten
  • Direktmessungen

Datensammlung über ein Panel

Das Panel wird nicht genauer erklärt, aber wenn man nur minimal recherchiert, so findet man schnell Browser-Extensions. Diese sind wohl die Nachfolger der früheren Browser-Toolbars. Welchen Vorteil bietet die Similar Web-Extension? Sie bietet genau das, was Similar Web auch bietet: Man kann mit einem Klick sehen, wie viele Benutzer die gegenwärtig angeschaute Seite hat, woher sie kommen, und so weiter. Dabei funkt die Similar Web-Extension nicht nur nach Hause, wenn man sich gerade die Daten für eine Seite anzeigen lässt, sondern bei jeder Seite, die man sich anschaut.

Wenn man dann einmal überlegt, für wen solche Daten interessant sind und wer sich dann eine solche Extension installiert, dann sind wir bei der Datenqualität von den Alexa Top Sites angekommen. Webmaster, Marketingmenschen, Suchmaschinenoptimierer, all diese Menschen haben eine höhere Wahrscheinlichkeit diese Extension zu installieren als zum Beispiel ein Teenie oder meine Mutter.

Crawling

Was genau Similar Web crawlt ist mir immer noch ein Rätsel, insbesondere wieso ein Crawling Aufschluss darüber geben kann, wie viel Traffic eine Seite hat. Genau genommen verursacht man ja nur Traffic mit einem Crawler Similar Web sagt dazu, “[we] scan every public website to create a highly accurate map of the digital world”. Vermutlich werden hier Links ausgelesen, vielleicht auch Themen automatisiert erkannt.

ISP-Traffic

Leider sagt Similar Web nicht, von welchen ISPs sie Traffic-Daten bekommen. In Deutschland ist es wahrscheinlich verboten, aber in irgendwelchen Ländern wird es sicherlich erlaubt sein, dass ein Internet Service Provider die Kollegen von Similar Web alles aufzeichnen lässt, was an Traffic durch ihre Kabel läuft. Das wäre natürlich eine sehr gute Datenbasis. Nur ist nicht jeder ISP gleich. Würden wir den Daten vertrauen, wenn zum Beispiel AOL noch existierte und nur deren Nutzer gemessen würden? Schlimmer noch, an keiner Stelle macht SimilarWeb transparent, wo ISP-Daten einfließen.

Direktmessungen

Hier wird es spannend, denn Firmen können ihre Web Analyse-Daten, in diesem Fall Google Analytics, direkt mit Similar Web verbinden, so dass die von Google Analytics gemessenen Daten für alle Similar Web-Nutzer zur Verfügung stehen. Dann steht bei der Site “verified”. Warum sollte man das tun? Man bekommt dafür nichts geschenkt, stattdessen könne man dadurch mit mehr Werbeeinnahmen rechnen oder seine Marke stärken. Ziemlich schwache Argumente, finde ich, dennoch finden sich einige Seiten, die das dennoch tun.

Wie zuverlässig sind die Similar Web-Daten wirklich?

Natürlich sind die Direktmessungen zuverlässig. Schwierig wird es bei allen anderen Datenquellen. Diese machen die Mehrzahl der Messungen aus. Nur ein Bruchteil der Similar Web-Daten basiert nach meinem Sample aus Direktmessungsdaten. Aber hier könnte man sicherlich auf Basis der genau gemessenen Daten und der ungenau gemessenen Daten Modelle erstellen. Wenn ich weiß, wie die Daten von spiegel.de genau sind und wie die ungenau gemessenen Daten aussehen, dann könnte ich zum Beispiel den Panel-Bias berechnen und für andere Seiten ausgleichen. Und das könnte ich auch mit allen anderen Daten tun. Aber funktioniert das wirklich? Schauen wir uns mal eine Messung von Similar Web an, für eine meiner Seiten:

Anscheinend schwankt die Anzahl der Besucher zwischen so gut wie nix und 6.000 Nutzern. Es gibt keine eindeutigen Muster. Und nun schauen wir uns die echten Zahlen von Google Analytics an:

Es ist derselbe Zeitraum. Und dennoch sind die eindeutigen Traffic-Muster aus den Google Analytics-Daten nicht in den Similar Web-Daten zu erkennen. Die Daten sind einfach falsch.

Fazit

Kann man Similar Web dann überhaupt nutzen? Ich rate komplett davon ab, sofern die erhobenen Daten nicht aus einer Direktmessung stammen. Natürlich kann nun die Frage kommen, was man denn sonst verwenden soll. Die Gegenfrage ist, was man mit Daten anfangen kann, von denen man nicht sicher sein kann, ob sie überhaupt irgendwie stimmen. In der Statistik legt man sich sowieso schon selten fest, aber wenn nicht mal die Erhebung der Daten transparent ist, dann muss man die Finger davon lassen. Wenn ich eine Geschäftsentscheidung treffen muss, die eventuell viel Geld kostet, dann würde ich mich nicht auf diese Daten verlassen. Und “für einen ersten Blick…?” Wir wissen auch, dass aus einem “ersten Blick” schnell ein “Fakt” werden kann, weil es so gut in die eigene Argumentation passt. Womit wir wieder bei dem Bestätigungsfehler wären.

Kommentare (seit Februar 2020 ist die Kommentarfunktion von meinem Blog entfernt):

Konrad says

  1. August 2017 at 14:56 Zum Thema Crawling: Vielleicht crawlen die nicht geschützte AW Stats Installationen und andere Counter Dienste und nutzen dann die Daten um die Algos zur Hochrechnung zu trainieren? Ist natürlich alles sehr unpräzise. Die nutzen meines Wissens nicht nur die SimilarWeb Toolbar sondern kaufen auch Daten aus fremden Browser Addons ein. Adblocker könnten schon eine viel bessere Datenbasis liefern…

Tom Alby says

  1. August 2017 at 11:52 Das ist nirgendwo dokumentiert, und wenn sie das täten, dann würden sie sicherlich darüber schreiben, denn das würde ja mehr Vertrauen schaffen. Allerdings sind die AdBlocker-Nutzer auch kein verkleinerter Ausschnitt der Gesamtbevölkerung, d.h. ich könnte daraus nicht auf die Gesamtpopulation schließen.

Und welche Seiten haben noch AW-Stats und andere Counter Dienste?

Daniel Brückner says

  1. August 2017 at 09:14 Hi Tom,

bzgl. des Crawlings: „data“ bedeutet ja nicht unbedingt, dass es sich um Trafficdaten handelt.

bzgl. des Panels: Es könnte auch sein, dass sie Trafficdaten von anderen Browserextensions aufkaufen. Darauf aufbauend kann man schon eine Schätzung abgeben.

Aber insgesamt hast Du Recht, dass man die Zahlen mit Vorsicht genießen sollte.

Lg, Daniel

Tom Alby says 11. August 2017 at 17:22 Hallo Daniel,

bzgl. Panel: das ist so nicht richtig, denn bei welchen anderen Browser Extensions kannst Du sicher sein, dass sie von einem Ausschnitt der Bevölkerung installiert wird, der der GesamtSurfPopulation entspricht? Bei Extensions würde ich immer davon ausgehen, dass allein die Bereitschaft zur Extension-Installation Dich aus der breiten Masse heraushebt. bzgl. Crawling: Steht ja auch da.

BG

Tom

Jan says

  1. Oktober 2017 at 05:28 Busted Ich kann sehen, die Extention ist wertlos. Gibts denn sowas, dass funktioniert?

Tom Alby says

  1. Oktober 2017 at 19:05 Nein. Sorry.

Tom says

  1. Juli 2019 at 13:34 Toller Artikel, der mir aus der Seele spricht! Ich bin bei den Daten (außer den verifizierten Direktmessungen) auch extrem skeptisch. SimilarWebs offizielle Wischiwaschi-Formulierung zu dem Thema verstärkt meine Skepsis nur noch mehr.

Ehrlich gesagt frage ich mich, wie die es überhaupt geschafft haben, Investoren für sich zu gewinnen…

Clustering mit Google Analytics und R


Manche Fragen lassen sich nicht so einfach oder auch gar nicht mit der Benutzeroberfläche von Google Analytics beantworten (das gilt übrigens auch für Adobe Analytics, Piwik, etc). Zwar bietet Google Analytics eine mächtige und einfach zu nutzende Funktionalität an, um Segmente oder Personas basierend auf Geräte, Akquisitionskanäle oder Browser manuell zu bilden und miteinander zu vergleichen, aber sobald es über diese Standardsegmente hinaus oder zu Kombinationen mehrerer Dimensionen geht, wird der Aufwand komplex. Oft genug wird dann auch einfach nur in den Daten “gestochert” und gehofft, dass man etwas Wertvolles findet. Genau hier kommen die Vorteile der Kombination von Google Analytics und R ins Spiel. Eine Möglichkeit, Google Analytics und R miteinander zu verbinden ist das R Package googleAnalyticsR von Mark Edmonson, das in diesem Artikel beispielhaft verwendet wird.

Segmentierung, Clustering und Klassifizierung

Bevor wir ins Praktische gehen, soll noch einmal kurz der Unterschied zwischen Segmentierung, Clustering und Klassifizierung erläutert werden. Bei einer Segmentierung wird versucht, Kunden oder Nutzer in Gruppen zu unterteilen, die sich anhand von Merkmalen unterscheiden, sei es ein Interesse, ein Zugangskanal, eine Marketingkampagne, über die ein Kunde kam, usw. Bei Clustering wird versucht, solche Gruppen und die sie jeweils unterscheidenden Dimensionen oder Features automatisiert zu identifizieren, wohingegen bei der Klassifizierung versucht wird vorherzusagen, zu welcher Gruppe ein Kunde oder Nutzer gehört. Klassifizierung ist ein gutes Beispiel für supervised Machine Learning, Clustering ein gutes Beispiel für unsupervised Machine Learning. Nicht immer kommt etwas Sinnvolles heraus, daher der häufige Gebrauch des Wortes “versucht”

In diesem Beispiel geht es um Clustering, also das Identifizieren von Gruppen auf Basis von Strukturen in den Daten mit Machine Learning-Algorithmen. Im Hierarchical Clustering werden Gruppen anhand ihrer Ähnlichkeit identifiziert, beginnend mit einem eigenen Cluster für jeden Datenpunkt und auf jeder weiteren Ebene mehr Cluster anhand der jeweiligen Ähnlichkeit zusammenzufassend, bis alle Cluster zusammengeführt sind (siehe das Dendrogram). Ein toller Algorithmus, der idealerweise numerische Daten als Input benötigt, denn Ähnlichkeit wird hier als Distanz berechnet. Zwar könnte man mit DAISY auch nicht-numerische Daten verwenden, aber für den ersten Schritt führt das zu weit.

Für unser Beispiel verwenden wir einen anderen Ansatz, wir wollen einfach nur herausfinden, ob Cluster auf Basis der angesehenen Inhalte oder Produkte einer Seite gebildet werden können. So vermute ich, dass die Besucher dieser Website, die sich Roller Derby-Fotos ansehen, sehr wahrscheinlich nicht an den Artikeln über Fintechs interessiert sind. Aber vielleicht interessieren sich die Google Analytics-Artikel-Leser für Fintechs, so dass ihnen Artikel zu diesem Thema angeboten werden könnten. Wir kennen das von Amazon (“Wird oft zusammen gekauft”), und meistens sind die Vorschläge nützlich. Natürlich kann ich mir auch den Nutzerfluss-Bericht in Google Analytics ansehen (bei den wenigen Seiten auf meiner Homepage reicht das auch völlig aus), aber sobald mehr Seiten oder Produkte vorhanden sind, kommen wir mit diesem Bericht nicht weiter. Hier helfen uns Association Rules weiter, auch als Market Basket Analysis bekannt (mit einem der Schöpfer, Tomas Imielinski, habe ich bei Ask.com sogar mal zusammengearbeitet). Dieser Machine Learning-basierte Ansatz versucht interessante Beziehungen zwischen Variablen in großen Datenbeständen zu identifizieren.

Generell hängt die Auswahl eines Algorithmus auch und vor allem zunächst einmal von dem Business-Problem ab, das gelöst werden soll. Dies ist ein extrem wichtiger Punkt: Welche Frage wollen wir eigentlich beantworten? In diesem Fall kann ich nur die Frage beantworten, welche Seiten in einem “Warenkorb” gelandet sind auf Basis der Nutzung durch Webseitenbesucher. Natürlich könnte ich eine “Ähnlichkeit” auch auf Basis des Inhalts maschinell berechnen.

Augen auf bei der Interpretation der Ergebnisse

Zunächst aber erst einmal eine fette Warnung: Das, was sich die Nutzer ansehen, hängt zu einem großen Maße auch davon ab, wie die Navigation oder weitere Elemente auf der Seite ausssehen. Wenn auf der Seite zum Beispiel schon ein Empfehlungssystem wie YARPP eingebunden ist, dann ist allein aufgrund dieses Plugins die Wahrscheinlichkeit höher, dass manche Seiten eher zusammen mit anderen Seiten aufgerufen werden. Aber auch Kleinigkeiten auf einer Seite können dazu führen, dass Zusammenhänge gesehen werden, die eigentlich gar nicht da sind, und sei es nur ein kleines Icon, dass die Aufmerksamkeit der Nutzer auf sich zieht und zum Klicken verführt.

Dann sollte auch noch darauf hingewiesen werden, dass das Ansehen von Seiten ein nicht ganz so starkes Signal ist wie das Kaufen eines Produktes. Nur weil jemand eine Seite aufruft, heißt das noch lange nicht, dass die Person auch lange auf dieser Seite geblieben und den Text gelesen hat. Man könnte das einfließen lassen, indem man zum Beispiel die Verweildauer auf der jeweiligen Seite misst und nur die Kombinationen zulässt, wo “genug” Zeit verbracht wurde, aber die Verweildauer in den Web Analyse-Systemen ist leider häufig unbrauchbar.

Voraussetzungen

Für das Clustering mit Google Analytics und R werden Analytics-Daten auf User-Level benötigt, das heißt, dass die Nutzer einer Standard-Installation der kostenlosen Variante von Google Analytics nicht ohne Weiteres ein Clustering durchführen können. Die Standard-Variante verfügt zwar über den neuen Nutzer-Explorer, über den man sich das Verhalten einzelner anonymisierter Nutzer anschauen kann, aber diese Daten sind nicht herunterladbar. Lediglich die Käufer der Pro-Variante können a priori auf User-Level Daten zugreifen, in der kostenlosen Variante sind nur aggregierte Daten im Angebot. Allerdings gibt es einen kleinen Hack, mit dem man das ändern kann, ansonsten ist hier ein weiteres Argument für Piwik zumindest als Zweitsystem. Der Vorteil von Piwik ist neben Zugriff auf die Rohdaten unter anderem auch, dass die Daten sofort zur Verfügung stehen. Und auch für Piwik existiert ein R Package. Aber in diesem Artikel soll die Lösung mit Google Analytics und R gezeigt werden.

Google Analytics und R mit googleAnalyticsR verbinden

Nun gehts ans Eingemachte. Ich werde nicht erklären, wie man ein R Package installiert, für das, was wir vorhaben, wird zum einen das Package googleAnalyticsR und das Package googleAuthR benötigt, zum andern das Package arules. Die R-Hilfe ist Dein Freund.

Wir laden zunächst einmal die beiden Packages und melden uns dann mit einem Google-Konto an (dafür geht ein Browser-Fenster auf):

library("googleAuthR")<l ibrary("googleAnalyticsR")<g a_auth()

Ist man übrigens bereits angemeldet und möchte auf ein anderes Konto wechseln, so gibt man

ga_auth(new_user = TRUE)

ein und meldet sich mit dem anderen Konto an. Als nächstes holen wir uns die Liste unserer Accounts und Properties, die mit diesem Google Account verbunden sind:

my_accounts <- ga_account_list()

In diesem Datenframe suchen wir in der Spalte viewName nach der Datenansicht, die wir verwenden wollen, und suchen in der Zeile nach der viewId. Diese viewId ist elementar, da wir mit ihr die Daten unserer Datenansicht abrufen werden. Wir speichern die viewID in einer Variable:

ga_id=XXXXXX

wobei XXXXXX für die viewId steht. Welche Daten stehen uns nun zur Verfügung? Einfach

meta <- google_analytics_meta()

eingeben und alle Dimensionen und Metriken sind im Data Frame meta abrufbar. Uns interessiert vor allem die Custom Dimension 1, in der die User Level ID gespeichert ist, und ga:pagePath:

gadata <- google_analytics(id = ga_id,<br /> start="2017-04-20", end="2017-05-06",<br /> dimensions = c("ga:dimension1", "ga:pagePath"),<br /> max = 2000)

In meinem Dataframe gadata habe ich nun die Daten wie oben beschrieben plus zwei weitere Spalten (sessions und bounceRate), da mir GA die Dimensionen nicht ohne Metriken ausgibt. Die Daten müssen transformiert werden, so dass sie ungefähr so aussehen:

<br /> user id 1, page 1, page 2<br /> user id 2, page 1<br /> user id 3, page 3

Dies geschieht mit dem Code

i <- split(gadata$pagePath,gadata$dimension1)

Wir haben jetzt jede “Transaktion” eines Nutzers in einer Zeile. Dies ist der benötigte Input für unseren Algorithmus.

Market Basket Analysis

Jetzt ist der Zeitpunkt, das R Package arules zu laden und die Daten für den Algorithmus zu modifizieren:

library(arules)<br /> txn <- as(i, "transactions")

Beim Aufruf des Algorithmus werden die Parameter sup für Support und conf für Confidence genutzt, d.h. wir sagen ihm im folgenden Beispiel, dass wir Regeln haben wollen, die mindestens in 0,1% der Fälle anwendbar sind und bei denen eine Konfidenz von 0,1% besteht. Das klingt erst einmal verdammt wenig, aber stellen wir uns vor, dass wir es mit einem “Warenkorb” zu tun haben, in den ganz viele verschiedene Kombinationen “gelegt” werden können, je nach Größe eines Online-Shops oder einer Webseite. Natürlich wollen wir mit den Regeln so viele Vorgänge wie möglich abdecken, aber je mehr Möglichkeiten vorhanden sind, desto wahrscheinlicher ist es, dass wir mit einem niedrigen Support-Wert hineingehen müssen.

basket_rules <- apriori(txn, parameter = list(sup = 0.001, conf = 0.001, target="rules"))

Hier kann ganz schön viel Prozessorzeit und Arbeitsspeicher draufgehen, und je nach Ausstattung beendet R den Prozess mit einer Fehlermeldung. Eine Möglichkeit, den Algorithmus zu begrenzen, ist, die Parameter sup und/oder conf zu vergrößern. Ist alles gut gegangen, so können die identifizierten Regeln begutachtet werden:

inspect(head(sort(basket_rules, by="lift"),20))

Hiermit werden die Top 20 Regeln angezeigt, sortiert nacht Lift. Der Lift sagt uns, wie viel höher die Abhängigkeit der Items ist im Vergleich zu ihrer Unabhängigkeit, von der man bei einem Lift von 1 ausgehen muss. Der Output bei mir sieht wie folgt aus (nicht für diese Webseite):

Regel zwei sagt zum Beispiel aus, dass ein kleiner Teil der Transaktionen beinhaltet, dass ein Nutzer sich einen Artikel über Kommunikationsmethoden anschaut und mit einer Konfidenz von 30% auch den Artikel über Kommunikationstechnologie lesen wird. Diese Verbindung hat einen extrem hohen Lift von 521, so dass wir davon ausgehen können, dass diese Verbindung viel wahrscheinlicher ist als ihr zufällig gemeinsames Auftreten.

Zusammenfassung Google Analytics und R

Dieses kleine Beispiel zeigt die Mächtigkeit von R und den Packages. Mit wenigen Zeilen Code können Daten ohne Umwege aus Google Analytics in R importiert und für komplexe Analysen verwendet werden. Diese Analyse wäre in der Benutzeroberfläche nicht möglich gewesen.

Wir sehen hier aber auch, wie wichtig es ist, Daten auf User-Level zu haben, wobei einschränkend gesagt werden muss, dass wir es hier nicht einmal mit User-Level-Daten zu haben, sondern mangels Cross-Device-Tracking eher mit Browser-Level-Daten. Eine nächster Schritt könnte also sein, dass die identifizierten Regeln noch mal auf Basis von segmentierten Daten erstellt werden, um Unterschiede zu identifizieren.

Laufen mit Künstlicher Intelligenz: LifeBEAM Vi


Mitte letzten Jahres hatte ich die Kickstarter-Kampagne von LifeBEAM unterstützt, diese Woche kam der LifeBEAM Vi an: “The first true artificial intelligence Personal Trainer”, der angeblich erste echte Personal Trainer, der auf Künstlicher Intelligenz basiert. LifeBEAM hat bisher vor allem Helme für Kampfpiloten hergestellt, die mit speziellen Sensoren die Vitalparameter messen können; etwas Erfahrung mit Sensoren ist der Firma also schon einmal zuzutrauen. Und das Messen des Pulses über das Ohr funktioniert definitiv besser als mit einer Uhr am Handgelenk, der Fitbit Blaze hat mich hier schon oft enttäuscht. KI ist “the next big thing”, warum also nicht wie in Her einen Assistenten haben, der meine Fitness verbessert?

Von “Her” sind wir zwar noch weit entfernt, eine “Her” aber für nur ein Gebiet (domain-specific), in diesem Fall Sport beziehungsweise noch eingeschränkter Laufen, ist realistisch. Her-like ist zudem, dass LifeBEAM das Interface mit Stimme sehr minimalistisch gehalten hat, damit die eigene Phantasie damit spielen kann, wie Vi für einen selbst aussieht (“your imagination can play with what Vi looks like for YOU“).

Tolle Verpackung, nicht so tolles Handbuch

$219 hat der Spaß inklusive Versand gekostet, dazu kamen dann noch mal knapp 50€ Zoll, was ich zwar für eine Frechheit halte, aber anscheinend auch nicht diskutierbar ist. Ich war auch einfach zu gespannt. Auf ein Unboxing-Video verzichte ich, davon existieren genug im Netz. Die Verpackung ist toll, es fühlt sich alles sehr wertig an, nur bei der Dokumentation wurde gespart. Zwar gibt es ein kleines Handbüchlein, aber da steht zum Beispiel nicht drin, welche Sprachbefehle existieren, auch andere Fragen kann man sich nur durch das Durchwühlen der Foren-Beiträge erfahren. Die Support-Seite hingegen ist eher dürftig.

Einrichten des LifeBEAM Vi

Toll ist, dass der LifeBEAM Vi nicht mit leerer Batterie geliefert wird, man kann also gleich loslegen. Schade dagegen ist, dass man nirgendwo sehen kann, wie voll die Batterie ist. Auch das angeblich mögliche Laden innerhalb von 45 Minuten funktioniert nicht.

Der/die/das Vi kann kein Deutsch sprechen und versteht auch kein Deutsch, die dazu gehörende App existiert auch nur auf Englisch. Aber wenigstens kann man die Einheiten auf das metrische System umstellen, so dass man während des Laufens keine Meilen umrechnen muss.

Suboptimal bei der Einrichtung ist, dass man die Kopfhörer drin hat, um “sie” zu hören, dann aber auf ein blaues Licht achten soll, das man ja nur sehen kann, wenn man die Kopfhörer eben nicht drin hat. Der Klang ist übrigens super. Zumindest wenn man nicht läuft.

Der erste Lauf

Zunächst einmal: Man spürt diesen Bügel überhaupt nicht. Er ist eh superleicht. Dadurch, dass man verschiedene Pinöpsel für unterschiedliche Ohrgrößen mitgeliefert bekommt und zusätzlich einen kleinen Haken, der den Hörer im Ohr halten soll, hält der In-Ear-Kopfhörer bei mir sehr gut, was eher selten der Fall ist. Man muss nur sehr genau darauf achten, dass das kleine grüne Licht, der Herzfrequenzmesser, nicht zu sehen ist, denn dann misst er den Puls nicht.

Für den ersten Lauf wollte ich einfach 5 Kilometer laufen, App gestartet, Verbindung wurde sofort gefunden, und los geht’s. Der LifeBEAM Vi redet erst einmal ganz schön viel, dabei läuft eine Spotify-Playlist, wobei ich nicht verstanden habe, welche das ist. Die Running-Funktion von Spotify hat nicht funktioniert. Die Musik wird etwas leiser, wenn Vi spricht, aber war zum Teil noch zu laut, so dass ich Vi nicht immer verstanden habe.

Was ich glaube, was sie gesagt hat, ist, dass sie 2 Stunden Training mit einem verbringen muss, bis sie genug Daten zusammen hat, um Vorschläge unterbreiten zu können. Im Forum beschweren sich einige Nutzer, dass nach 2 Stunden nix passiert ist. In dem Fall lag es aber wohl daran, dass das Coaching anscheinend momentan nur auf dem iPhone funktioniert. Der Sound wirkte beim Laufen übrigens nicht mehr ganz so toll, was aber auch daran liegen kann, dass ich die Stöpsel kurz vorher noch mal ausgewechselt hatte.

Erstes Coaching

Das, was der LifeBEAM Vi sagt, ist auf jeden Fall schon mal persönlicher als das, was mir Runkeeper sagt. Die Stimme ist natürlicher, und es ist weniger vorhersehbar. Schön war auch, dass sie mir nach 2 Kilometern sagte, dass meine Schritte zu groß sind, und einen coolen Beat “auflegte”, mit dem ich eine andere Schrittlänge probieren konnte. Sie lobte mich nach 2/3 des Laufs, dass ich die Geschwindigkeit gut halten könne. Das wirkte schon mal sehr viel individueller als Runkeeper.

Was ich nicht verstanden hatte war, wie ich es hinbekomme, dass sie mir meine Herzfrequenz sagt. Erst habe ich es ganz klassisch mit “Vi, what is my Heart Rate?” probiert, aber sie hatte nicht reagiert. Dann habe ich mal auf den rechten Kopfhörer gedrückt, weil ich meinte, mich dunkel zu erinnern, dass das funktioniert. Tatsächlich muss man dann nur “Heart Rate” sagen, und wenn an der Elbe nicht ganz so viel Wind entgegen pustet, dann versteht sie es auch. Witzig nur, dass sie mir 20 Sekunden später erklärt, wie ich sie nach der Herzfrequenz fragen kann. Dass mein Puls relativ hoch war, dazu hat sie nix gesagt. Auch die Frage nach “Distance” hat sie nicht verstanden; ich hätte manchmal schon gerne gewusst, wie viel ich noch vor mir habe.

You’ll never run alone

Kurz vor dem Ende des Laufs sagte sie mir, dass ich es gleich geschafft hätte. Es kam mir danach noch wie eine Ewigkeit vor, aber das kann auch am Elbberg gelegen haben, der mir jedes Mal in die Quere kommt (daher auch der hohe Puls bei gleichzeitig geringer Geschwindigkeit in dem Screenshot).

Als es dann vorbei war, war es schön, jemanden zu haben, der einem Feedback gibt, wenngleich es auch nur eine Zusammenfassung war. Insgesamt war es eine gute Erfahrung, jemanden zu haben, der zu einem spricht, denn manchmal ist mir schon langweilig beim Laufen. Manche denken beim Laufen über Probleme nach, ich dagegen versuche den Kopf frei zu bekommen. Dabei hat der LifeBEAM Vi gut geholfen.

Nächste Schritte

Mir fehlen also noch anderthalb Stunden, bis der LifeBEAM Vi coachen kann; darüber werde ich dann berichten. Bis dahin kann ich auch berichten, welche anderen Sprachbefehle der Vi funktionieren und wie schnell die Batterie tatsächlich hält und lädt. Insgesamt ist der Eindruck erst einmal positiv, auch wenn die hohen Erwartungen, die die initialen Videos weckten, nicht komplett erfüllt wurden.

Update: Das Video, das ich hier eingebunden hatte, wurde von LifeBeam auf privat gestellt. Hintergrund ist wahrscheinlich, dass in dem Video ein Mann auf einem Laufband gezeigt wurde. Aber damit kann Vi gar nicht umgehen