perdidos - reemplazar NA en una cadena dplyr
reemplazar na en r (1)
El problema principal que tienes es que la mean
devuelve un doble, mientras que la columna G_batting
es un número entero. Así que envolver la media en as.integer
funcionaría, o tendrías que convertir toda la columna en numeric
, supongo.
Dicho esto, aquí hay un par de alternativas de datos. No data.table
cuál es más rápido.
library(data.table)
# using ifelse
dt = data.table(a = 1:2, b = c(1,2,NA,NA,3,4,5,6,7,8))
dt[, b := ifelse(is.na(b), mean(b, na.rm = T), b), by = a]
# using a temporary column
dt = data.table(a = 1:2, b = c(1,2,NA,NA,3,4,5,6,7,8))
dt[, b.mean := mean(b, na.rm = T), by = a][is.na(b), b := b.mean][, b.mean := NULL]
Y esto es lo que me gustaría hacer idealmente ( hay un FR sobre esto):
# again, atm this is pure fantasy and will not work
dt[, b[is.na(b)] := mean(b, na.rm = T), by = a]
La versión dplyr
de ifelse
es (como en OP):
dt %>% group_by(a) %>% mutate(b = ifelse(is.na(b), mean(b, na.rm = T), b))
No estoy seguro de cómo implementar la segunda idea de data.table
en una sola línea en dplyr
. Tampoco estoy seguro de cómo puede evitar que dplyr
codificar / ordenar los datos (además de crear una columna de índice).
La pregunta ha sido editada desde el original .
Después de leer esta interesante discussion me preguntaba cómo reemplazar las NA en una columna usando dplyr en, por ejemplo, los datos de bateo de Lahman:
Source: local data frame [96,600 x 3]
Groups: teamID
yearID teamID G_batting
1 2004 SFN 11
2 2006 CHN 43
3 2007 CHA 2
4 2008 BOS 5
5 2009 SEA 3
6 2010 SEA 4
7 2012 NYA NA
Lo siguiente no funciona como esperaba
library(dplyr)
library(Lahman)
df <- Batting[ c("yearID", "teamID", "G_batting") ]
df <- group_by(df, teamID )
df$G_batting[is.na(df$G_batting)] <- mean(df$G_batting, na.rm = TRUE)
Fuente: marco de datos local [20 x 3] Grupos: ID de año, ID de equipo
yearID teamID G_batting
1 2004 SFN 11.00000
2 2006 CHN 43.00000
3 2007 CHA 2.00000
4 2008 BOS 5.00000
5 2009 SEA 3.00000
6 2010 SEA 4.00000
7 2012 NYA **49.07894**
> mean(Batting$G_battin, na.rm = TRUE)
[1] **49.07894**
De hecho, imputa la media general y no la media del grupo. ¿Cómo harías esto en una cadena dplyr? Usar la transform
de la base R tampoco funciona, ya que imputa la media general y no la media del grupo. También este enfoque convierte los datos a un dat regular. un cuadro. ¿Hay una mejor manera de hacer esto?
df %.%
group_by( yearID ) %.%
transform(G_batting = ifelse(is.na(G_batting),
mean(G_batting, na.rm = TRUE),
G_batting)
)
Editar: Reemplazar la transform
con mutate
da el siguiente error
Error in mutate_impl(.data, named_dots(...), environment()) :
INTEGER() can only be applied to a ''integer'', not a ''double''
Editar: Agregar as.integer parece resolver el error y produce el resultado esperado. Ver también la respuesta de @ eddi.
df %.%
group_by( teamID ) %.%
mutate(G_batting = ifelse(is.na(G_batting), as.integer(mean(G_batting, na.rm = TRUE)), G_batting))
Source: local data frame [96,600 x 3]
Groups: teamID
yearID teamID G_batting
1 2004 SFN 11
2 2006 CHN 43
3 2007 CHA 2
4 2008 BOS 5
5 2009 SEA 3
6 2010 SEA 4
7 2012 NYA 47
> mean_NYA <- mean(filter(df, teamID == "NYA")$G_batting, na.rm = TRUE)
> as.integer(mean_NYA)
[1] 47
Editar: Siguiendo con el comentario de @ Romain, instalé dplyr desde github:
> head(df,10)
yearID teamID G_batting
1 2004 SFN 11
2 2006 CHN 43
3 2007 CHA 2
4 2008 BOS 5
5 2009 SEA 3
6 2010 SEA 4
7 2012 NYA NA
8 1954 ML1 122
9 1955 ML1 153
10 1956 ML1 153
> df %.%
+ group_by(teamID) %.%
+ mutate(G_batting = ifelse(is.na(G_batting), mean(G_batting, na.rm = TRUE), G_batting))
Source: local data frame [96,600 x 3]
Groups: teamID
yearID teamID G_batting
1 2004 SFN 0
2 2006 CHN 0
3 2007 CHA 0
4 2008 BOS 0
5 2009 SEA 0
6 2010 SEA 1074266112
7 2012 NYA 90693125
8 1954 ML1 122
9 1955 ML1 153
10 1956 ML1 153
.. ... ... ...
Así que no obtuve el error (bien) pero obtuve un resultado (aparentemente) extraño.