La eliminación por lista (también conocida como eliminación por caso o análisis de caso completo) elimina todas las observaciones de sus datos, que tienen un valor faltante en una o más variables.
Se necesitan datos completos sin valores faltantes para muchos tipos de cálculos, por ejemplo, análisis de regresión o correlación. La eliminación por lista se utiliza para crear un conjunto de datos tan completo.
Muchos paquetes de software como R, SAS, Stata o SPSS utilizan la eliminación por lista como método predeterminado , si no se especifica nada más. Aunque es posible que aún no haya oído hablar de la eliminación por lista o por caso, probablemente ya la haya utilizado.
En esta publicación, le mostraré todo lo que necesita saber para aplicar la eliminación por lista a sus propios datos (Sugerencia: es posible que ya no desee usar la eliminación por lista después de leer este artículo).
Selecciona el tema de tu interés:
Ejemplo de análisis de caso completo para datos faltantes en R
A continuación, les mostraré un ejemplo en el lenguaje de programación estadística R, que ilustra cómo funciona el análisis completo de casos.
Considere los siguientes datos de ejemplo:
##### Crear algunos datos de ejemplo sintéticos ##### establecer _ seed ( 34567 ) # Establecer seed para obtener un ejemplo reproducible N <- 1000 # Tamaño de la muestra y <- rnorm ( N ) # Variable de resultado/objetivo x1 <- rnorm ( N, 10 , 5 ) # Primera variable independiente/auxiliar; Esta variable no está correlacionada con y x2 <- y + rnorm ( N, 2 , 5 ) # Segunda variable independiente/auxiliar; Esta variable está correlacionada con y x3 <- y + rnorm ( N, - 5 , 8 ) # Segunda variable independiente/auxiliar; También correlacionado con y data <- round ( data . frame ( y, x1, x2, x3 ) , 2 ) # Almacenar datos en un data frame head ( data ) data$y [ rbinom ( N, 1 , 0.9 ) == 0 ] <- NA # 10 % de valores faltantes en y data$x1 [ rbinom ( N, 1 , 0.8 ) == 0 ] <- NA # 20 % de valores faltantes en x1 cabeza ( datos ) |
set.seed(34567) # Set seed to get a reproducible example
N <- 1000 # Sample size
y <- rnorm(N) # Outcome/target variable
x1 <- rnorm(N, 10, 5) # First independent/auxiliary variable; This variable is uncorrelated with y
x2 <- y + rnorm(N, 2, 5) # Second independent/auxiliary variable; This variable is correlated with y
x3 <- y + rnorm(N, – 5, 8) # Second independent/auxiliary variable; Also correlated with y
data <- round(data.frame(y, x1, x2, x3), 2) # Store data in a data frame
head(data)
data$y[rbinom(N, 1, 0.9) == 0] <- NA # 10% missing values in y
data$x1[rbinom(N, 1, 0.8) == 0] <- NA # 20% missing values in x1
head(data)
Tabla 1: Primeras 6 filas de nuestros datos de ejemplo sintéticos
Como puede ver en la Tabla 1, faltan valores ( en R se muestra como NA ) en la variable objetivo Y (tasa de respuesta 90%) y en la variable auxiliar X1 (tasa de respuesta 80%). Las variables X2 y X3 no contienen ningún valor faltante.
Esta es una situación típica que también puede encontrar en la realidad. Las tasas faltantes del 20 por ciento o más no son nada especial en las encuestas voluntarias. Las preguntas especialmente delicadas sobre ingresos, orientación sexual o edad corren el riesgo de tener altas tasas de falta de respuesta.
Últimamente, por ejemplo, estaba trabajando en algunos datos sobre ingresos y condiciones de vida y me encontré con tasas faltantes en las variables de ingresos del 10-25%.
Pero, ¿qué significa eso para nuestros análisis de datos? Hagamos un ejemplo simple basado en nuestros datos sintéticos creados previamente con valores faltantes:
##### Ejemplo de análisis de regresión ##### model <- lm ( y ~ . , data ) # Resumen del modelo de regresión estimado ( model ) # Resumen de nuestra regresión |
model <- lm(y ~., data) # Estimate regression model
summary(model) # Summary of our regression
Tabla 2: Resumen de resultados de nuestro análisis de regresión
En la Tabla 2, puede ver algunos resultados regulares de una regresión lineal en nuestra variable dependiente Y. La variable X1 no tiene un impacto significativo en Y; no sorprende, ya que no modelamos ninguna correlación entre X1 e Y, cuando creó nuestros datos sintéticos.
Las variables X2 y X3, por el contrario, son predictores altamente significativos para nuestra variable objetivo Y, de nuevo, no sorprende.
La diferencia en comparación con un análisis sin valores faltantes se puede encontrar en la descripción de nuestro resultado: En la descripción de nuestro resultado de regresión en la Tabla 2, puede leer la línea » 259 observaciones eliminadas debido a faltantes «.
Debido a la eliminación por lista , el tamaño de nuestra muestra se redujo de 1000 a 741 observaciones, ¡una pérdida de más del 25 %! Eso es como descartar a 259 personas de nuestro conjunto de datos al frente de nuestro análisis.
La eliminación por lista de datos faltantes en R se realiza manualmente de la siguiente manera:
##### Eliminación por lista a mano ##### data_complete_cases <- data [ completa . casos ( datos ) , ] dim ( datos_completos_casos ) # [1] 741 4 |
data_complete_cases <- data[complete.cases(data), ] dim(data_complete_cases)
# [1] 741 4
Después de realizar la eliminación por casos con la función complete.cases , solo quedan 741 observaciones.
Si ejecuta de nuevo los análisis de regresión anteriores con nuestros datos completos, obtendrá exactamente los mismos resultados:
model_complete_cases <- lm ( y ~ . , data_complete_cases ) # Resumen del modelo de regresión estimado ( model_complete_cases ) # Resumen de nuestra regresión |
En caso de análisis de regresión, R elimina todas las observaciones incompletas por defecto . Sin embargo, este no es siempre el caso.
Si desea realizar un análisis de correlación, por ejemplo, verá que R no elimina automáticamente los casos incompletos. Tendría que hacer una eliminación por lista manualmente:
##### Análisis de correlación con y sin eliminación por listas ##### cor ( data$y, data$x1 ) # NA --> La función cor() no elimina las observaciones faltantes por defecto cor ( data_complete_cases$y, data_complete_cases$x1 ) # Correlación de datos completos |
cor(data$y, data$x1) # NA –> The function cor() is not deleting missing observations by default
cor(data_complete_cases$y, data_complete_cases$x1) # Correlation of complete data
Con archivos de casos completos, como data_complete_cases, puede realizar todos los análisis que desee sin problemas.
¿Es legítimo el análisis completo de casos?
Aunque la simplicidad del análisis completo de casos es una gran ventaja, la eliminación por lista causa grandes problemas en muchas situaciones de falta de datos.
Hay dos razones principales por las que la eliminación por caso puede ser problemática:
- El tamaño de la muestra se reduce.
- Las razones por las que faltan valores pueden no ser aleatorias
¡Echemos un vistazo más de cerca a estos dos problemas!
El primer problema, un tamaño de muestra más pequeño , ya se ilustró en los ejemplos de estudios de casos completos anteriores. Como has visto, más del 25% de nuestros datos fueron eliminados. Obviamente, eso es una gran pérdida para nuestro análisis de datos estadísticos.
Simple y llanamente: un tamaño de muestra más pequeño conduce a un menor poder estadístico de nuestros análisis.
El segundo problema, la aleatoriedad de nuestros datos faltantes , podría ser menos intuitivo y, por lo tanto, a menudo se descuida en la práctica.
En realidad, sin embargo, la no aleatoriedad de los datos faltantes puede resultar en estimaciones sesgadas y, por lo tanto, en conclusiones erróneas de su análisis de caso completo.
La aleatoriedad de los valores perdidos, es decir, el mecanismo perdido, se divide en tres tipos diferentes: Falta completamente al azar (MCAR), Falta al azar (MAR) y Falta no al azar (MNAR) ( Little und Rubin, 2002 ).
Si sus faltantes son MCAR, la eliminación por lista es menos problemática. Si sus valores faltantes son MAR o MNAR, es probable que su estudio de caso completo esté sesgado.
Veamos nuestro ejemplo de arriba:
##### Gráfico para valores perdidos y no perdidos ##### plot ( densidad ( y [ ! is . na ( data$y ) ] ) , xlab = "y" , main = "Valores observados y faltantes de Y" ) puntos ( densidad ( y [ is . na ( data$y ) ] ) , tipo = "l" , col = 2 ) leyenda ( "superior izquierda" , c ( "Valores observados" , "Valores perdidos") , lty = 1 , columna = 1 : 2 ) |
plot(density(y[!is.na(data$y)]), xlab = «y», main = «Observed and Missing Values of Y»)
points(density(y[is.na(data$y)]), type = «l», col = 2)
legend(«topleft», c(«Observed Values», «Missing Values»), lty = 1, col = 1:2)
Gráfico 1: Valores observados y faltantes de Y
Como puede ver en el gráfico 1, solo hay ligeras diferencias entre las densidades de los valores observados y perdidos.
Una prueba de Kolmogorov-Smirnov confirma lo que ya vimos gráficamente: las diferencias de nuestros valores observados y no observados no son significativas.
##### Prueba de Kolmogorov-Smirnov entre valores perdidos y no perdidos ##### ks _ prueba ( y [ ! es . na ( datos$y ) ] , y [ es . na ( datos$y ) ] ) |
ks.test(y[!is.na(data$y)], y[is.na(data$y)])
Tabla 3: Prueba de Kolmogorov-Smirnov de datos observados y faltantes
Tenga en cuenta que pudimos inspeccionar los mecanismos faltantes con estas pruebas estadísticas, ya que creamos los datos nosotros mismos. En realidad, no podríamos realizar tales pruebas y, por lo tanto, tendríamos que basarnos en supuestos teóricos sobre la aleatoriedad de nuestros datos incompletos.
Sin embargo, en general, es muy raro en las estadísticas que los datos faltantes sean MCAR . En la mayoría de los casos, debe intentar utilizar métodos más sofisticados, como la imputación de datos faltantes, para tener en cuenta los datos faltantes y la estructura de la falta.
Nota: No todos los métodos de imputación reducen el sesgo. De hecho, algunos métodos (por ejemplo , la imputación media o la sustitución de datos faltantes por cero ) incluso aumentan el sesgo. Aprenda aquí , qué método es apropiado para su base de datos específica.
Sin embargo, veamos qué sucede, si tenemos alguna estructura sistemática en nuestros valores faltantes (mucho más realista). A modo de ilustración, considere los siguientes datos de ejemplo:
establecer _ seed ( 987654321 ) # Establecer seed para obtener un ejemplo reproducible N <- 5000 # Tamaño de muestra aumentado, para que el efecto sea más visible y <- rnorm ( N ) # Nuestra variable de resultado/objetivo. Aún no faltan valores x <- 2 * y + rnorm ( N, 10 , 5 ) # Variable independiente/auxiliar; Esta variable está correlacionada con y resp_prop <- x + rnorm ( N, 10 , 5 ) # Influencia sistemática de x en la ausencia de y. # Las observaciones con valores más bajos en x tienen una # propensión de respuesta más baja en y resp_prop [ resp_prop < media ( resp_prop ) ] <- NA # Aproximadamente 50% de valores faltantes sistemáticos en y |
N <- 5000 # Increased sample size, to make the effect more visible
y <- rnorm(N) # Our outcome/target variable. No missing values yet
x <- 2 * y + rnorm(N, 10, 5) # Independent/auxiliary variable; This variable is correlated with y
resp_prop <- x + rnorm(N, 10, 5) # Systematic influence of x on the missingness in y.
# Observations with lower values in x have a
# lower response propensity in y
resp_prop[resp_prop < mean(resp_prop)] <- NA # Approximately 50% systematic missing values in y
Ahora vamos a comprobar gráficamente cómo se distribuyen los valores observados y faltantes de Y.
par ( mfrow = c ( 1 , 2 ) ) # 2 parcelas en un gráfico plot ( densidad ( y [ ! is . na ( resp_prop ) ] ) , # Valores observados en negro xlim = c ( - 4 , 4 ) , ylim = c ( 0 , 0.48 ) , xlab = "Y" , main = "Valores observados y perdidos de Y" ) puntos ( densidad ( y [ is . na ( resp_prop ) ] ) , type = "l" , col = 2 ) # Datos faltantes en la leyenda roja ( " topleft" , c ( "Valores observados" , "Valores perdidos" ) , lty = 1 , col = 1 : 2 ) plot ( x [ ! es . na ( resp_prop ) ] , y [ ! es . na ( resp_prop ) ] , # Valores observados en negro xlim = c ( - 10 , 30 ) , ylim = c ( - 4 , 5 ) , xlab = "X" , ylab = "Y" , main = "Gráfica de correlación de X e Y" ) puntos ( x [ es . na ( resp_prop ) ] , y [ es . na ( resp_prop ) ] , col = 2 ) # Datos faltantes en abline rojo ( h = mean ( y ) , lwd = 2 , col = "deepskyblue" , lty = "discontinua" ) # Media verdadera (observada y faltante combinada) abline ( h = media ( y [ ! is . na ( resp_prop ) ] ) , lwd = 2 ) # Media de los valores observados abline ( h = media ( y [ is . na ( resp_prop ) ] ) , lwd = 2 , col = 2 ) # Leyenda de la media de los valores observados( "arriba a la izquierda" , c ( "Valores observados" , "Valores perdidos" , "Media de valores observados" , "Media de valores perdidos" , "Media verdadera" ) , pch = c ( 1 , 1 , NA, NA, NA ) , lwd = c ( NA, NA, 1 , 1 , 1 ) , col = c ( 1 , 2 , 1 , 2 , "azul cielo profundo" ) , lty = c ( "" , "" , "sólido" , "sólido" , "discontinua" ) ) |
plot(density(y[!is.na(resp_prop)]), # Observed values in black
xlim = c(- 4, 4), ylim = c(0, 0.48),
xlab = «Y», main = «Observed and Missing Values of Y»)
points(density(y[is.na(resp_prop)]), type = «l», col = 2) # Missing data in red
legend(«topleft», c(«Observed Values», «Missing Values»), lty = 1, col = 1:2)
plot(x[!is.na(resp_prop)], y[!is.na(resp_prop)], # Observed values in black
xlim = c(- 10, 30), ylim = c(- 4, 5),
xlab = «X», ylab = «Y», main = «Correlation Plot of X and Y»)
points(x[is.na(resp_prop)], y[is.na(resp_prop)], col = 2) # Missing data in red
abline(h = mean(y), lwd = 2, col = «deepskyblue», lty = «dashed») # True mean (observed & missing combined)
abline(h = mean(y[!is.na(resp_prop)]), lwd = 2) # Mean of observed values
abline(h = mean(y[is.na(resp_prop)]), lwd = 2, col = 2) # Mean of observed values
legend(«topleft»,
c(«Observed Values», «Missing Values», «Observed Values Mean», «Missing Values Mean», «True Mean»),
pch = c(1, 1, NA, NA, NA),
lwd = c(NA, NA, 1, 1, 1),
col = c(1, 2, 1, 2, «deepskyblue»),
lty = c(«», «», «solid», «solid», «dashed»))
Gráfico 2: Valores observados y faltantes de Y con estructura de respuesta sistemática
Como se muestra en el Gráfico 2 en el panel izquierdo, las densidades de los valores observados y faltantes difieren. Los casos completos parecen ser más altos en promedio.
En el panel derecho se ilustra un gráfico de correlación de X e Y. Como se modeló antes, cuando creamos los datos sintéticos, existe una correlación positiva entre X e Y.
Sin embargo, también podemos ver que la media de Y difiere entre los valores observados y perdidos. La media de los datos faltantes, ilustrada por la línea recta roja, indica un valor ligeramente más bajo para las observaciones con datos faltantes en Y.
Si realizáramos un análisis de caso completo, por lo tanto, sobrestimaríamos la media de Y . ¡No es realmente el resultado que esperaríamos ver!
##### Media de los valores observados y faltantes ##### round ( mean ( y [ ! is . na ( resp_prop ) ] ) , 2 ) # Los valores observados tienen una media de 0.24 round ( mean ( y [ is . na ( resp_prop ) ] ) , 2 ) # Los valores faltantes tienen una media de - 0,23 |
round(mean(y[!is.na(resp_prop)]), 2) # Observed values have a mean of 0.24
round(mean(y[is.na(resp_prop)]), 2) # Missing values have a mean of – 0.23
Esta impresión gráfica se confirma mediante una prueba de Kolmogorov-Smirnov:
##### Prueba de Kolmogorov-Smirnov de valores perdidos y no perdidos: falta sistemática ##### ks _ prueba ( y [ ! es . na ( datos$y ) ] , y [ es . na ( datos$y ) ] ) |
ks.test(y[!is.na(data$y)], y[is.na(data$y)])
El valor p de la prueba Kolmogorov-Smirnov es significativo: nuestros valores faltantes son significativamente diferentes a nuestros datos observados.
Entonces, para responder a nuestra pregunta » ¿Es legítimo el análisis completo de casos?» » en breve:
- Si el Problema 2) NO ocurre , nuestro análisis de caso completo para los datos faltantes tendrá menos poder estadístico, pero será legítimo.
- Si ocurre el Problema 2), ¡definitivamente deberíamos implementar algunos métodos más avanzados que la eliminación por listas para lidiar con nuestros datos faltantes!
Eliminación por listas en SPSS
¿No estás familiarizado con el lenguaje de programación R? ¡No te preocupes! Hay muchos otros programas de software disponibles que pueden encontrar filas incompletas en sus datos y realizar la eliminación por casos.
En el siguiente video, el orador Jason del canal de YouTube SPSSisFun compara tres opciones diferentes para tratar los datos que faltan en SPSS: eliminación por listas, eliminación por pares y imputación media.
Conclusión
La gran ventaja de la eliminación de listiwse es que es fácil de entender e implementar . De hecho, es el método predeterminado en muchos programas estadísticos como R o SPSS.
Sin embargo, la eliminación de casos a menudo conduce a un sesgo en las estimaciones de la encuesta e incluso si este no es el caso, desperdiciamos mucha información valiosa si se aplica la eliminación de listas.
Se pueden utilizar métodos más sofisticados, por ejemplo, imputación de datos faltantes , para reemplazar los valores faltantes con nuevos valores a fin de mejorar los análisis de datos ( Allison, 2002 ).
En resumen: ¡La eliminación por lista casi nunca es la mejor opción!
¿Algún comentario o pregunta?
Te mostré todo lo que sé sobre la eliminación por listas.
¡Ahora es tu turno!
¿También ha experimentado algún problema con los análisis de casos completos? ¿Qué métodos está utilizando para tratar con datos incompletos? ¿Tiene más preguntas sobre la eliminación por listas?
¡Desplácese hacia abajo y hágamelo saber en los comentarios !
Referencias
Allison, PD (2002). Datos faltantes: aplicaciones cuantitativas en las ciencias sociales . Publicaciones SAGE.
Little, RJA y Rubin, DB, editores (2002). Análisis estadístico con datos faltantes . Wiley-Blackwell.
Apéndice
¿Quieres saber cómo creé el gráfico de encabezado de esta página? ¡Aquí está el código!
El gráfico muestra lo que sucede cuando se aplica la eliminación por lista: el sesgo aumenta; El tamaño de la muestra disminuye.
establecer _ seed ( 845346 ) # Establecer seed para crear un gráfico reproducible x1 <- sort ( runif ( 50 , 0 , 100 ) ) * ( - 1 ) # Reducción del tamaño de la muestra x2 <- sort ( runif ( 50 , 0 , 100 ) ) * 0.75 - 100 # Incremento del sesgo par ( bg = "#353436" ) # Fondo negro del gráfico plot ( x1, # Tipo de reducción del tamaño de la muestra de la parcela = "l" , lwd = 3 , columna = "#1b98e0" , xlim = c ( 0 , 60 ) , ylim = c ( - 120 , 0 ) , xlab = "" , ylab = "" , xaxt = "n" , yaxt = "n" ) abline ( v = seq ( 0 , 60 , by = 5 ) , col = "steelblue4" , lty = 2 ) # Pon algunas líneas verticales en el gráfico abline ( h = seq ( - 120 , 0 , by = 10 ) , col = "steelblue4" , lty = 2 ) # Pon algunas líneas horizontales en la trama líneas ( x1, # Vuelva a trazar la reducción del tamaño de la muestra para superponer las líneas discontinuas lwd = 3 , columna = "#1b98e0" ) líneas ( x2, # Grafique el aumento en el sesgo lwd = 3 , columna = "marrón1" ) flechas ( c ( 9 , 19 , 29 , 39 , 49 ) , x1 [ c ( 9 , 19 , 29 , 39 , 49 ) ] , # Dibujar flechas para el tamaño de muestra reducido c ( 10 , 20 , 30 , 40 , 50 ) , x1 [ c ( 10 , 20 , 30 , 40, 50 ) ] , lwd = 3 , columna = "#1b98e0" ) flechas ( c ( 9 , 19 , 29 , 39 , 49 ) , x2 [ c ( 9 , 19 , 29 , 39 , 49 ) ] , # Dibujar flechas para el aumento del sesgo c ( 10 , 20 , 30 , 40 , 50 ) , x2 [ c ( 10 , 20 , 30 , 40 ,50 ) ] , lwd = 3 , col = "marrón1" ) texto ( 25.1 , - 40.3 , "Tamaño de la muestra" , cex = 2 , col = "#1b98e0" ) # Ponga algo de texto en el gráfico text ( 31.5 , - 54 , "Bias" , cex = 2 , col = "brown1" ) |
x1 <- sort(runif(50, 0, 100)) * (- 1) # Sample size reduction
x2 <- sort(runif(50, 0, 100)) * 0.75 – 100 # Bias incresement
par(bg = «#353436») # Black background of graphic
plot(x1, # Plot sample size reduction
type = «l»,
lwd = 3,
col = «#1b98e0»,
xlim = c(0, 60), ylim = c(- 120, 0),
xlab = «», ylab = «»,
xaxt = «n», yaxt = «n»)
abline(v = seq(0, 60, by = 5), col = «steelblue4», lty = 2) # Put some vertical lines on plot
abline(h = seq(- 120, 0, by = 10), col = «steelblue4», lty = 2) # Put some horizontal lines on plot
lines(x1, # Plot sample size reduction again in order to verlap the dashed lines
lwd = 3,
col = «#1b98e0»)
lines(x2, # Plot the increase in bias
lwd = 3,
col = «brown1»)
arrows(c(9, 19, 29, 39, 49), x1[c(9, 19, 29, 39, 49)], # Draw arrows for the reduced sample size
c(10, 20, 30, 40, 50), x1[c(10, 20, 30, 40, 50)],
lwd = 3, col = «#1b98e0»)
arrows(c(9, 19, 29, 39, 49), x2[c(9, 19, 29, 39, 49)], # Draw arrows for the increased bias
c(10, 20, 30, 40, 50), x2[c(10, 20, 30, 40, 50)],
lwd = 3, col = «brown1»)
text(25.1, – 40.3, «Sample Size», cex = 2, col = «#1b98e0») # Put some text on the plot
text(31.5, – 54, «Bias», cex = 2, col = «brown1»)
Alejandro Lugón es un economista y escritor especializado en Python y R, conocido por ser el creador del blog Estadisticool. Nacido en México, Lugón se graduó de la Universidad Autónoma de México con una Licenciatura en Economía. Desde entonces ha trabajado como economista en varias empresas. Lugón también ha escrito varios libros sobre temas relacionados con la economía, el análisis de datos y la programación. Su blog Estadisticool se ha convertido en un lugar de referencia para los programadores de Python y R. Alejandro Lugón es una inspiración para aquellos que buscan aprender programación y análisis de datos. Su trabajo ha ayudado a muchas personas a entender mejor el uso de la tecnología para hacer sus trabajos.