r data.table

seleccione una fila por grupo con ifelse en data.table



(3)

Creo que es un buen caso de uso para ambos match y es nomatch argumento nomatch

d[, .SD[match(1L, x, nomatch = 1L)], by = a] # a x y # 1: 1 1 2 # 2: 2 0 1 # 3: 3 1 1

Esto es básicamente, en caso de que no coincida, devuelve 1 , y como resultado le da la primera fila en el grupo. Si hay una coincidencia múltiple, devolverá la primera, según su deseo

Estoy agrupando una tabla de datos y quiero seleccionar de cada grupo la primera fila donde x == 1 o, si tal fila no existe, entonces la primera fila con cualquier valor en x

d <- data.table( a = c(1,1,1, 2,2, 3,3), x = c(0,1,0, 0,0, 1,1), y = c(1,2,3, 1,2, 1,2) )

este intento

d[, ifelse(any(.SD[,x] == 1),.SD[x == 1][1], .SD[1]), by = a]

devoluciones

a V1 1: 1 1 2: 2 0 3: 3 1

pero esperaba

a x y 1: 1 1 2 2: 2 0 1 3: 3 1 1

¿Alguna idea de cómo hacerlo bien?


Otra opción ( which.max está básicamente diseñada para hacer exactamente lo que quieres):

d[, .SD[which.max(x == 1)], by = a] # a x y #1: 1 1 2 #2: 2 0 1 #3: 3 1 1


También podemos hacer esto con .I para devolver el índice de la fila y usarlo para subcontratar las filas.

d[d[, .I[which.max(x==1)], by = a]$V1] # a x y #1: 1 1 2 #2: 2 0 1 #3: 3 1 1

En las versiones actuales de data.table , el enfoque de .I es más eficiente en comparación con el .SD para subordenar filas (sin embargo, podría cambiar en el futuro). Esta es también una publicación similar.

Aquí hay otra opción con order (también se puede usar setkey - por eficiencia) el conjunto de datos por ''a'' y ''x'' después de agrupar por ''a'', y luego obtener la primera fila con head

d[order(a ,-x), head(.SD, 1) ,by = a] # a x y #1: 1 1 2 #2: 2 0 1 #3: 3 1 1

Puntos de referencia

Inicialmente, estábamos pensando en la evaluación comparativa en> 1e6, pero los métodos .SD están tomando tiempo, por lo que se comparan en 3e5 filas usando data.table_1.9.7

set.seed(24) d1 <- data.table(a = rep(1:1e5, 3), x = sample(0:1, 1e5*3, replace=TRUE), y = rnorm(1e5*3)) system.time(d1[, .SD[which.max(x == 1)], by = a]) # user system elapsed # 56.21 30.64 86.42 system.time(d1[, .SD[match(1L, x, nomatch = 1L)], by = a]) # user system elapsed # 55.27 30.07 83.75 system.time(d1[d1[, .I[which.max(x==1)], by = a]$V1]) # user system elapsed # 0.19 0.00 0.19 system.time(d1[order(a ,-x), head(.SD, 1) ,by = a]) # user system elapsed # 0.03 0.00 0.04