2012-05-06 11 views
22

Dado un sortkey, ¿hay un acceso directo data.table para duplicar las funcionalidades first y last encontradas en SAS y SPSS?usando data.table para marcar el primer (o último) registro en un grupo

El siguiente acercamiento peatonal marca el primer registro de un grupo.

Dada la elegancia de data.table (con el que poco a poco me estoy familiarizando), supongo que hay un atajo con una autocombinación & mult, pero todavía estoy tratando de resolverlo.

Aquí está el ejemplo:

require(data.table) 

set.seed(123) 
n <- 17 
DT <- data.table(x=sample(letters[1:3],n,replace=T), 
       y=sample(LETTERS[1:3],n,replace=T)) 
sortkey <- c("x","y") 
setkeyv(DT,sortkey) 
key <- paste(DT$x,DT$y,sep="-") 
nw <- c(T , key[2:n]!=key[1:(n-1)]) 
DT$first <- 1*nw 
DT 
+0

buenas respuestas aquí, incluyendo un conjunto de datos. tabla de solución: http://stats.stackexchange.com/questions/7884/fast-ways-in-r-to-get-the-first-row-of-a-data-frame-grouped-by-an-identifier/7889 # 7889 – Chase

+0

Creo que el M.Dimo específicamente quiere * etiquetar * el primero y el último en el grupo en lugar de * extraer * ellos. El enlace que apuntó, así como el enfoque 'mult 'al que se refiere el OP, muestran cómo * extraer *, no * etiqueta *. –

Respuesta

21

Éstos son par de soluciones utilizando data.table:

## Option 1 (cleaner solution, added 2016-11-29) 
uDT <- unique(DT) 
DT[, c("first","last"):=0L] 
DT[uDT, first:=1L, mult="first"] 
DT[uDT, last:=1L, mult="last"] 


## Option 2 (original answer, retained for posterity) 
DT <- cbind(DT, first=0L, last=0L) 
DT[DT[unique(DT),,mult="first", which=TRUE], first:=1L] 
DT[DT[unique(DT),,mult="last", which=TRUE], last:=1L] 

head(DT) 
#  x y first last 
# [1,] a A  1 1 
# [2,] a B  1 1 
# [3,] a C  1 0 
# [4,] a C  0 1 
# [5,] b A  1 1 
# [6,] b B  1 1 

Obviamente hay una gran cantidad empaquetada en cada una de esas líneas. El constructo clave, sin embargo, es el siguiente, que devuelve el índice de la fila del primer registro en cada grupo:

DT[unique(DT),,mult="first", which=TRUE] 
# [1] 1 2 3 5 6 7 11 13 15 
+0

Gracias por su respuesta. Tuve la sensación de que esto era posible usando la combinación & "primero", pero no pude encontrar la sintaxis correcta. Ahí está, claramente explicado. Gracias de nuevo. –

+0

+1 es bueno saber sobre el argumento 'which' –

+0

Gracias a los dos. En la práctica, probablemente usaría algo como el enfoque de @PrasadChalasani. Pero pensé que esta era una buena demostración de un montón de características de 'data.table' y esperaba que otras lo encontraran útil. También me interesará aprender (a) si hay una mejor solución de datos para esto, y (b) si hay una forma mejor que 'única (DT)' de extraer todas las combinaciones de teclas únicas en 'data.table '. –

8

Una forma fácil es usar la función duplicated(). Cuando se aplica a un marco de datos, produce un vector donde una entrada es VERDADERA si y solo si la combinación de valores de fila no ha ocurrido antes, cuando se mueve hacia abajo del marco de datos.

DT$first <- !duplicated(DT[, list(x,y) ])                                                          
DT$last <- rev(!duplicated(DT[, list(rev(x),rev(y)) ]))                                                      

> DT                                                                   
     x y first last                                                               
    [1,] a A TRUE TRUE                                                               
    [2,] a B TRUE TRUE                                                               
    [3,] a C TRUE FALSE                                                               
    [4,] a C FALSE TRUE                                                               
    [5,] b A TRUE TRUE                                                               
    [6,] b B TRUE TRUE                                                               
    [7,] b C TRUE FALSE                                                               
    [8,] b C FALSE FALSE                                                               
    [9,] b C FALSE FALSE                                                               
[10,] b C FALSE TRUE                                                               
[11,] c A TRUE FALSE                                                               
[12,] c A FALSE TRUE                                                               
[13,] c B TRUE FALSE                                                               
[14,] c B FALSE TRUE                                                               
[15,] c C TRUE FALSE                                                               
[16,] c C FALSE FALSE                                                               
[17,] c C FALSE TRUE    

Otra forma sin usar duplicated() es:

DT[ unique(DT), list(first = c(1, rep(0,length(y)-1)),                                                       
        last = c(rep(0,length(y)-1),1)) ]  

     x y first last                                                             
    [1,] a A  1 1                                                               
    [2,] a B  1 1                                                               
    [3,] a C  1 0                                                               
    [4,] a C  0 1                                                               
    [5,] b A  1 1                                                               
    [6,] b B  1 1                                                               
    [7,] b C  1 0                                                               
    [8,] b C  0 0                                                               
    [9,] b C  0 0                                                               
[10,] b C  0 1                                                               
[11,] c A  1 0                                                               
[12,] c A  0 1                                                               
[13,] c B  1 0                                                               
[14,] c B  0 1                                                               
[15,] c C  1 0                                                               
[16,] c C  0 0                                                               
[17,] c C  0 1   
+0

¡Gracias! Todavía me pregunto acerca de una solución de datos, pero la elegancia definitivamente califica en este caso. –

+0

De nada ... Acabo de agregar otra forma de hacerlo. La función 'mult' a la que se refiere es solo para elegir la primera o la última (o todas) las coincidencias cuando hay múltiples coincidencias con el argumento' i' en 'DT [i, j, mult = ...]' –

1

Una forma más simple que Josh puede ser

unique(DT) 
unique(DT,fromLast=TRUE] 
Cuestiones relacionadas