Przeprowadziłem kilka eksperymentów na danych symulowanych, aby sprawdzić, która metoda działa najlepiej. Proszę przeczytać moje ustalenia poniżej.
Przyjrzyjmy się dwóm różnym scenariuszom - po pierwsze, gdy nie ma bezpośredniego związku między sklepami DUI i alkoholowymi, a po drugie, gdy mamy bezpośredni związek. Następnie sprawdź każdą z metod, aby zobaczyć, która metoda działa najlepiej.
Przypadek 1: Brak bezpośredniego związku, ale oba są związane z populacją
library(rmutil)
############
## Simulating Data
set.seed(111)
# Simulating city populations
popln <- rpareto(n=10000,m=10000,s=1.2)
# Simulating DUI numbers
e1 <- rnorm(10000,mean=0,sd=15)
DUI = 100 + popln * 0.04 + e1
summary(DUI)
truehist(log(DUI))
# Simulating Nbr of Liquor stores
e2 <- rnorm(100,mean=0,sd=5)
Nbr_Liquor_Stores = 20 + popln * 0.009 + e2
summary(Nbr_Liquor_Stores)
truehist(log(Nbr_Liquor_Stores))
dat <- data.frame(popln,DUI,Nbr_Liquor_Stores)
Teraz, gdy dane są symulowane, zobaczmy, jak radzi sobie każda z metod.
## Method 0: Simple OLS
fit0 <- lm(DUI~Nbr_Liquor_Stores,data=dat)
summary(fit0)
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.4353630 0.2801544 33.68 <2e-16 ***
Nbr_Liquor_Stores 4.4444207 0.0001609 27617.49 <2e-16 ***
Nbr_Liquor_Stores bardzo znaczący, zgodnie z oczekiwaniami. Chociaż związek jest pośredni.
## Method 1: Divide Liquor Stores by population and then regress
fit1 <- lm( I(DUI/popln) ~ Nbr_Liquor_Stores, data=dat)
summary(fit1)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.981e-01 4.143e-02 12.022 <2e-16 ***
Nbr_Liquor_Stores -1.325e-05 2.380e-05 -0.557 0.578
Nbr_Liquor_Stores nie ma znaczenia. Niby działa, ale nie wyciągajmy jeszcze wniosków.
## Method 2: Divide Liquor Stores by population and then regress
fit2 <- lm( DUI ~ Nbr_Liquor_Stores + popln, data=dat)
summary(fit2)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.003e+02 6.022e-01 166.569 <2e-16 ***
Nbr_Liquor_Stores -1.603e-02 3.042e-02 -0.527 0.598
popln 4.014e-02 2.738e-04 146.618 <2e-16 ***
Nbr_Liquor_Stores nieistotne, wartość p jest również dość zbliżona do metody 1.
## Method 3: "DUI per capita" on "liquer stores per capita" and "population size"
fit3 <- lm( I(DUI/popln) ~ I(Nbr_Liquor_Stores/popln) + popln, data=dat)
summary(fit3)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.841e-02 1.300e-02 2.187 0.0288 *
I(Nbr_Liquor_Stores/popln) 4.886e+00 1.603e-02 304.867 <2e-16 ***
popln -8.426e-09 6.675e-08 -0.126 0.8996
(Nbr_Liquor_Stores / popln) bardzo znaczący! Nie spodziewałem się tego, być może ta metoda nie jest najlepsza do opisu problemu.
Przypadek 2: Bezpośredni związek z populacją i Nbr_Liquor_Stores
### Simulating Data
set.seed(111)
# Simulating city populations
popln <- rpareto(n=10000,m=10000,s=1.2)
# Simulating Nbr of Liquor stores
e2 <- rnorm(100,mean=0,sd=5)
Nbr_Liquor_Stores = 20 + popln * 0.009 + e2
summary(Nbr_Liquor_Stores)
truehist(log(Nbr_Liquor_Stores))
# Simulating DUI numbers
e1 <- rnorm(10000,mean=0,sd=15)
DUI = 100 + popln * 0.021 + Nbr_Liquor_Stores * 0.01 + e1
summary(DUI)
truehist(log(DUI))
dat <- data.frame(popln,DUI,Nbr_Liquor_Stores)
Zobaczmy wydajność każdej z metod w tym scenariuszu.
## Method 0: Simple OLS
fit0 <- lm(DUI~Nbr_Liquor_Stores,data=dat)
summary(fit0)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.244e+01 1.951e-01 268.8 <2e-16 ***
Nbr_Liquor_Stores 2.343e+00 1.121e-04 20908.9 <2e-16 ***
Oczekiwana, ale nie świetna metoda wnioskowania przyczynowego.
## Method 1: Divide Liquor Stores by population and then regress
fit1 <- lm( I(DUI/popln) ~ Nbr_Liquor_Stores, data=dat)
summary(fit1)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.705e-01 4.005e-02 11.747 <2e-16 ***
Nbr_Liquor_Stores -1.294e-05 2.301e-05 -0.562 0.574
To dla mnie niespodzianka, spodziewałem się, że ta metoda uchwyci związek, ale go nie odbierze. Więc ta metoda zawodzi w tym scenariuszu!
## Method 2: Divide Liquor Stores by population and then regress
fit2 <- lm( DUI ~ Nbr_Liquor_Stores + popln, data=dat)
summary(fit2)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.013e+02 5.945e-01 170.391 <2e-16 ***
Nbr_Liquor_Stores -5.484e-02 2.825e-02 -1.941 0.0523 .
popln 2.158e-02 2.543e-04 84.875 <2e-16 ***
Nbr_Liquor_Stores jest znaczący, wartość p ma sens. Dla mnie wyraźny zwycięzca.
## Method 3: "DUI per capita" on "liquer stores per capita" and "population size"
fit3 <- lm( I(DUI/popln) ~ I(Nbr_Liquor_Stores/popln) + popln, data=dat)
summary(fit3)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 6.540e-02 1.485e-02 4.405 1.07e-05 ***
I(Nbr_Liquor_Stores/popln) 3.915e+00 1.553e-02 252.063 < 2e-16 ***
popln -2.056e-08 7.635e-08 -0.269 0.788
TLDR; Metoda 2 zapewnia najdokładniejsze wartości p dla różnych scenariuszy.