Pruebas de Normalidad para los residuos

Econometría UES

Importación de Datos

library(readr)
ejemplo_regresion <- read_csv("G:/clases/Econometria_r/ejemplo_regresion.csv")
head(ejemplo_regresion)
## # A tibble: 6 × 3
##      X1    X2     Y
##   <dbl> <dbl> <dbl>
## 1  3.92  7298  0.75
## 2  3.61  6855  0.71
## 3  3.32  6636  0.66
## 4  3.07  6506  0.61
## 5  3.06  6450  0.7 
## 6  3.11  6402  0.72

Modelo Estimado

library(stargazer)
modelo_estimado<-lm("Y~.",data=ejemplo_regresion)
stargazer(modelo_estimado,title = "Modelo para Ejemplo", type = "html")
Modelo para Ejemplo
Dependent variable:
NA
X1 0.237***
(0.056)
X2 -0.0002***
(0.00003)
Constant 1.564***
(0.079)
Observations 25
R2 0.865
Adjusted R2 0.853
Residual Std. Error 0.053 (df = 22)
F Statistic 70.661*** (df = 2; 22)
Note: p<0.1; p<0.05; p<0.01

Ajuste de los residuos a la Distribución Normal

Verificando el ajuste de los residuos a la distribución normal, se usará la librería fitdistrplus

library(fitdistrplus)
fit_normal<-fitdist(data = modelo_estimado$residuals,distr = "norm")
plot(fit_normal)

summary(fit_normal)
## Fitting of the distribution ' norm ' by maximum likelihood 
## Parameters : 
##          estimate  Std. Error
## mean 7.770748e-18 0.010000382
## sd   5.000191e-02 0.007058615
## Loglikelihood:  39.41889   AIC:  -74.83778   BIC:  -72.40002 
## Correlation matrix:
##      mean sd
## mean    1  0
## sd      0  1

1. Prueba de Normalidad de Jarque Bera

Usando tseries

library(tseries)
salida_JB<-jarque.bera.test(modelo_estimado$residuals)
salida_JB
## 
##  Jarque Bera Test
## 
## data:  modelo_estimado$residuals
## X-squared = 0.93032, df = 2, p-value = 0.628
library(fastGraph)
alpha_sig<-0.05
JB<-salida_JB$statistic
gl<-salida_JB$parameter
VC<-qchisq(1-alpha_sig,gl,lower.tail = TRUE)
shadeDist(JB,ddist = "dchisq",
          parm1 = gl,
          lower.tail = FALSE,xmin=0,
          sub=paste("VC:",round(VC,2)," ","JB:",round(JB,2)))

Usando notmtest (descatalogada)

library(normtest)
jb.norm.test(modelo_estimado$residuals)
## 
##  Jarque-Bera test for normality
## 
## data:  modelo_estimado$residuals
## JB = 0.93032, p-value = 0.5045

2. Prueba de Kolmogorov Smirnov -Lilliefors

Cálculo Manual

library(dplyr)  # Carga la librería dplyr para manipulación de datos
library(gt)  # Carga la librería gt para crear tablas de datos
library(gtExtras)  # Carga la librería gtExtras para agregar funcionalidades a las tablas creadas con gt
residuos<-modelo_estimado$residuals  # Crea un vector con los residuos del modelo estimado
residuos %>%  # Utiliza el operador %>% para encadenar las operaciones siguientes al vector residuos
  as_tibble() %>%  # Convierte el vector residuos en una tibble (tabla) de una columna
  mutate(posicion=row_number()) %>%  # Agrega una columna llamada "posicion" con el número de fila
  arrange(value) %>%  # Ordena la tabla por los valores de residuos en orden ascendente
  mutate(dist1=row_number()/n()) %>%  # Agrega una columna "dist1" con los percentiles según su posición en la tabla (usando la función row_number() y n() para obtener el número de filas)
  mutate(dist2=(row_number()-1)/n()) %>%  # Agrega una columna "dist2" con los percentiles según su posición en la tabla, pero ajustando en una unidad para evitar problemas con los extremos de la distribución
  mutate(zi=as.vector(scale(value,center=TRUE))) %>%  # Agrega una columna "zi" con los valores de residuos escalados para tener media cero y varianza uno
  mutate(pi=pnorm(zi,lower.tail = TRUE)) %>%  # Agrega una columna "pi" con los valores de la función de distribución acumulada (CDF) de una distribución normal estándar evaluada en los valores de zi
  mutate(dif1=abs(dist1-pi)) %>%  # Agrega una columna "dif1" con las diferencias absolutas entre los percentiles según la posición y los valores de pi
  mutate(dif2=abs(dist2-pi)) %>%  # Agrega una columna "dif2" con las diferencias absolutas entre los percentiles ajustados según la posición y los valores de pi
  rename(residuales=value) -> tabla_KS  # Renombra la columna "value" como "residuales" y asigna la tabla resultante a la variable tabla_KS


