5.8: Manejo de Valores Faltantes
- Page ID
- 151508
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)Hay un último tema que quiero discutir brevemente en este capítulo, y ese es el tema de la falta de datos. Los conjuntos de datos reales con mucha frecuencia resultan tener valores faltantes: tal vez alguien olvidó rellenar una pregunta de encuesta en particular, por ejemplo. Los datos faltantes pueden ser la fuente de muchos problemas complicados, la mayoría de los cuales voy a pasar por alto. Sin embargo, como mínimo, es necesario comprender los conceptos básicos del manejo de datos faltantes en R.
caso de variable única
Empecemos por el caso más simple, en el que estás tratando de calcular estadísticas descriptivas para una sola variable a la que le faltan datos. En R, esto significa que habrá valores de NA
en su vector de datos. Vamos a crear una variable así:
> partial <- c(10, 20, NA, 30)
Supongamos que quieres calcular la media de esta variable. Por defecto, R asume que quieres calcular la media usando los cuatro elementos de este vector, que probablemente sea lo más seguro para un autómata tonto, pero rara vez es lo que realmente quieres. ¿Por qué no? Bueno, recuerda que la interpretación básica de NA
es “no sé qué es este número”. Esto significa que 1 + NA = NA
: si agrego 1 a algún número que no conozco (es decir, el NA
) entonces la respuesta también es un número que no conozco. Como consecuencia, si no le dice explícitamente a R que ignore los valores NA
, y el conjunto de datos tiene valores faltantes, entonces la salida en sí misma será un valor faltante. Si trato de calcular la media del vector parcial
, sin hacer nada sobre el valor faltante, esto es lo que sucede:
> mean( x = partial )
[1] NA
Técnicamente correcto, pero profundamente inservible.
Para solucionar esto, todas las funciones de estadística descriptiva que he discutido en este capítulo (con la excepción de cor ()
que es un caso especial que discutiré a continuación) tienen un argumento opcional llamado na.rm
, que es la taquigrafía de “eliminar valores NA”. Por defecto, na.rm = FALSO
, entonces R no hace nada sobre el problema de datos faltantes. Intentemos establecer na.rm = VERDADERO
y veamos qué sucede:
Al calcular sumas y medias cuando faltan datos presentes (es decir, cuando hay valores NA
) en realidad hay un argumento adicional a la función que debe conocer. Este argumento se llama na.rm
, y es un valor lógico que indica si R debe ignorar (o “eliminar”) los datos faltantes para los fines de hacer los cálculos. Por defecto, R asume que quieres conservar los valores faltantes, así que a menos que digas lo contrario establecerá na.rm = FALSO
. No obstante, R supone que 1 + NA = NA
: si agrego 1 a algún número que no conozco (es decir, el NA
) entonces la respuesta es también un número que no conozco. Como consecuencia, si no le dice explícitamente a R que ignore los valores NA
, y el conjunto de datos tiene valores faltantes, entonces la salida en sí misma será un valor faltante. Esto se ilustra en el siguiente extracto:
> mean( x = partial, na.rm = TRUE )
[1] 20
Observe que la media es 20
(es decir, 60/3
) y no 15
. Cuando R ignora un valor de NA
, realmente lo ignora. En efecto, el cálculo anterior es idéntico al que obtendrías si pidieras la media del vector de tres elementos c (10, 20, 30)
.
Como se indicó anteriormente, esto no es exclusivo de la función mean ()
. Prácticamente todas las otras funciones de las que he hablado en este capítulo tienen un argumento na.rm
que indica si debe ignorar los valores faltantes. No obstante, su comportamiento es el mismo para todas estas funciones, así que no voy a perder el tiempo a todos demostrándolo por separado para cada una.
Valores faltantes en cálculos por pares
Mencioné anteriormente que la función cor ()
es un caso especial. No tiene un argumento na.rm
, porque la historia se vuelve mucho más complicada cuando hay más de una variable involucrada. Lo que sí tiene es un argumento llamado uso
que hace aproximadamente lo mismo, pero hay que pensar un poco más detenidamente en lo que quiere esta vez. Para ilustrar los problemas, vamos a abrir un conjunto de datos que tiene valores faltantes, Parenthood2.rData
. Este archivo contiene los mismos datos que los datos originales de paternidad, pero con algunos valores eliminados. Contiene un solo marco de datos, paréntesis 2
:
> load( "parenthood2.Rdata" )
> print( parenthood2 )
dan.sleep baby.sleep dan.grump day
1 7.59 NA 56 1
2 7.91 11.66 60 2
3 5.14 7.92 82 3
4 7.71 9.61 55 4
5 6.68 9.75 NA 5
6 5.99 5.04 72 6
BLAH BLAH BLAH
Si calculo mis estadísticas descriptivas usando la función describe ()
> describe( parenthood2 )
var n mean sd median trimmed mad min max BLAH
dan.sleep 1 91 6.98 1.02 7.03 7.02 1.13 4.84 9.00 BLAH
baby.sleep 2 89 8.11 2.05 8.20 8.13 2.28 3.25 12.07 BLAH
dan.grump 3 92 63.15 9.85 61.00 62.66 10.38 41.00 89.00 BLAH
day 4 100 50.50 29.01 50.50 50.50 37.06 1.00 100.00 BLAH
podemos ver en la columna n
que faltan 9 valores para dan.sleep
, 11 valores faltantes para baby.sleep
y 8 valores faltantes para dan.grump
. 84 Supongamos que lo que me gustaría es una matriz de correlación. Y supongamos también que no me molesto en decirle a R cómo manejar esos valores faltantes. Esto es lo que sucede:
> cor( parenthood2 )
dan.sleep baby.sleep dan.grump day
dan.sleep 1 NA NA NA
baby.sleep NA 1 NA NA
dan.grump NA NA 1 NA
day NA NA NA 1
Molesto, pero tiene sentido. Si no sé cuáles son realmente algunos de los valores de dan.sleep
y baby.sleep
, entonces tampoco puedo saber cuál es la correlación entre estas dos variables, ya que la fórmula para el coeficiente de correlación hace uso de cada observación en el conjunto de datos. Una vez más, tiene sentido: simplemente no es particularmente útil.
Para que R se comporte de manera más sensata en esta situación, es necesario especificar el argumento use
a la función cor ()
. Hay varios valores diferentes que puedes especificar para esto, pero los dos que más nos importan en la práctica tienden a ser “complete.obs”
y “pairwise.complete.obs”
. Si especificamos use = “complete.obs”
, R ignorará por completo todos los casos (es decir, todas las filas en nuestro marco de datos entre paréntesis 2
) que tengan valores faltantes en absoluto. Entonces, por ejemplo, si miras hacia atrás en el extracto antes cuando usé la función head ()
, observe que a la observación 1 (es decir, el día 1) del conjunto de datos entre paréntesis 2
le falta el valor para baby.sleep
, pero ¿por lo demás está completo? Bueno, si eliges use = “complete.obs”
R ignorará esa fila por completo: es decir, incluso cuando está tratando de calcular la correlación entre dan.sleep
y dan.grump
, la observación 1 será ignorada, porque el valor de baby.sleep
falta para eso observación. Esto es lo que obtenemos:
> cor(parenthood2, use = "complete.obs")
dan.sleep baby.sleep dan.grump day
dan.sleep 1.00000000 0.6394985 -0.89951468 0.06132891
baby.sleep 0.63949845 1.0000000 -0.58656066 0.14555814
dan.grump -0.89951468 -0.5865607 1.00000000 -0.06816586
day 0.06132891 0.1455581 -0.06816586 1.00000000
La otra posibilidad que nos importa, y la que tiende a acostumbrarse más a menudo en la práctica, es establecer use = “pairwise.complete.obs”
. Cuando hacemos eso, R solo mira las variables que está tratando de correlacionar a la hora de determinar qué dejar caer. Entonces, por ejemplo, ya que el único valor que falta para la observación 1 de paréntesis 2
es para baby.sleep
R solo dejará caer la observación 1 cuando baby.sleep
es una de las variables involucradas: y así R mantiene la observación 1 cuando intenta correlacionar dan.sleep
y dan.gruñón
. Cuando lo hacemos de esta manera, esto es lo que obtenemos:
> cor(parenthood2, use = "pairwise.complete.obs")
dan.sleep baby.sleep dan.grump day
dan.sleep 1.00000000 0.61472303 -0.903442442 -0.076796665
baby.sleep 0.61472303 1.00000000 -0.567802669 0.058309485
dan.grump -0.90344244 -0.56780267 1.000000000 0.005833399
day -0.07679667 0.05830949 0.005833399 1.000000000
Similar, pero no exactamente lo mismo. También vale la pena señalar que la función correlate ()
(en el paquete lsr
) usa automáticamente el método “pairwise complete”:
> correlate(parenthood2)
CORRELATIONS
============
- correlation type: pearson
- correlations shown only when both variables are numeric
dan.sleep baby.sleep dan.grump day
dan.sleep . 0.615 -0.903 -0.077
baby.sleep 0.615 . -0.568 0.058
dan.grump -0.903 -0.568 . 0.006
day -0.077 0.058 0.006 .
Los dos enfoques tienen diferentes fortalezas y debilidades. El enfoque “por pares completos” tiene la ventaja de que mantiene más observaciones, por lo que está haciendo uso de más datos y (como discutiremos con tedioso detalle en el Capítulo 10 y mejora la confiabilidad de su correlación estimada. Por otro lado, significa que cada correlación en tu matriz de correlación se está calculando a partir de un conjunto ligeramente diferente de observaciones, lo que puede ser incómodo cuando quieres comparar las diferentes correlaciones que tienes.
Entonces, ¿qué método deberías usar? Depende mucho de por qué crees que faltan tus valores, y probablemente depende un poco de lo paranoico que estés. Por ejemplo, si crees que los valores faltantes fueron “elegidos” completamente al azar 85 entonces probablemente querrás usar el método por pares. Si crees que los datos faltantes son una señal para pensar que toda la observación podría ser basura (por ejemplo, alguien simplemente seleccionando respuestas arbitrarias en tu cuestionario), pero que no hay un patrón al que las observaciones sean “basura” entonces probablemente sea más seguro guardar solo aquellas observaciones que estén completas. Si crees que está pasando algo sistemático, en que es más probable que falten algunas observaciones que otras, entonces tienes un problema mucho más complicado que resolver, y uno que está más allá del alcance de este libro.