Использование списков внутри столбцов data.table

В data.table возможно иметь столбцы типа list, и я впервые пытаюсь воспользоваться этой функцией. Мне нужно сохранить для каждой строки таблицы dt несколько комментариев, взятых из веб-службы rApache. Каждый комментарий будет иметь имя пользователя, дату и время.

Вместо того, чтобы использовать длинные строки с каким-то странным необычным персонажем, чтобы отделить каждое сообщение от других (например, |) и ;, чтобы отделить каждый элемент комментария, я подумал использовать списки, подобные этому:

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>

чтобы сохранить все комментарии, добавленные для одной конкретной строки. (также потому, что будет легче конвертировать в JSON позже, когда мне нужно будет отправить его обратно в интерфейс)

Однако, когда я пытаюсь моделировать, как я буду фактически заполнять свою таблицу во время производства (добавив один комментарий к определенной строке), R либо сбой, либо не присваивает то, что я хотел бы, а затем сбой:

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

Я знаю, что пытаюсь неправильно использовать data.table, например. способ, которым был разработан аргумент j, позволяет это:

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

Вопрос: Итак, есть ли способ выполнить задание, которое я хочу? Или мне просто нужно взять dt$comment в переменную, изменить ее, а затем повторно назначить весь столбец каждый раз, когда мне нужно сделать обновление?

Ответы

Ответ 1

Использование :=:

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

В последнем случае вам понадобится еще один list, потому что data.table использует list(.) для поиска значений для назначения столбцам по ссылке.

Используя 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"))))

НТН


Я использую текущую версию версии 1.9.3, но должен отлично работать в любой другой версии.

> 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   

Ответ 2

Чтобы добавить дополнительную информацию, какие столбцы list действительно предназначены для каждой ячейки - это 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 

Обратите внимание на красивую печать векторов в столбце b. Эти запятые только для отображения, каждая ячейка на самом деле является вектором (как показано командой sapply выше). Обратите внимание также на запятую запятую на 2-й элемент b. Это указывает, что вектор длиннее, чем отображается (data.table показывает только первые 6 элементов).

Или, больше похоже на ваш пример:

> 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 

То, что вы пытаетесь сделать, - это не только столбец list, но и помещать list в каждую ячейку, поэтому отображается <list>. Кроме того, если вы помещаете названные списки в каждую ячейку, то остерегайтесь того, что все эти имена будут использовать пробел. По возможности, столбец list vectors может быть проще.