#Formato
 tabla_KS %>%  # Utiliza el operador %>% para encadenar las operaciones siguientes a la tabla tabla_KS
  gt() %>%  # Crea una tabla con la función gt()
  tab_header("Tabla para calcular el Estadistico KS") %>%  # Agrega un encabezado a la tabla
  tab_source_note(source_note = "Fuente: Elaboración propia") %>%  # Agrega una nota de fuente a la tabla
  tab_style(  # Cambia el estilo de algunas celdas de la tabla
    style = list(
      cell_fill(color = "#A569BD"),  # Cambia el color de fondo de las celdas a un tono de morado
      cell_text(style = "italic")  # Cambia el estilo de texto de las celdas a itálico
      ),
    locations = cells_body(  # Aplica el estilo a las celdas del cuerpo de la tabla que cumplan las siguientes condiciones:
      columns = dif1,  # Que pertenezcan a la columna "dif1"
      rows = dif1==max(dif1)  # Que pertenezcan a la fila donde el valor de "dif1" es máximo
    )) %>%
   tab_style(  # Cambia el estilo de algunas celdas de la tabla
    style = list(
      cell_fill(color = "#3498DB"),  # Cambia el color de fondo de las celdas a un tono de azul
      cell_text(style = "italic")  # Cambia el estilo de texto de las celdas a itálico
      ),
    locations = cells_body(  # Aplica el estilo a las celdas del cuerpo de la tabla que cumplan las siguientes condiciones:
      columns = dif2,  # Que pertenezcan a la columna "dif2"
      rows = dif2==max(dif2)  # Que pertenezcan a la fila donde el valor de "dif2" es máximo
    ))
Tabla para calcular el Estadistico KS
residuales posicion dist1 dist2 zi pi dif1 dif2
-0.085089833 19 0.04 0.00 -1.66734963 0.04772245 0.007722452 0.047722452
-0.069637086 22 0.08 0.04 -1.36455045 0.08619719 0.006197193 0.046197193
-0.062183196 4 0.12 0.08 -1.21849022 0.11151887 0.008481131 0.031518869
-0.057379932 25 0.16 0.12 -1.12436944 0.13042817 0.029571834 0.010428166
-0.057277771 12 0.20 0.16 -1.12236757 0.13085309 0.069146907 0.029146907
-0.048434733 11 0.24 0.20 -0.94908676 0.17128824 0.068711757 0.028711757
-0.039102258 3 0.28 0.24 -0.76621535 0.22177409 0.058225910 0.018225910
-0.033971640 16 0.32 0.28 -0.66568001 0.25280783 0.067192174 0.027192174
-0.024886579 17 0.36 0.32 -0.48765671 0.31289651 0.047103492 0.007103492
-0.022166535 13 0.40 0.36 -0.43435700 0.33201461 0.067985390 0.027985390
-0.018597878 8 0.44 0.40 -0.36442855 0.35776901 0.082230992 0.042230992
-0.010121525 21 0.48 0.44 -0.19833299 0.42139227 0.058607729 0.018607729
-0.003341163 2 0.52 0.48 -0.06547065 0.47389964 0.046100362 0.006100362
0.012424659 6 0.56 0.52 0.24346329 0.59617674 0.036176739 0.076176739
0.016240338 5 0.60 0.56 0.31823217 0.62484558 0.024845584 0.064845584
0.017281530 20 0.64 0.60 0.33863450 0.63255746 0.007442545 0.032557455
0.026439478 10 0.68 0.64 0.51808602 0.69780087 0.017800874 0.057800874
0.026966239 18 0.72 0.68 0.52840800 0.70139191 0.018608095 0.021391905
0.030236216 7 0.76 0.72 0.59248375 0.72323665 0.036763350 0.003236650
0.035565142 15 0.80 0.76 0.69690497 0.75706887 0.042931135 0.002931135
0.040753758 14 0.84 0.80 0.79857675 0.78773206 0.052267936 0.012267936
0.072518915 23 0.88 0.84 1.42102038 0.92234458 0.042344582 0.082344582
0.073469743 1 0.92 0.88 1.43965200 0.92501706 0.005017061 0.045017061
0.074601871 24 0.96 0.92 1.46183625 0.92810696 0.031893044 0.008106956
0.105692240 9 1.00 0.96 2.07105726 0.98082328 0.019176722 0.020823278
Fuente: Elaboración propia

