Ada sejumlah opsi yang tersedia saat berurusan dengan data heteroskedastik. Sayangnya, tidak satu pun dari mereka dijamin untuk selalu bekerja. Berikut adalah beberapa opsi yang saya kenal:
- transformasi
- Welch ANOVA
- kuadrat terkecil tertimbang
- regresi yang kuat
- heteroscedasticity konsisten kesalahan standar
- bootstrap
- Tes Kruskal-Wallis
- regresi logistik ordinal
Pembaruan: Ini adalah demonstrasi di R
beberapa cara pemasangan model linier (yaitu, ANOVA atau regresi) ketika Anda memiliki heteroskedastisitas / heterogenitas varians.
Mari kita mulai dengan melihat data Anda. Untuk kenyamanan, saya minta mereka memuatnya ke dalam dua frame data yang disebut my.data
(yang terstruktur seperti di atas dengan satu kolom per grup) dan stacked.data
(yang memiliki dua kolom: values
dengan angka dan ind
dengan indikator grup).
Kami dapat secara resmi menguji heteroskedastisitas dengan uji Levene:
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
Benar saja, Anda memiliki heteroskedastisitas. Kami akan memeriksa untuk melihat apa varian dari grup tersebut. Aturan praktisnya adalah bahwa model linear cukup kuat untuk heterogenitas varians selama varians maksimum tidak lebih dari lebih besar dari varians minimum, jadi kami juga akan menemukan rasio itu: 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
Varians Anda berbeda secara substansial, dengan yang terbesar B
, yaitu yang terkecil,. Ini adalah tingkat heteroscedsaticity yang bermasalah. 19×A
parallel.universe.data
2.7B
.7C
Untuk menunjukkan cara kerjanya:
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
Menggunakan transformasi akar kuadrat menstabilkan data tersebut dengan cukup baik. Anda dapat melihat peningkatan untuk data paralel semesta di sini:
λλ = .5λ = 0
boxcox(values~ind, data=stacked.data, na.action=na.omit)
boxcox(values~ind, data=stacked.pu.data, na.action=na.omit)
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
Pendekatan yang lebih umum adalah dengan menggunakan kuadrat terkecil tertimbang . Karena beberapa kelompok ( B
) menyebar lebih banyak, data dalam kelompok tersebut memberikan lebih sedikit informasi tentang lokasi rata-rata daripada data dalam kelompok lain. Kita dapat membiarkan model memasukkan ini dengan memberikan bobot pada setiap titik data. Sistem yang umum adalah menggunakan kebalikan dari varians grup sebagai bobot:
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
Fhal4.5089
0.01749
zt50100N
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 *
Bobot di sini tidak ekstrem. Berarti kelompok diprediksi sedikit berbeda ( A
: WLS 0.36673
, kuat 0.35722
; B
: WLS 0.77646
, kuat 0.70433
; C
: WLS 0.50554
, kuat 0.51845
), dengan cara B
dan C
yang kurang ditarik oleh nilai-nilai ekstrim.
Dalam ekonometrik kesalahan standar Huber-White ("sandwich") sangat populer. Seperti koreksi Welch, ini tidak mengharuskan Anda untuk mengetahui varian a-priori dan tidak mengharuskan Anda memperkirakan bobot dari data Anda dan / atau bergantung pada model yang mungkin tidak benar. Di sisi lain, saya tidak tahu bagaimana menggabungkan ini dengan ANOVA, yang berarti bahwa Anda hanya mendapatkannya untuk tes kode boneka individu, yang menurut saya kurang membantu dalam kasus ini, tetapi saya akan tetap menunjukkannya:
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
vcovHC
ttt
R
car
white.adjust
hal
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
FFhal
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
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
Meskipun uji Kruskal-Wallis jelas merupakan perlindungan terbaik terhadap kesalahan tipe I, tes ini hanya dapat digunakan dengan variabel kategori tunggal (yaitu, tidak ada prediktor berkelanjutan atau desain faktorial) dan memiliki kekuatan paling sedikit dari semua strategi yang dibahas. Pendekatan non-parametrik lain adalah dengan menggunakan regresi logistik ordinal . Ini terlihat aneh bagi banyak orang, tetapi Anda hanya perlu berasumsi bahwa data respons Anda mengandung informasi ordinal yang sah, yang pasti mereka lakukan atau strategi lain di atas tidak valid:
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
chi2
Discrimination Indexes
hal0.0363