Missing Values (NA) in R. En la siguiente entrada se
muestran algunas operaciones básicas para la identificación y tratamiento de
valores perdidos en R. Dado el siguiente vector de valores, se verifica que los
valores NA son utilizados en R para señalar valore
perdidos:
x<-c(24, 14, 17, 25, 12, NA, 11, NA)
Aunque en este ejemplo es fácil
de identificar donde se encuentran los NA, en la mayoría de los casos prácticos
el volumen de datos no permitirá se identifique
con facilidad la presencia de algún valor perdido en el vector de datos.
Sin embargo, en R la función is.na permite obtener un vector lógico con TRUE en
los casos de valores perdidos. Al anidar la función any con la función
is.na se verifica si un vector determinado tiene algún valor perdido, la función
which permite identificar la posición de estos valores, mean el porcentaje de NA y sum la cantidad de NA:
> is.na(x) # Vector lógico con T==NA
[1] FALSE FALSE FALSE FALSE FALSE TRUE FALSE TRUE
> any(is.na(x)) # TRUE = hay al menos un valor NA
[1] TRUE
> anyNA(x) # Alternativa a lo
anterior
[1] TRUE
> which(is.na(x)) # Indica las coordenadas donde están los NA
[1] 6 8
> mean(is.na(x)) # Porcentaje de valores NA
[1] 0.25
> sum(is.na(x)) # Cantidad de valores perdidos en
el vector
[1] 2
R, también permite omitir
los valores perdidos de un vector de datos usando las funciones na.omit y na.exlude:
> na.omit(x)
[1] 24 14 17 25 12 11
attr(,"na.action")
[1] 6 8
attr(,"class")
[1] "omit"
> na.exclude(x)
[1] 24 14 17 25 12 11
attr(,"na.action")
[1] 6 8
attr(,"class")
[1] "exclude"
Adicionalmente, podemos omitir valores NA de un vector mediante indexación
lógica:
> x[!is.na(x)]
[1] 24 14 17 25 12 11
> all(na.omit(x) == x[!is.na(x)])
[1] TRUE
La función na.fail imprime un error en caso de encontrar
valores perdidos, esta es usada como mensaje de advertencia en caso de
condicionales o estructuras como las funciones:
> na.fail(x)
Error in na.fail.default(x) : missing values in object
Note que en caso de no existir valores NA, no se imprime el
mensaje:
> na.fail(na.omit(x))
[1] 24 14 17 25 12 11
attr(,"na.action")
[1] 6 8
attr(,"class")
[1] "omit"
Otra forma de contabilizar valores NA es mediante la
función table, esta nos permite obtener una tabla de frecuencia de
nuestros datos:
y <-c(1, 0, 1, 1, 1, 0, NA, 0)
> table(y)
y
0 1
3 4
> table(y, useNA =
"always")
y
0 1 <NA>
3 4 1
En el caso de bases datos, que
son más frecuente que los vectores, podemos también identificar valores NA. Las
siguientes líneas de códigos insertan una base de datos llamada data, con los
vectores creados anteriormente.
> data <- data.frame(mujer=y, edad=x)
> data
mujer edad
1 1 24
2 0 14
3 1 17
4 1 25
5 1 12
6 0 NA
7 NA 11
8 0 NA
Mediante la función vectorizada
apply, podemos obtener, por columna o variable, la cantidad, el porcentaje o la
ubicación de los valores lógicos de nuestra base de datos. Esto se logra
anidando esta función apply con la función is.na vista anteriormente. Verifique
que si cambiamos el 2 por el 1, repite el ejercicio anterior para cada una de
las observaciones.
> apply(is.na(data), 2, mean) # Porcentaje de NA por columna
mujer edad
0.125 0.250
> apply(is.na(data), 2, sum) # Cantidad de NA por columna
mujer edad
1 2
>
apply(is.na(data), 2, which) # Posición
de NA por
columna
$mujer
[1] 7
$edad
[1] 6 8
Esta posición se puede
verificar de forma directa para cada variable (columna):
> which(is.na(data[ , 2]))
[1] 6 8
Ahora bien, si queremos ambos
operadores (seguro si buscamos en internet hay alguna forma más bonita de
logarlos, en este caso, lo que hacemos para que la función apply me aplique dos
funciones, es crear una nueva función que haga las dos tareas a la vez):
nerysF <-function(x) {
a<-mean(x);
b<-sum(x)
return(c(a,b))
}
> apply(is.na(data), 2,
nerysF)
mujer edad peso
[1,] 0.125 0.25 0
[2,] 1.000 2.00 0
Agreguemos la variable peso a
nuestra base de datos, la cual, de manera intencional no contiene valores NA:
data$peso <- c(110, 150, 180, 125, 121, 121, 111, 150)
Identificar variables (columnas)
con al menos 1 NA en mi base de datos:
La función apply, usando como argumento
la función sum, nos permite verificar
cuales variables tienen al menos un valor NA. Como ejemplo, creamos un
vector lógico llamado VARna=TRUE en los casos donde la columna tenga al menos
un valor NA. Posteriormente usamos la indexación lógica para acceder a los nombres
de las columnas identificadas:
VARna <-
apply(is.na(data), 2, sum)>=1
> VARna
mujer edad peso
TRUE TRUE FALSE
> VARna[VARna==TRUE]
mujer edad
TRUE TRUE
La función complete.case permite
obtener la cantidad de observaciones de
la data, donde ninguna observación contiene observaciones perdidas. En tal
caso, se utiliza el vector lógico complete.cases(data) para poder indexar la
data, para poder acceder a estas observaciones, donde ninguna de las variables
cumplen con ser NA.
> complete.cases(data)
[1] TRUE TRUE TRUE TRUE TRUE FALSE
FALSE FALSE
> data[complete.cases(data), ]
mujer edad peso
1 1 24 110
2 0 14 150
3 1 17 180
4 1 25 125
5 1 12 121
De forma más directa, na.omit permite
realizar esta tarea directamente:
> na.omit(data)
mujer edad peso
1 1 24 110
2 0 14 150
3 1 17 180
4 1 25 125
5 1 12 121
Adicionalmente, mediante el operador
de negación (!) podemos acceder a las
observaciones donde alguna de las variables tiene un valor NA.
> data[!complete.cases(data), ]
mujer edad peso
6 0 NA 121
7 NA 11 111
8 0 NA 150
Cuando utilizamos funciones
también debemos de tener presente la presencia de valores NA en nuestros datos,
debajo se colocan algunos ejemplos de cómo puede condicionarse el resultado a
considerar o no los valores NA:
# NA en funciones y operaciones
# Media
> mean(x)
[1] NA
> mean(na.omit(x))
[1] 17.16667
> mean(x,
na.rm = TRUE)
[1] 17.16667
#Ordenar datos
> sort(x)
[1] 11 12 14 17 24 25
> sort(x, na.last = TRUE)
[1] 11 12 14 17 24 25 NA NA
# Modelos de
regresión
model0 <-
lm(y ~ x, data = data)
model1 <-
lm(y ~ x, data = data, na.action = na.exclude)
model2 <-
lm(y ~ x, data = data, na.action = na.omit)
> resid(model0)
>
resid(model1)
> resid(model2)
#Operaciones
data$edad^2
# NA^2 = NA,
data$edad+1
# NA+1=NA
Finalmente, podemos recodificar
nuestros valores NA. insertando el promedio de nuestro vector en cada una de
las observaciones con valores perdidos (Una mala idea). La librería tree
permite hacer imputaciones sobre un conjunto mayor de valores.
> x2<-x
>
x2[is.na(x)] <- mean(x, na.rm = TRUE)
>
>
cbind(x,x2)
x
x2
[1,] 24
24.00000
[2,] 14
14.00000
[3,] 17
17.00000
[4,] 25
25.00000
[5,] 12
12.00000
[6,] NA
17.16667
[7,] 11
11.00000
[8,] NA
17.16667
Referencias
-
Dhana, Klodian (2015). How to Deal with
Missing Values in R. Consult: 8/9/2019. Disponible: https://datascienceplus.com/missing-values-in-r/.
-
Kabacoff, R. (2017). Missing Data.
Quick-R. Consult: 8/9/2019. Disponible: https://www.statmethods.net/input/missingdata.html
-
UCLA (2012). How does R handle missing
values?. Institute for Digital Research and Education. Consult: 8/9/2019. Disponible: https://stats.idre.ucla.edu/r/faq/how-does-r-handle-missing-values/.
-
Naval Postgraduate School. Missing Values
in R. Consult: 8/9/2019. Disponible:
https://faculty.nps.edu/sebuttre/home/R/missings.html.
-
Statistics Globe (nd). R Find Missing
Values (6 Examples for Data Frame, Column & Vector). Consult: 8/9/2019. Disponible: https://statisticsglobe.com/r-find-missing-values/.