Cálculo del estadístico D:

D<-max(max(tabla_KS$dif1),max(tabla_KS$dif2))
print(D)
## [1] 0.08234458

Valor crítico de la tabla de Lilliefors

Conclusión:

En este caso dado que \(0.0823446\) \(<0.1726\) No se rechaza la Hipótesis Nula: \(\epsilon \sim N(0,\sigma^{2})\), por lo que los residuos siguen una distribución normal.

Usando nortest

library(nortest)
prueba_KS<-lillie.test(modelo_estimado$residuals)
prueba_KS
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  modelo_estimado$residuals
## D = 0.082345, p-value = 0.9328
p.value<-prueba_KS$p.value

En este caso dado que \(0.9327912\) \(>0.05\) No se rechaza la Hipótesis Nula: \(\epsilon \sim N(0,\sigma^{2})\), por lo que los residuos siguen una distribución normal.

3. Prueba de Shapiro - Wilk

Cálculo Manual

library(dplyr)
library(gt)
residuos<-modelo_estimado$residuals
residuos %>%  
  as_tibble() %>%
  rename(residuales=value) %>%
  arrange(residuales) %>%
  mutate(pi=(row_number()-0.375)/(n()+0.25)) %>%
  mutate(mi=qnorm(pi,lower.tail = TRUE)) %>% 
  mutate(ai=0)->tabla_SW

m<-sum(tabla_SW$mi^2)
n<-nrow(ejemplo_regresion)
theta<-1/sqrt(n)
tabla_SW$ai[n]<- -2.706056*theta^5+4.434685*theta^4-2.071190*theta^3-0.147981*theta^2+0.2211570*theta+tabla_SW$mi[n]/sqrt(m)
tabla_SW$ai[n-1]<- -3.582633*theta^5+5.682633*theta^4-1.752461*theta^3-0.293762*theta^2+0.042981*theta+tabla_SW$mi[n-1]/sqrt(m)
tabla_SW$ai[1]<- -tabla_SW$ai[n]
tabla_SW$ai[2]<- -tabla_SW$ai[n-1]
omega<-(m-2*tabla_SW$mi[n]^2-2*tabla_SW$mi[n-1]^2)/(1-2*tabla_SW$ai[n]^2-2*tabla_SW$ai[n-1]^2)
tabla_SW$ai[3:(n-2)]<-tabla_SW$mi[3:(n-2)]/sqrt(omega)

tabla_SW %>% 
  mutate(ai_ui=ai*residuales,ui2=residuales^2) ->tabla_SW

tabla_SW %>%
  gt() %>% tab_header("Tabla para calcular el Estadistico W") %>%  # Agrega un encabezado a la tabla
  tab_source_note(source_note = "Fuente: Elaboración propia")
