Ich hatte mich in Folge 15 mit Vorher-Nachher-Vergleichen beschäftigt. Bei diesem Verfahren vergleichen Sie den Erfolg im Nachher-Zeitraum mit dem Erfolg im Vorher-Zeitraum. Dies kann sinnvoll sein, wenn Sie Grund zu der Annahme haben, dass die beobachtete Veränderung durch eine im Nachher-Zeitraum ergriffene Marketing-Maßnahme verursacht wurde.
Ein Vorher-Nachher-Vergleich wäre für Fragen der folgenden Art unzureichend:
Sie messen die wöchentlichen Visits auf Ihrer Website, die Ihnen Google gebracht hat. Seit einiger Zeit schalten Sie auch Textanzeigen mit Google Ads und wollen wissen, ob sich dies für Sie lohnt. Im Vorher-Zeitraum hatten Sie Visits durch Klicks auf Google-Suchergebnisse, im Nachher-Zeitraum Visits durch Klicks auf Google-Suchergebnisse und Klicks auf Textanzeigen. In diesem Fall könnte das Schalten der Textanzeigen die Anzahl der Visits durch Klicks auf Google-Suchergebnisse reduziert haben.
Ein Ansatz zur Untersuchung derartiger Fragen besteht in einer modifizierten Form des Vorher-Nachher-Vergleichs:
Das von Google verwendete CausalImpact-Package vergleicht den Erfolg im Nachher-Zeitraum mit einem prognostizierten Wert, dem Erfolg im Nachher-Zeitraum, der sich ohne die Marketing-Maßnahme ergeben wäre. Die Differenz zwischen den beiden Größen dient dann als Schätzwert für den Effekt der Marketing-Maßnahme, den Causal Impact.
Ich erläutere das Verfahren anhand von Beispieldaten, indem ich zunächst einen Vorher-Nachher-Vergleich anstelle, dann den Effekt mit der Methode der kleinsten Quadrate schätze und schließlich das CausalImpact-Package verwende und die Ergebnisse vergleiche.
Als Ausgangspunkt dient mein Datensatz eins, den Sie in der folgenden Grafik sehen und am Ende dieses Beitrags in Form einer HTML-Tabelle finden. Der Vorher-Zeitraum umfasst 70 Beobachtungswerte, der Nachher-Zeitraum 30.
Vermutung:
Eine seit Beginn des Nachher-Zeitraums laufende Marketing-Maßnahme hat die höheren Werte im Nachher-Zeitraum verursacht.
library(ggplot2)
svg("emim-31-1.svg", width=5.3, height=3.6, bg="transparent")
ggplot(daten,aes(x=x,y=y)) +
geom_line(colour="#dddddd") +
geom_vline(xintercept=70.5,colour="darkgrey",
size=0.8,linetype="dashed") +
geom_point() +
annotate("text",x=69.5, y=97.2,
label="Vorher-Zeitraum",hjust=1,vjust=0, size=4) +
annotate("text",x=71.5, y=97.2,
label="Nachher-Zeitraum",hjust=0,vjust=0, size=4) +
labs(x="Zeit",
y="Visits",
title="Datensatz eins") +
theme_bw() +
theme(plot.background=
element_rect(colour=NA,fill="transparent"))
dev.off()
Für einen Vorher-Nachher-Vergleich Art berechne ich für jeden der beiden Zeiträume den Mittelwert. Dann subtrahiere ich vom Mittelwert für den Nachher-Zeitraum den Mittelwert für den Vorher-Zeitraum. Als Ergebnis erhalte ich 6,36 (gerundet).
Die folgende Grafik zeigt die beiden Mittelwerte und den sich hieraus ergebenden Schätzwert für den Effekt der Marketing-Maßnahme:
mw1 <- mean(daten[71:100,"y"]) # 106.5426
mw0 <- mean(daten[1:70,"y"]) # 100.1793
mw1-mw0 # Effekt = 6.363274
svg("emim-31-2.svg", width=5.3, height=3.6, bg="transparent")
ggplot(daten,aes(x=x,y=y)) +
geom_line(colour="#dddddd") +
geom_vline(xintercept=70.5,colour="darkgrey",
size=0.8,linetype="dashed") +
geom_point(colour="#bbbbbb") +
geom_segment(aes(x=70.5,xend=100,y=mw1,yend=mw1),
size=1,colour="darkblue",linetype="solid") +
geom_segment(aes(x=1,xend=70.5,y=mw0,yend=mw0),
size=1,colour="darkblue",linetype="solid") +
geom_segment(aes(x=72.5,xend=72.5,y=mw0,yend=mw1),
size=1,colour="#dd0000",
arrow=arrow(ends="last",length=unit(0.3,"cm"))) +
annotate("text",x=69.5, y=97.2,label="Vorher-Zeitraum",hjust=1,vjust=0, size=4) +
annotate("text",x=71.5, y=97.2,label="Nachher-Zeitraum",hjust=0,vjust=0, size=4) +
annotate("text",x=75.5, y=103,label="Effekt = 6,36",
hjust=0,vjust=0, size=4,col="#dd0000",fontface=1) +
labs(x="Zeit",
y="Visits",
title="Vorher-Nachher-Vergleich") +
theme_bw() +
theme(plot.background=
element_rect(colour=NA,fill="transparent"))
dev.off()
Beim Vorher-Nachher-Vergleich wird vorausgesetzt, dass sich bei einem Verzicht auf die Marketing-Maßnahme im Nachher-Zeitraum der gleiche Mittelwert ergeben hätte wie im Vorher-Zeitraum. Dies ist hier allein schon deshalb fragwürdig, weil in den Daten des Vorher-Zeitraums ein leichter Aufwärtstrend erkennbar ist.
Eine naheliegende Verbesserung besteht darin, einen Trend in den Daten des Vorher-Zeitraums bei der Schätzung des Effekts zu berücksichtigen.
Als Datenbasis für meine Zeitreihenprognose verwende ich die 70 Beobachtungswerte des Vorher-Zeitraums aus der Datensatz eins.
Der Ansatz lautet:
Visitst = α + β*t + εt für t = 1, …, 70
reg <- lm(y~x,daten[1:70,]) # y = Visits, x = t (Zeit)
summary(reg)
Als Schätzwerte erhalte ich 99,64 für die Niveaukonstante α und 0,02 für die Steigung β (jeweils gerundet). Beide Koeffizienten sind signifikant (p=0,000 für die Niveaukonstante und p=0,033 für den Einfluss der Variablen x).
Die folgende Grafik zeigt die Daten des Vorher-Zeitraums und die Regressionsgerade, die den Aufwärtstrend in den Daten verdeutlicht:
svg("emim-31-3.svg", width=5.3, height=3.6, bg="transparent")
ggplot(fortify(reg),aes(x=x,y=y)) +
geom_point(colour="#bbbbbb") +
labs(x="Zeit",
y="Visits",
title="Regressionsanalyse für den Vorher-Zeitraum") +
geom_line(aes(y=.fitted)) +
theme_bw() +
theme(plot.background=
element_rect(colour=NA,fill="transparent"))
dev.off()
Ich verwende jetzt die Schätzergebnisse für meine Regressionsgleichung, um die Anzahl der Visits für den Nachher-Zeitraum (t = 71 bis 100) vorherzusagen:
Visitst = 99,64 + 0,02*t für t = 71, …, 100
Ich hatte die Regressionsgleichung ursprünglich für den Vorher-Zeitraum geschätzt (t = 1 bis 70) und verwende sie jetzt für den Nachher-Zeitraum (t = 71 bis 100). Ich unterstelle demnach für den Vorher- und den Nachher-Zeitraum eine einheitliche Regressionsgleichung, die ich jedoch nur anhand meiner Daten für den Vorher-Zeitraum geschätzt habe.
Wie hätte sich die Anzahl der Visits im Nachher-Zeitraum entwickelt, wenn die Marketing-Maßnahme im Nachher-Zeitraum unterblieben wäre?
Zur Beantwortung dieser Frage berechne ich die prognostizierten Werte (t = 71 bis 100) und bilde hiervon den Mittelwert:
prog <- predict(reg,daten[71:100,])
mwp <- mean(prog) # 100.9319
Als Mittelwert der prognostizierten Visits mwp erhalte ich 100,93 (gerundet). Dies ist etwas mehr als der für den Vorher-Zeitraum ermittelte Wert (mw0 = 100,18).
Beim Vorher-Nachher-Vergleich hatte ich den Effekt nach der Formel mw1-mw0 berechnet (durchschnittliche Visits im Nachher-Zeitraum minus durchschnittliche Visits im Vorher-Zeitraum). Ich ersetze jetzt den Wert mw0 durch den Wert mwp und berücksichtige hiermit den für den Vorher-Zeitraum gefundenen Aufwärtstrend.
Der Schätzwert für die Größe des Effekts ist daher gleich mw1-mwp = 5,61 (gerundet).
Ich zeichne dies:
daten2 <- data.frame(x=daten$x,
fittedreg=c(reg$fitted,rep(NA,30)),
prognose=c(rep(NA,70),prog))
svg("emim-31-4.svg", width=5.3, height=3.6, bg="transparent")
ggplot(daten2,aes(x=x,y=y)) +
geom_point(colour="#bbbbbb") +
geom_line(aes(y=fittedreg),size=0.6,colour="darkblue") +
geom_point(aes(y=prognose),size=0.6,colour="red") +
geom_vline(xintercept=70.5,colour="darkgrey",
size=0.8,linetype="dashed") +
geom_segment(aes(x=70.5,xend=100,y=mwp,yend=mwp),
size=1,colour="darkblue",linetype="solid") +
geom_segment(aes(x=70.5,xend=100,y=mw1,yend=mw1),
size=1,colour="darkblue",linetype="solid") +
geom_segment(aes(x=72.5,xend=72.5,y=mwp,yend=mw1),
size=1,colour="#dd0000",
arrow=arrow(ends="last",length=unit(0.3,"cm"))) +
annotate("text",x=69.5, y=97.2,
label="Vorher-Zeitraum",hjust=1,vjust=0, size=4) +
annotate("text",x=71.5, y=97.2,
label="Nachher-Zeitraum",hjust=0,vjust=0, size=4) +
annotate("text",x=75.5, y=103.3,
label="Effekt = 5,61",hjust=0,vjust=0,
size=4,col="#dd0000",fontface=1) +
labs(x="Zeit",
y="Visits",
title="Vergleich mit Zeitreihenprognose") +
theme_bw() +
theme(plot.background=
element_rect(colour=NA,fill="transparent"))
dev.off()
Sie sehen in der unteren Hälfte der Grafik die Regressionsgerade (ansteigende dunkelblaue Linie) und die für den Nachher-Zeitraum prognostizierten Visits (rote Punkte). Die Mittelwerte mw1 und mwp sind durch die waagerechten Linien dargestellt.
Für meinen Vergleich mit dem CausalImpact-Package schätze ich zusätzlich ein Konfidenzintervall für den Effekt. Hierzu schätze ich eine Regressionsgerade von der Art y = α + βx, deren Koeffizient β der Effekt ist.
Grundlage für meine Schätzung sind die Daten für den Nachher-Zeitraum und die für den Nachher-Zeitraum prognostizierten Werte. Außerdem verwende ich eine (0,1)-Variable.
Y <- c(daten2[71:100,"prognose"],daten[71:100,"y"])
D <- c(rep(0,30),rep(1,30))
Der Vektor Y enthält die prognostizierten und die tatsächlichen Visits, jeweils für den Nachher-Zeitraum. Vektor D besteht aus 30 Nullen und 30 Einsen.
Meine Regressionsgleichung lautet:
YT = α + β*DT + εT mit T = 1, …, 60
reg2 <- lm(Y~D)
summary(reg2)
Der Schätzwert für den Koeffizienten der (0,1)-Variablen ist signifikant (p=0,000) und stimmt mit dem Effekt überein (5,6107). Der Schätzwert für die Niveaukonstante ist ebenfalls signifikant (p=0,000) und ist gleich mwp (100,9319).
confint(reg2)
Als 0,95-Konfidenzintervall erhalte ich (5,29926; 5,922049). Der Effekt ist demnach gleich 5,61 ± 0,31 (0,95-Konfidenzintervall, Werte gerundet).
Google ermittelt den Return on Investment von Google-Ads-Kampagnen mit Hilfe von R und dem CausalImpact-Package (http://blog.revolutionanalytics.com/2014/09/google-uses-r-to-calculate-roi-on-advertising-campaigns.html).
Informationen zum CausalImpact-Package finden Sie auf den Seiten https://cran.r-project.org/package=CausalImpact und http://google.github.io/CausalImpact/. Es gibt dort eine Einführung in das CausalImpact-Package und einen Aufsatz über die verwendete Methode (»Inferring Causal Impact Using Bayesian Structural Time-Series Models«).
Die Anwendung von CausalImpact ist einfach. Ich definiere zunächst den Vorher- und den Nachher-Zeitraum:
pre.period <- c(1,70) # Vorher
post.period <- c(71,100) # Nachher
Jetzt kommt die Auswertung:
library(CausalImpact)
impact <- CausalImpact(daten[,"y",drop=FALSE],
pre.period, post.period)
Sie können sich das Ergebnis in Form eines Texts ausgeben lassen:
summary(impact,"report")
Die von CausalImpact berechneten Werte:
impact$summary
Sie sehen unter anderem:
impact$summary$AbsEffect[1] # Effekt = 6.347309
Der Effekt ist die Differenz zwischen dem Mittelwert im Nachher-Zeitraum mw1 und dem für den Nachher-Zeitraum prognostizierten Mittelwert, der sich bei einem Verzicht auf die Kampagne ergeben hätte. Ich bezeichne diesen prognostizierten Mittelwert mit mwp2.
impact$summary$Actual[1] # 106.5426 = mw1
mwp2 <- impact$summary$Pred[1] # Prognose = 100.1953
Effekt = mw1-mwp2 = 6,347309
Das CausalImpact-Package bietet hierzu eine Grafik, die ich mit zusätzlichen Beschriftungen versehen habe:
svg("emim-31-5.svg", width=5.3, height=4.1, bg="transparent")
plot(impact, "original") +
geom_segment(aes(x=1,xend=100,y=mw1,yend=mw1),
size=0.4,linetype="dashed") +
geom_segment(aes(x=78.1,xend=78.1,y=mwp2,yend=mw1),
size=1,colour="#dd0000",
arrow=arrow(ends="last", length=unit(0.3,"cm"))) +
annotate("text",x=80.1, y=103.1,
label="Effekt = 6,35",hjust=0,vjust=0,
size=4,col="#dd0000",fontface=1) +
annotate("text", x=67, y=mw1+0.1,
label="mw[1]", hjust=1, vjust=0,
size=4, parse=TRUE) +
annotate("text", x=80.1, y=mwp2-0.2,
label="mw[p2]", hjust=0, vjust=1,
size=4,parse=TRUE) +
labs(x="Zeit",
y="Visits",
title="CausalImpact:",
subtitle="Effekt = Mittelwert Nachher - Mittelwert Nachher prognostiziert") +
theme(plot.background=
element_rect(colour=NA,fill="transparent")) +
theme(axis.text=element_text(size=8),
axis.title=element_text(size=12),
plot.title=element_text(size=14),
plot.subtitle=element_text(size=12))
dev.off()
Ich hatte im vorherigen Abschnitt die Methode der kleinsten Quadrate für meine Zeitreihenprognose verwendet. Das CausalImpact-Package basiert auf einem anderen Verfahren der Regressionsanalyse und liefert daher andere Ergebnisse.
Ein Vorteil des CausalImpact-Packages liegt in der einfachen Anwendung. Bei der Methode der kleinsten Quadrate (OLS) ist dies anders. Meine Gleichung
Visitst = α + β*t + εt für t = 1, …, 70
ist nur sinnvoll, wenn sich meine Daten hierdurch hinreichend gut beschreiben lassen. Andernfalls müsste ich die Kurvenform ändern oder meine Daten transformieren. Die Methode der kleinsten Quadrate erfordert daher immer, dass ich mein Regressionsmodell vor der Schätzung des Effekts prüfe und bei Bedarf modifiziere.
Ich erstelle eine Tabelle mit den Schätzwerten für die Konfidenzintervalle und den Effekt:
ci_ols <- c(confint(reg2)[2,1],
mw1-mwp,
confint(reg2)[2,2])
ci_CI <- c(impact$summary$AbsEffect.lower[1],
impact$summary$AbsEffect[1],
impact$summary$AbsEffect.upper[1])
daten3 <- data.frame(
x=c("OLS","CausalImpact"),
yu=c(ci_ols[1],ci_CI[1]),
ym=c(ci_ols[2],ci_CI[2]),
yo=c(ci_ols[3],ci_CI[3]),
stringsAsFactors=FALSE)
x | yu | ym | yo |
---|---|---|---|
OLS | 5,29926022 | 5,61065481 | 5,92204939 |
CausalImpact | 5,81640654 | 6,34730861 | 6,90512468 |
Ich erstelle hieraus eine Grafik:
svg("emim-31-6.svg", width=5.3, height=3.6, bg="transparent")
ggplot(daten3,aes(x=x,y=ym)) +
geom_hline(yintercept=mw1-mw0, size=0.4, linetype="dashed") +
geom_errorbar(aes(ymin=yu, ymax=yo),width=0.2) +
geom_point(shape=4,size=5) +
annotate("text", x=1.25, y=mw1-mw0+0.03,
label="Effekt laut Vorher-Nachher-Vergleich", hjust=0, vjust=0, size=4) +
labs(x="Schätzverfahren",
y="Visits (Mittelwerte)",
title="Schätzwerte für den Effekt: 0,95-Konfidenzintervalle") +
theme_bw() +
theme(plot.background=
element_rect(colour=NA,fill="transparent"))
dev.off()
Mit dem CausalImpact-Package ergibt sich für den Effekt ein Schätzwert, der fast so hoch ist wie das Ergebnis eines Vorher-Nachher-Vergleichs. Mit der Methode der kleinsten Quadrate (OLS) erhalte ich einen deutlich geringeren Schätzwert. Die 0,95-Konfidenzintervalle überschneiden sich jedoch.
x | y |
---|---|
1 | 99,5015543 |
2 | 98,9813896 |
3 | 100,741802 |
4 | 99,7982887 |
5 | 98,8711229 |
6 | 101,616058 |
7 | 98,325559 |
8 | 98,3667855 |
9 | 99,2337765 |
10 | 99,4636658 |
11 | 100,324057 |
12 | 97,8719502 |
13 | 99,1075943 |
14 | 98,4932543 |
15 | 99,216314 |
16 | 101,213564 |
17 | 100,774714 |
18 | 100,058527 |
19 | 100,104992 |
20 | 99,8198409 |
21 | 100,109563 |
22 | 100,489431 |
23 | 99,4666881 |
24 | 101,820151 |
25 | 101,093173 |
26 | 99,8306003 |
27 | 99,0590092 |
28 | 99,7600472 |
29 | 100,958284 |
30 | 101,766345 |
31 | 100,323126 |
32 | 99,8555863 |
33 | 100,512612 |
34 | 100,002685 |
35 | 98,4797086 |
36 | 100,683796 |
37 | 101,364484 |
38 | 101,677215 |
39 | 101,117848 |
40 | 101,372664 |
41 | 99,9401036 |
42 | 100,207955 |
43 | 99,7585705 |
44 | 99,4495427 |
45 | 99,9927617 |
46 | 102,95352 |
47 | 99,9741758 |
48 | 100,592913 |
49 | 100,070976 |
50 | 101,04321 |
51 | 100,71251 |
52 | 99,8241224 |
53 | 100,069161 |
54 | 100,443498 |
55 | 102,632423 |
56 | 100,821653 |
57 | 102,488252 |
58 | 98,5524819 |
59 | 99,0693248 |
60 | 96,8541086 |
61 | 98,2336541 |
62 | 99,8574657 |
63 | 101,043623 |
64 | 101,304247 |
65 | 101,656343 |
66 | 100,784154 |
67 | 101,314706 |
68 | 99,3770573 |
69 | 99,1705215 |
70 | 102,731858 |
71 | 107,39714 |
72 | 106,664968 |
73 | 106,7075 |
74 | 105,510513 |
75 | 107,915939 |
76 | 106,798159 |
77 | 105,34848 |
78 | 105,703675 |
79 | 106,208017 |
80 | 106,443917 |
81 | 105,33143 |
82 | 106,278507 |
83 | 107,558315 |
84 | 106,579954 |
85 | 106,558143 |
86 | 106,5903 |
87 | 107,465578 |
88 | 106,229093 |
89 | 106,224054 |
90 | 106,182379 |
91 | 106,308635 |
92 | 106,956843 |
93 | 106,971453 |
94 | 105,75681 |
95 | 104,435021 |
96 | 106,904138 |
97 | 107,002995 |
98 | 107,120277 |
99 | 106,4397 |
100 | 108,686009 |
Das liberale Propaganda-Handbuch, Taschenbuch, 382 Seiten
Einführung in die Statistik-Software R Commander
Business Cases für den Verkauf
Fachliteratur suchen mit Google Scholar, WorldCat etc. pp.
Ghostwriter für Dissertationen, Bachelor- und Masterarbeiten
Wissenschaftliches Ghostwriting
Content-Marketing mit White Papers für Start-up-Unternehmen im B2B-Geschäft
1. White Papers als Werbemittel
2. Fallstudien im Sinne von White Papers
Warum White Papers im B2B-Geschäft häufig wirkungsvoller sind als klassische Werbung
Lead-Management im B2B-Geschäft - warum und wie?
White Papers erstellen - von der Themenwahl bis zum Layout