Alternativen zur Einweg-ANOVA für heteroskedastische Daten


36

Ich habe Daten aus 3 Gruppen von Algenbiomasse ( , , ), die ungleiche Stichprobengrößen enthalten ( , , ) und möchte vergleichen, ob diese Gruppen aus derselben Population stammen.B C n A = 15 n B = 13 n C = 12ABCnA=15nB=13nC=12

Einweg-ANOVA wäre auf jeden Fall der richtige Weg, doch bei der Durchführung von Normalitätstests für meine Daten scheint Heteroskedascity das Hauptproblem zu sein. Meine Rohdaten ergaben ohne Transformation ein Varianzverhältnis ( ), das sehr viel höher ist als der kritische Wert ( ), und daher kann ich keine Einweg-ANOVA durchführen .Fmax=19.1Fcrit=4.16

Ich habe auch versucht, meine Daten zu normalisieren. Selbst nach Versuchen mit verschiedenen Transformationen (log, Quadratwurzel, Quadrat) betrug das niedrigste Fmax das nach der Transformation mit einer log10 -Transformation erzeugt wurde, 7.16 , was im Vergleich zu F _ {\ rm crit} immer noch höher war Fcrit.

Kann mir hier jemand raten, wohin ich von hier aus gehen soll? Ich kann mir keine anderen Transformationsmethoden für die Normalisierung durch Daten vorstellen. Gibt es Alternativen zu einer Einweg-ANOVA?

PS: meine Rohdaten sind unten:

A: 0.178 0.195 0.225 0.294 0.315 0.341 0.36  0.363 0.371 0.398 0.407 0.409 0.432 
   0.494 0.719
B: 0.11  0.111 0.204 0.416 0.417 0.441 0.492 0.965 1.113 1.19  1.233 1.505 1.897
C: 0.106 0.114 0.143 0.435 0.448 0.51  0.576 0.588 0.608 0.64  0.658 0.788 0.958

2
Der F-Test zeigt deutlich, dass die Gruppen nicht aus derselben Population stammen. Der nächste Schritt wäre die Interpretation dieses Ergebnisses, beginnend mit klaren Visualisierungen und einer quantitativen Beschreibung der nach Gruppen aufgeschlüsselten Daten.
whuber

Es gibt auch die Permutationstests im Münzpaket. Für ANOVA wäre es die Funktion oneway_test. Quick-R-Beispiel: statmethods.net/stats/resampling.html
user16263

Antworten:


73

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: valuesmit den Zahlen und indmit 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 Bdie 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.dataindem wir zu allen Werten und zu hinzufügen2.7B.7Cum 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:

Bildbeschreibung hier eingeben

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) 

Bildbeschreibung hier eingeben

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.445df = 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.50890.01749

Bildbeschreibung hier eingeben

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 Bund Cweniger 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 vcovHCberechnet 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 RBenutzer bemerkt @TomWenseleers in den Kommentaren unten, dass die Funktion ? Anova im carPaket ein white.adjustArgument 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 chi2schlechteste 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


1
Liebe deine Antworten! Jetzt gibt es einen Schimmer von zu Hause, um mit meinen Daten umzugehen! :) Welche dieser Ansätze würden Sie für meine Art von Daten wärmstens empfehlen, insbesondere im Hinblick auf die Bereitstellung einer ausreichenden statistischen Leistung? Ich bin nicht besonders daran interessiert, einen nicht parametrischen Ansatz zu verwenden, z. B. einen Kruskal-Wallis-Test, da dies bedeuten würde, dass ich wahrscheinlich einen Fehler vom Typ I begehen würde. Korrigiere mich, wenn ich falsch liege.
Rick L.

2
Ich werde hier etwas mehr Material aufarbeiten, wenn ich die Gelegenheit dazu habe, aber nein, der Kruskal-Wallis-Test bietet wahrscheinlich Ihren besten Schutz vor Typ-I-Fehlern. OTOH, es ist möglicherweise nicht die leistungsstärkste Option, die Sie haben.
gung - Wiedereinsetzung von Monica

4
Beachten Sie, dass es in der Bibliothek carauch die Option gibt, die white.adjust=TBehandlung der Heteroskedazität mithilfe von Standardfehlern mit Weiß-korrigierter Heteroskedastizität
einzustellen

3
Ja, es wird nur für lm's erwähnt, aber es scheint auch für aov' s zu funktionieren (Optionen für white.adjustsind white.adjust=c(FALSE, TRUE, "hc3", "hc0", "hc1", "hc2", "hc4")- für weitere Informationen siehe ?hccm)
Tom Wenseleers

1
@Nakx, nein, nicht das ich wüsste. Es ist eine Faustregel; Es ist unwahrscheinlich, dass es eine Veröffentlichung in der statistischen Literatur gibt. Es ist wahrscheinlich in einigen einführenden Lehrbüchern.
gung - Wiedereinsetzung von Monica
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.