Tabla para calcular el Estadistico W
residuales pi mi ai ai_ui ui2
-0.085089833 0.02475248 -1.96421684 -0.44179982 0.0375926725 0.00724027966
-0.069637086 0.06435644 -1.51919718 -0.31084122 0.0216460772 0.00484932379
-0.062183196 0.10396040 -1.25930333 -0.25447584 0.0158241211 0.00386674992
-0.057379932 0.14356436 -1.06444156 -0.21509882 0.0123423556 0.00329245654
-0.057277771 0.18316832 -0.90335666 -0.18254732 0.0104559034 0.00328074300
-0.048434733 0.22277228 -0.76286392 -0.15415701 0.0074665537 0.00234592337
-0.039102258 0.26237624 -0.63603674 -0.12852819 0.0050257427 0.00152898660
-0.033971640 0.30198020 -0.51871372 -0.10481995 0.0035609055 0.00115407231
-0.024886579 0.34158416 -0.40814351 -0.08247629 0.0020525526 0.00061934182
-0.022166535 0.38118812 -0.30236184 -0.06110028 0.0013543815 0.00049135529
-0.018597878 0.42079208 -0.19986756 -0.04038857 0.0007511418 0.00034588106
-0.010121525 0.46039604 -0.09943603 -0.02009370 0.0002033789 0.00010244527
-0.003341163 0.50000000 0.00000000 0.00000000 0.0000000000 0.00001116337
0.012424659 0.53960396 0.09943603 0.02009370 0.0002496574 0.00015437215
0.016240338 0.57920792 0.19986756 0.04038857 0.0006559241 0.00026374859
0.017281530 0.61881188 0.30236184 0.06110028 0.0010559063 0.00029865129
0.026439478 0.65841584 0.40814351 0.08247629 0.0021806299 0.00069904597
0.026966239 0.69801980 0.51871372 0.10481995 0.0028265997 0.00072717803
0.030236216 0.73762376 0.63603674 0.12852819 0.0038862062 0.00091422875
0.035565142 0.77722772 0.76286392 0.15415701 0.0054826161 0.00126487936
0.040753758 0.81683168 0.90335666 0.18254732 0.0074394891 0.00166086875
0.072518915 0.85643564 1.06444156 0.21509882 0.0155987331 0.00525899308
0.073469743 0.89603960 1.25930333 0.25447584 0.0186962745 0.00539780313
0.074601871 0.93564356 1.51919718 0.31084122 0.0231893370 0.00556543919
0.105692240 0.97524752 1.96421684 0.44179982 0.0466948120 0.01117084954
Fuente: Elaboración propia

Cálculo del Estadistico W

W<-(sum(tabla_SW$ai_ui)^2)/sum(tabla_SW$ui2)
print(W)
## [1] 0.9700088

Cálculo del \(W_n\) y su p value

mu<-0.0038915*log(n)^3-0.083751*log(n)^2-0.31082*log(n)-1.5861
sigma<-exp(0.0030302*log(n)^2-0.082676*log(n)-0.4803)
Wn<-(log(1-W)-mu)/sigma
print(Wn)
## [1] -0.3726406
p.value<-pnorm(Wn,lower.tail = FALSE)
print(p.value)
## [1] 0.645292
library(fastGraph)
shadeDist(Wn,ddist = "dnorm",lower.tail = FALSE)

En este caso dado que \(0.645292\) \(>0.05\) No se rechaza la Hipótesis Nula: \(\epsilon \sim N(0,\sigma^{2})\), por lo que los residuos siguen una distribución normal.

Usando la librería stats (precargada al iniciar R)

salida_SW<-shapiro.test(modelo_estimado$residuals)
print(salida_SW)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo_estimado$residuals
## W = 0.97001, p-value = 0.6453

Mismos resultados que en el cálculo manual.

Importante, a partir de esta salida se puede calcular el \(W_n\) si se llegará a necesitar:

Wn_salida<-qnorm(salida_SW$p.value,lower.tail = FALSE)
print(Wn_salida)
## [1] -0.3726406