Usando listas dentro de columnas data.table

En data.table es posible tener columnas de tipo list y estoy intentando por primera vez beneficiarme de esta característica. Necesito almacenar para cada fila de mi tabla varios comentarios tomados de un servicio web de rApache. Cada comentario tendrá un nombre de usuario, fecha y elemento del cuerpo.

En lugar de usar cadenas largas con algún personaje raro e inusual para separar cada mensaje de los demás (como | ), y a ; para separar cada elemento en un comentario, pensé usar listas como esta:

 library(data.table) dt  dt id comment 1: 1  2: 2  

para almacenar todos los comentarios agregados para una fila en particular. (también porque será más fácil convertir a JSON más tarde cuando necesite enviarlo a la IU)

Sin embargo, cuando trato de simular cómo estaré realmente llenando mi tabla durante la producción (agregando un solo comentario a una fila en particular), R bloquea o no asigna lo que me gustaría y luego falla:

 library(data.table) > library(data.table) > dt  dt$comment [[1]] NULL [[2]] NULL > dt[1L, comment := 1] # this works > dt$comment [[1]] [1] 1 [[2]] NULL > set(dt, 1L, "comment", list(1, "a")) # assign only `1` and when I try to see `dt` R crashes Warning message: In set(dt, 1L, "comment", list(1, "a")) : Supplied 2 items to be assigned to 1 items of column 'comment' (1 unused) > dt[1L, comment := list(1, "a")] # R crashes as soon as I run > dt[1L, comment := list(list(1, "a"))] # any of these two 

Sé que estoy tratando de hacer un mal uso de data.table , por ejemplo, la forma en que se ha diseñado el argumento j permite esto:

 dt[1L, c("id", "comment") := list(1, "a")] # lists in RHS are seen as different columns! not parts of one 

Pregunta: Entonces, ¿hay alguna manera de hacer la tarea que quiero? ¿O simplemente tengo que quitar dt$comment en una variable, modificarla y luego reasignar toda la columna cada vez que necesito hacer una actualización?

Usando := :

 dt = data.table(id = 1:2, comment = vector("list", 2L)) # assign value 1 to just the first column of 'comment' dt[1L, comment := 1L] # assign value of 1 and "a" to rows 1 and 2 dt[, comment := list(1, "a")] # assign value of "a","b" to row 1, and 1 to row 2 for 'comment' dt[, comment := list(c("a", "b"), 1)] # assign list(1, "a") to just 1 row of 'comment' dt[1L, comment := list(list(list(1, "a")))] 

Para el último caso, necesitará una list más porque data.table usa list(.) Para buscar valores para asignar a columnas por referencia.

Usando el set :

 dt = data.table(id = 1:2, comment = vector("list", 2L)) # assign value 1 to just the first column of 'comment' set(dt, i=1L, j="comment", value=1L) # assign value of 1 and "a" to rows 1 and 2 set(dt, j="comment", value=list(1, "a")) # assign value of "a","b" to row 1, and 1 to row 2 for 'comment' set(dt, j="comment", value=list(c("a", "b"), 1)) # assign list(1, "a") to just 1 row of 'comment' set(dt, i=1L, j="comment", value=list(list(list(1, "a")))) 

HTH


Estoy usando la versión de desarrollo actual 1.9.3, pero debería funcionar bien en cualquier otra versión.

 > sessionInfo() R version 3.0.3 (2014-03-06) Platform: x86_64-apple-darwin10.8.0 (64-bit) locale: [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 attached base packages: [1] stats graphics grDevices utils datasets methods base other attached packages: [1] data.table_1.9.3 loaded via a namespace (and not attached): [1] plyr_1.8.0.99 reshape2_1.2.2 stringr_0.6.2 tools_3.0.3 

Solo para agregar más información, para qué están realmente diseñadas las columnas de la list es cuando cada celda es en sí misma un vector :

 > DT = data.table(a=1:2, b=list(1:5,1:10)) > DT ab 1: 1 1,2,3,4,5 2: 2 1,2,3,4,5,6, > sapply(DT$b, length) [1] 5 10 

Observe la bonita impresión de los vectores en la columna b . Esas comas son solo para mostrar, cada celda es en realidad un vector (como se muestra en el comando sapply anterior). Tenga en cuenta también la coma final en el segundo elemento de b . Eso indica que el vector es más largo de lo que se muestra (data.table solo muestra los primeros 6 elementos).

O, más como su ejemplo:

 > DT = data.table(id=1:2, comment=list( c("michele", Sys.time(), "hello"), c("michele", Sys.time(), "world") )) > DT id comment 1: 1 michele,1395330180.9278,hello 2: 2 michele,1395330180.9281,world 

Lo que intenta hacer no es solo tener una columna de list , sino también poner una list en cada celda, por lo que se muestra . Además, si coloca listas con nombre en cada celda, tenga cuidado de que todos esos nombres ocuparán espacio. Donde sea posible, una list columna de vectors puede ser más fácil.