Beim Umgang mit heteroskedastischen Daten stehen eine Reihe von Optionen zur Verfügung. Leider funktioniert garantiert keiner von ihnen immer. Hier sind einige Optionen, mit denen ich vertraut bin:
- Transformationen
- Welch ANOVA
- gewichtete kleinste Quadrate
- robuste Regression
- Heteroskedastizität konsistente Standardfehler
- Bootstrap
- Kruskal-Wallis-Test
- ordinale logistische Regression
Update: Hier finden Sie eine Demonstration R
einiger Möglichkeiten zur Anpassung eines linearen Modells (z. B. einer ANOVA oder einer Regression) bei Heteroskedastizität / Varianzheterogenität.
Beginnen wir mit einem Blick auf Ihre Daten. Der Einfachheit halber habe ich sie in zwei Datenrahmen geladen my.data
(die wie oben mit einer Spalte pro Gruppe strukturiert sind) und stacked.data
(die zwei Spalten haben: values
mit den Zahlen und ind
mit dem Gruppenindikator).
Wir können die Heteroskedastizität formell mit dem Levene-Test testen:
library(car)
leveneTest(values~ind, stacked.data)
# Levene's Test for Homogeneity of Variance (center = median)
# Df F value Pr(>F)
# group 2 8.1269 0.001153 **
# 38
Sicher genug, Sie haben Heteroskedastizität. Wir werden prüfen, wie unterschiedlich die Gruppen sind. Als Faustregel gilt, dass lineare Modelle für die Heterogenität der Varianz ziemlich robust sind, solange die maximale Varianz nicht mehr als das der minimalen Varianz beträgt.4×
apply(my.data, 2, function(x){ var(x, na.rm=T) })
# A B C
# 0.01734578 0.33182844 0.06673060
var(my.data$B, na.rm=T) / var(my.data$A, na.rm=T)
# [1] 19.13021
Ihre Varianzen unterscheiden sich erheblich, wobei die größten B
die der kleinsten sind . Dies ist ein problematisches Maß an Heteroscedosaticity. 19×A
Sie hatten überlegt, Transformationen wie den Logarithmus oder die Quadratwurzel zu verwenden, um die Varianz zu stabilisieren. In einigen Fällen funktioniert dies, aber Transformationen vom Typ Box-Cox stabilisieren die Varianz, indem sie die Daten asymmetrisch komprimieren. Entweder werden sie nach unten komprimiert, wobei die höchsten Daten am stärksten komprimiert werden, oder sie werden nach oben komprimiert, wobei die niedrigsten Daten am stärksten komprimiert werden. Sie müssen also die Varianz Ihrer Daten ändern, damit dies optimal funktioniert. Ihre Daten weisen einen großen Unterschied in der Varianz auf, aber einen relativ kleinen Unterschied zwischen Mittelwerten und Medianwerten, dh die Verteilungen überlappen sich meistens. Als Unterrichtsübung können wir einige erstellen, parallel.universe.data
indem wir zu allen Werten und zu hinzufügen2.7B
.7C
um zu zeigen, wie es funktionieren würde:
parallel.universe.data = with(my.data, data.frame(A=A, B=B+2.7, C=C+.7))
apply(parallel.universe.data, 2, function(x){ var(x, na.rm=T) })
# A B C
# 0.01734578 0.33182844 0.06673060
apply(log(parallel.universe.data), 2, function(x){ var(x, na.rm=T) })
# A B C
# 0.12750634 0.02631383 0.05240742
apply(sqrt(parallel.universe.data), 2, function(x){ var(x, na.rm=T) })
# A B C
# 0.01120956 0.02325107 0.01461479
var(sqrt(parallel.universe.data$B), na.rm=T) /
var(sqrt(parallel.universe.data$A), na.rm=T)
# [1] 2.074217
Durch die Verwendung der Quadratwurzel-Transformation werden diese Daten recht gut stabilisiert. Sie können die Verbesserung für die parallelen Universumsdaten hier sehen:
Anstatt nur verschiedene Transformationen auszuprobieren, besteht ein systematischerer Ansatz darin, den Box-Cox-Parameter zu optimieren (obwohl es normalerweise empfohlen wird, diesen auf die nächste interpretierbare Transformation zu runden). In Ihrem Fall ist entweder die Quadratwurzel oder das Protokoll zulässig, obwohl beides nicht funktioniert. Für die parallelen Universumsdaten ist die Quadratwurzel am besten: λλ=.5λ=0
boxcox(values~ind, data=stacked.data, na.action=na.omit)
boxcox(values~ind, data=stacked.pu.data, na.action=na.omit)
Da es sich bei diesem Fall um eine ANOVA handelt (dh keine stetigen Variablen), besteht eine Möglichkeit, mit Heterogenität umzugehen, darin, die Welch-Korrektur auf die Nennerfreiheitsgrade im Test anzuwenden (nb , ein Bruchwert statt ): Fdf = 19.445
df = 38
oneway.test(values~ind, data=stacked.data, na.action=na.omit, var.equal=FALSE)
# One-way analysis of means (not assuming equal variances)
#
# data: values and ind
# F = 4.1769, num df = 2.000, denom df = 19.445, p-value = 0.03097
Ein allgemeinerer Ansatz besteht darin, gewichtete kleinste Quadrate zu verwenden . Da sich einige Gruppen ( B
) mehr ausbreiten, liefern die Daten in diesen Gruppen weniger Informationen über den Ort des Mittelwerts als die Daten in anderen Gruppen. Wir können das Modell einbeziehen lassen, indem wir jedem Datenpunkt ein Gewicht zuweisen. Ein übliches System besteht darin, den Kehrwert der Gruppenvarianz als Gewicht zu verwenden:
wl = 1 / apply(my.data, 2, function(x){ var(x, na.rm=T) })
stacked.data$w = with(stacked.data, ifelse(ind=="A", wl[1],
ifelse(ind=="B", wl[2], wl[3])))
w.mod = lm(values~ind, stacked.data, na.action=na.omit, weights=w)
anova(w.mod)
# Response: values
# Df Sum Sq Mean Sq F value Pr(>F)
# ind 2 8.64 4.3201 4.3201 0.02039 *
# Residuals 38 38.00 1.0000
Dies ergibt geringfügig andere und Werte als die ungewichtete ANOVA ( , ), hat jedoch die Heterogenität gut berücksichtigt: Fp4.5089
0.01749
Weighted Least Squares ist jedoch kein Allheilmittel. Eine unangenehme Tatsache ist, dass es nur richtig ist, wenn die Gewichte richtig sind, was unter anderem bedeutet, dass sie von vornherein bekannt sind. Nicht-Normalität (z. B. Versatz) oder Ausreißer werden ebenfalls nicht behandelt. Die Verwendung von aus Ihren Daten geschätzten Gewichten funktioniert jedoch häufig, insbesondere wenn Sie über genügend Daten verfügen, um die Varianz mit angemessener Genauigkeit zu schätzen (dies entspricht der Idee, eine Tabelle anstelle einer Tabelle zu verwenden, wenn Sie oder habenzt50100Freiheitsgrade), Ihre Daten sind ausreichend normal und Sie scheinen keine Ausreißer zu haben. Leider haben Sie relativ wenige Daten (13 oder 15 pro Gruppe), einige Abweichungen und möglicherweise einige Ausreißer. Ich bin mir nicht sicher, ob dies schlimm genug ist, um eine große Sache daraus zu machen, aber Sie könnten gewichtete kleinste Quadrate mit robusten Methoden mischen . Anstatt die Varianz als Maß für die Streuung zu verwenden (die für Ausreißer empfindlich ist, insbesondere bei niedrigem ), können Sie auch den Kehrwert des Interquartilbereichs verwenden (der von bis zu 50% Ausreißern in jeder Gruppe nicht beeinflusst wird). Diese Gewichte könnten dann mit einer robusten Regression unter Verwendung einer anderen Verlustfunktion wie Tukeys Bisquadrat kombiniert werden: N
1 / apply(my.data, 2, function(x){ var(x, na.rm=T) })
# A B C
# 57.650907 3.013606 14.985628
1 / apply(my.data, 2, function(x){ IQR(x, na.rm=T) })
# A B C
# 9.661836 1.291990 4.878049
rw = 1 / apply(my.data, 2, function(x){ IQR(x, na.rm=T) })
stacked.data$rw = with(stacked.data, ifelse(ind=="A", rw[1],
ifelse(ind=="B", rw[2], rw[3])))
library(robustbase)
w.r.mod = lmrob(values~ind, stacked.data, na.action=na.omit, weights=rw)
anova(w.r.mod, lmrob(values~1,stacked.data,na.action=na.omit,weights=rw), test="Wald")
# Robust Wald Test Table
#
# Model 1: values ~ ind
# Model 2: values ~ 1
# Largest model fitted by lmrob(), i.e. SM
#
# pseudoDf Test.Stat Df Pr(>chisq)
# 1 38
# 2 40 6.6016 2 0.03685 *
Die Gewichte hier sind nicht so extrem. Die vorausgesagten Gruppe Mittel unterscheiden sich geringfügig ( A
: WLS 0.36673
, robust 0.35722
; B
: WLS 0.77646
, robust 0.70433
; C
: WLS 0.50554
, robust 0.51845
), mit den Mitteln B
und C
weniger extreme Werte gezogen wird.
In der Ökonometrie ist der Huber-White- Standardfehler ("Sandwich") sehr beliebt. Wie bei der Welch-Korrektur ist es auch hier nicht erforderlich, dass Sie die Abweichungen a priori kennen und die Gewichte anhand Ihrer Daten schätzen und / oder von einem Modell abhängig machen, das möglicherweise nicht korrekt ist. Andererseits weiß ich nicht, wie ich das in eine ANOVA integrieren soll, was bedeutet, dass Sie sie nur für die Tests einzelner Dummy-Codes erhalten, was mir in diesem Fall weniger hilfreich erscheint, aber ich werde sie trotzdem demonstrieren:
library(sandwich)
mod = lm(values~ind, stacked.data, na.action=na.omit)
sqrt(diag(vcovHC(mod)))
# (Intercept) indB indC
# 0.03519921 0.16997457 0.08246131
2*(1-pt(coef(mod) / sqrt(diag(vcovHC(mod))), df=38))
# (Intercept) indB indC
# 1.078249e-12 2.087484e-02 1.005212e-01
Die Funktion vcovHC
berechnet eine heteroskedastische konsistente Varianz-Kovarianz-Matrix für Ihre Betas (Ihre Dummy-Codes), wofür die Buchstaben im Funktionsaufruf stehen. Um Standardfehler zu erhalten, extrahieren Sie die Hauptdiagonale und nehmen die Quadratwurzeln. Um Tests für Ihre Betas zu erhalten, dividieren Sie Ihre Koeffizientenschätzungen durch die SEs und vergleichen Sie die Ergebnisse mit der entsprechenden Verteilung ( dh der Verteilung mit Ihren verbleibenden Freiheitsgraden). ttt
Für R
Benutzer bemerkt @TomWenseleers in den Kommentaren unten, dass die Funktion ? Anova im car
Paket ein white.adjust
Argument akzeptieren kann, um einen Wert für den Faktor zu erhalten, der heteroskedastische konsistente Fehler verwendet. p
Anova(mod, white.adjust=TRUE)
# Analysis of Deviance Table (Type II tests)
#
# Response: values
# Df F Pr(>F)
# ind 2 3.9946 0.02663 *
# Residuals 38
# ---
# Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Sie können versuchen, eine empirische Schätzung der tatsächlichen Stichprobenverteilung Ihrer Teststatistik durch Bootstrapping zu erhalten . Zunächst erstellen Sie eine echte Null, indem Sie alle Gruppenmittelwerte exakt gleich machen. Anschließend nehmen Sie eine erneute Abtastung mit Ersatz vor und berechnen Ihre Teststatistik ( ) für jede Bootprobe, um eine empirische Schätzung der Stichprobenverteilung von unter der Null mit Ihren Daten zu erhalten, unabhängig von deren Status in Bezug auf Normalität oder Homogenität. Der Anteil dieser Stichprobenverteilung, der so extrem oder extremer ist als Ihre beobachtete Teststatistik, ist der Wert: FFp
mod = lm(values~ind, stacked.data, na.action=na.omit)
F.stat = anova(mod)[1,4]
# create null version of the data
nullA = my.data$A - mean(my.data$A)
nullB = my.data$B - mean(my.data$B, na.rm=T)
nullC = my.data$C - mean(my.data$C, na.rm=T)
set.seed(1)
F.vect = vector(length=10000)
for(i in 1:10000){
A = sample(na.omit(nullA), 15, replace=T)
B = sample(na.omit(nullB), 13, replace=T)
C = sample(na.omit(nullC), 13, replace=T)
boot.dat = stack(list(A=A, B=B, C=C))
boot.mod = lm(values~ind, boot.dat)
F.vect[i] = anova(boot.mod)[1,4]
}
1-mean(F.stat>F.vect)
# [1] 0.0485
In mancher Hinsicht ist Bootstrapping der ultimative Ansatz mit reduzierten Annahmen, um eine Analyse der Parameter (z. B. Mittelwerte) durchzuführen. Es wird jedoch vorausgesetzt, dass Ihre Daten eine gute Darstellung der Grundgesamtheit sind, was bedeutet, dass Sie eine angemessene Stichprobengröße haben. Da Ihre 's klein sind, kann es weniger vertrauenswürdig sein. Wahrscheinlich besteht der ultimative Schutz gegen Nichtnormalität und Heterogenität in der Verwendung eines nichtparametrischen Tests. Die grundlegende nicht parametrische Version einer ANOVA ist der Kruskal-Wallis-Test : n
kruskal.test(values~ind, stacked.data, na.action=na.omit)
# Kruskal-Wallis rank sum test
#
# data: values by ind
# Kruskal-Wallis chi-squared = 5.7705, df = 2, p-value = 0.05584
Obwohl der Kruskal-Wallis-Test definitiv der beste Schutz gegen Typ-I-Fehler ist, kann er nur mit einer einzelnen kategorialen Variablen (dh ohne kontinuierliche Prädiktoren oder faktorielle Konstruktionen) verwendet werden und hat die geringste Aussagekraft aller diskutierten Strategien. Ein weiterer nicht parametrischer Ansatz ist die Verwendung der ordinalen logistischen Regression . Dies scheint für viele Leute seltsam, aber Sie müssen nur davon ausgehen, dass Ihre Antwortdaten legitime Ordinalinformationen enthalten, was sie sicherlich tun, oder jede andere der oben genannten Strategien ist ebenfalls ungültig:
library(rms)
olr.mod = orm(values~ind, stacked.data)
olr.mod
# Model Likelihood Discrimination Rank Discrim.
# Ratio Test Indexes Indexes
# Obs 41 LR chi2 6.63 R2 0.149 rho 0.365
# Unique Y 41 d.f. 2 g 0.829
# Median Y 0.432 Pr(> chi2) 0.0363 gr 2.292
# max |deriv| 2e-04 Score chi2 6.48 |Pr(Y>=median)-0.5| 0.179
# Pr(> chi2) 0.0391
Möglicherweise geht aus der Ausgabe nichts hervor, aber der Test des gesamten Modells, der in diesem Fall der Test Ihrer Gruppen ist, ist der chi2
schlechteste Discrimination Indexes
. Es werden zwei Versionen aufgelistet, ein Wahrscheinlichkeitsquotiententest und ein Punktetest. Der Likelihood-Ratio-Test wird normalerweise als der beste angesehen. Es ergibt sich ein Wert von . p0.0363