Elimine el grupo del data.frame si al menos un miembro del grupo cumple la condición
Tengo un data.frame
problema en el que me gustaría eliminar grupos completos si alguno de sus miembros cumple una condición.
En este primer ejemplo, si los valores son números y la condición es, NA
el siguiente código funciona.
df <- structure(list(world = c(1, 2, 3, 3, 2, NA, 1, 2, 3, 2), place = c(1,
1, 2, 2, 3, 3, 1, 2, 3, 1), group = c(1, 1, 1, 2, 2, 2, 3,
3, 3, 3)), .Names = c("world", "place", "group"), row.names = c(NA,
-10L), class = "data.frame")
ans <- ddply(df, . (group), summarize, code=mean(world))
ans$code[is.na(ans$code)] <- 0
ans2 <- merge(df,ans)
final.ans <- ans2[ans2$code !=0,]
Sin embargo, esta ddply
maniobra con los NA
valores no funcionará si la condición es distinta a " NA
", o si el valor no es numérico.
Por ejemplo, si quisiera eliminar grupos que tienen una o más filas con un valor mundial de AF
(como en el marco de datos a continuación), este ddply
truco no funcionaría.
df2 <-structure(list(world = structure(c(1L, 2L, 3L, 3L, 3L, 5L, 1L,
4L, 2L, 4L), .Label = c("AB", "AC", "AD", "AE", "AF"), class = "factor"),
place = c(1, 1, 2, 2, 3, 3, 1, 2, 3, 1), group = c(1,
1, 1, 2, 2, 2, 3, 3, 3, 3)), .Names = c("world", "place",
"group"), row.names = c(NA, -10L), class = "data.frame")
Puedo imaginar un bucle for en el que para cada grupo se verifica el valor de cada miembro y, si se cumple la condición code
, se podría completar una columna y luego se podría crear un subconjunto basado en ese código.
Pero, ¿quizás haya una forma vectorizada de hacer esto?
Intentar
library(dplyr)
df2 %>%
group_by(group) %>%
filter(!any(world == "AF"))
O según lo mencionado por @akrun:
setDT(df2)[, if(!any(world == "AF")) .SD, group]
O
setDT(df2)[, if(all(world != "AF")) .SD, group]
Lo que da:
#Source: local data frame [7 x 3]
#Groups: group
#
# world place group
#1 AB 1 1
#2 AC 1 1
#3 AD 2 1
#4 AB 1 3
#5 AE 2 3
#6 AC 3 3
#7 AE 1 3
Solución alternativa de tabla de datos :
setDT(df2)
df2[!(group %in% df2[world == "AF",group])]
da:
world place group
1: AB 1 1
2: AC 1 1
3: AD 2 1
4: AB 1 3
5: AE 2 3
6: AC 3 3
7: AE 1 3
Usando claves podemos ser un poco más rápidos:
setkey(df2,group)
df2[!J((df2[world == "AF",group]))]
paquete básico :
df2[ df2$group != df2[ df2$world == 'AF', "group" ], ]
Producción:
world place group
1 AB 1 1
2 AC 1 1
3 AD 2 1
7 AB 1 3
8 AE 2 3
9 AC 3 3
10 AE 1 3
Usando sqldf
:
library(sqldf)
sqldf("SELECT df2.world, df2.place, [group] FROM df2
LEFT JOIN
(SELECT * FROM df2 WHERE world LIKE 'AF') AS t
USING([group])
WHERE t.world IS NULL")
Producción:
world place group
1 AB 1 1
2 AC 1 1
3 AD 2 1
4 AB 1 3
5 AE 2 3
6 AC 3 3
7 AE 1 3