web-dev-qa-db-fra.com

Utilisation de listes dans les colonnes data.table

Dans data.table est possible d'avoir des colonnes de type list et j'essaie pour la première fois de bénéficier de cette fonctionnalité. J'ai besoin de stocker pour chaque ligne de ma table dt plusieurs commentaires extraits d'un service Web rApache. Chaque commentaire aura un nom d'utilisateur, une date et un élément de corps.

Au lieu d'utiliser de longues chaînes avec un caractère étrange et inhabituel pour séparer chaque message des autres (comme |) et un ; pour séparer chaque élément dans un commentaire, j'ai pensé à utiliser des listes comme celle-ci:

library(data.table)
dt <- data.table(id=1:2,
        comment=list(list(
            list(username="michele", date=Sys.time(), message="hello"),
            list(username="michele", date=Sys.time(), message="world")),
          list(
            list(username="michele", date=Sys.time(), message="hello"),
            list(username="michele", date=Sys.time(), message="world"))))

> dt
   id comment
1:  1  <list>
2:  2  <list>

pour stocker tous les commentaires ajoutés pour une ligne particulière. (également parce qu'il sera plus facile de convertir en JSON plus tard lorsque je devrai le renvoyer à l'interface utilisateur)

Cependant, lorsque j'essaie de simuler comment je vais réellement remplir ma table pendant la production (en ajoutant un seul commentaire à une ligne particulière), R plante ou n'affecte pas ce que je voudrais, puis se bloque:

library(data.table)

> library(data.table)
> dt <- data.table(id=1:2, comment=vector(mode="list", length=2))
> 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

Je sais que j'essaie d'abuser data.table, par exemple. la façon dont l'argument j a été conçu permet ceci:

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

Question: Alors, y a-t-il un moyen de faire le devoir que je veux? Ou je dois juste prendre dt$comment dans une variable, modifiez-la, puis réattribuez la colonne entière à chaque fois que je dois faire une mise à jour?

25
Michele

En utilisant :=:

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")))]

Pour le dernier cas, vous aurez besoin d'un list de plus car data.table Utilise list(.) pour rechercher les valeurs à affecter aux colonnes par référence.

Utilisation de 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


J'utilise la version de développement actuelle 1.9.3, mais devrait bien fonctionner sur toute autre version.

> 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   
26
Arun

Juste pour ajouter plus d'informations, les colonnes list sont vraiment conçues lorsque chaque cellule est elle-même un vector:

> DT = data.table(a=1:2, b=list(1:5,1:10))
> DT
   a            b
1: 1    1,2,3,4,5
2: 2 1,2,3,4,5,6,

> sapply(DT$b, length)
[1]  5 10 

Remarquez la jolie impression des vecteurs dans la colonne b. Ces virgules sont juste pour l'affichage, chaque cellule est en fait un vecteur (comme le montre la commande sapply ci-dessus). Notez également la virgule de fin sur le 2ème élément de b. Cela indique que le vecteur est plus long que celui affiché (data.table n'affiche que les 6 premiers éléments).

Ou, plus comme votre exemple:

> 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 

Ce que vous essayez de faire est non seulement d'avoir une colonne list, mais également de mettre list dans chaque cellule, c'est pourquoi <list> est affiché. De plus, si vous placez des listes nommées dans chaque cellule, prenez garde à ce que tous ces noms utilisent de l'espace. Dans la mesure du possible, une colonne list de vectors peut être plus simple.

14
Matt Dowle