2013-04-30 2 views
2

У меня есть некоторые data.tables так:data.table назначая с `sapply` в слиянии

x <- data.table(id=rep(1:3, 2), a=1:6) 
y <- data.table(id=1:3, b=2:4) 

я могу объединить их, как это:

setkey(x, id) 
setkey(y, id) 
x[y] 
    id a b 
1: 1 1 2 
2: 1 4 2 
3: 2 2 3 
4: 2 5 3 
5: 3 3 4 
6: 3 6 4 

Теперь я хочу, чтобы создать новый колонка в x основана на a и b, которая является суммой a и b. я могу сделать это с помощью:

x[y, val:=a + b] 

Однако теперь, по какой-то причине, что оператор «+» не vectorised. Как я могу отсортировать по строкам в x, где x[y] необходим для расчета? Кроме того, предположим, что я не могу использовать mapply (потому что для моей фактической проблемы mapply не подходит для этой функции).

Я пытаюсь использовать sapply как так, чтобы добавить в строчном порядке:

x[y, sapply(1:nrow(x), function (i) a[i] + b[i])] 

Однако это возвращает неправильный результат:

id V1 
1: 1 3 
2: 1 NA 
3: 1 NA 
4: 1 NA 
5: 1 NA 
6: 1 NA 
7: 2 5 
8: 2 NA 
9: 2 NA 
10: 2 NA 
11: 2 NA 
12: 2 NA 
13: 3 7 
14: 3 NA 
15: 3 NA 
16: 3 NA 
17: 3 NA 
18: 3 NA 

Если я делаю это работает:

x[y][, sapply(1:nrow(x), function (i) a[i] + b[i])] 
# [1] 3 6 5 8 7 10 

НО когда я пытаюсь и назначить это для столбца в x, он не сохраняется (имеет смысл, потому что похоже, что я пытаюсь сохранить новый столбец в x[y]).

x[y][, val:=sapply(1:nrow(x), function (i) a[i] + b[i])] 

Есть ли способ сделать выше, но сохранить вывод в x[, val]? Это как я должен это делать, или есть еще data.table -y way?

x[, val:=x[y][, sapply(1:nrow(x), function (i) a[i] + b[i])]] 
+0

Это будет легче ответить, если вы дадите лучший пример функции, которую вы хотите векторизовать. – mnel

ответ

5

Вы делаете by-without-by, не зная его, (смотрите ниже для описания с помощью)

Дополнительно: Aggregation для подмножества известных групп особенно эффективен при прохождении этих групп в I , Когда i является data.table, DT [i, j] оценивает j для каждой строки i. Мы называем это без или группировкой по i. Следовательно, self join DT [data.table (unique (colA)), j] равно , идентичному DT [, j, by = colA].

Это означает, что j вычисляется для каждой строки i (cylcing через y один ряд в то время, - так что, если вы запустите sapply(1:nrow(x),...) в j это создаст вектор длины nrow(x) каждый раз, когда это не то, что вы хотите.

Таким образом, ваш второй вариант, безусловно, действительный подход (как это один из рекомендуемых подходов к делать это)

В противном случае вы можете использовать .N (При группировке по I, .N является количество строк в x соответствует, для каждой строки i) не nrow(x), но вам нужно будет подумать о длине ваших объектов и о том, как ваша функция должна быть векторизована.

Возьмите это в качестве примера

x[y, {browser(); a+b}] 
Called from: `[.data.table`(x, y, { 
    browser() 
    a + b 
}) 
Browse[1]> a 
[1] 1 4 
Browse[1]> b 
[1] 2 
Browse[1]> .N 
[1] 2 

a имеет длину два, поскольку значение ключевых матчей с 2 ​​рядами от х. b только имеет длину 1, потому что он имеет длину 1 в y.

Я думаю, что лучший подход правильно Vectorize вашей функции (что трудно дать совет, на не более пример)

другой подход был бы повторить b длиной a например

x[y, val := { 
bl <- rep_len(b, .N) 
sapply(seq_len(.N), function(i) a[i] + bl[i])}] 
x 
    id a val 
1: 1 1 3 
2: 1 4 6 
3: 2 2 5 
4: 2 5 8 
5: 3 3 7 
6: 3 6 10 

или если вы знаете, что y имеет уникальные строки для каждого значения id, тогда вам не нужно пытаться индексировать любые столбцы из него.

x[y, val2 := sapply(seq_len(.N), function(i) a[i] + b)] 
# an alternative would be to use sapply on a (avoid creating another vector) 
x[y, val3 := sapply(a, function(ai) ai + b)] 
x 
# id a val val2 val3 
# 1: 1 1 3 3 3 
# 2: 1 4 6 6 6 
# 3: 2 2 5 5 5 
# 4: 2 5 8 8 8 
# 5: 3 3 7 7 7 
# 6: 3 6 10 10 10 
+0

О, спасибо за объяснение по разным длинам 'a' и' b'. Я спросил, потому что моя функция действительно не является векторизуемой, не используя 'sapply', как я имею в вопросе (это * почти * подходит' mapply', но одним из аргументов функции является 'list (a [i], b [i ]) 'и я не хочу генерировать весь список списков, которые мне нужно будет передать этому' mapply'). –

+0

Хотя я не уверен, что понимаю документацию 'by-without-by' и как это относится к моему вопросу, если я не делаю' by = 1: nrow (x) '? –

+0

Да '1: nrow (x)' не то, что вы хотите, если оно находится в одном и том же '[]' вызове как объединение 'i', которое реализуется by-without-by. Переход к отдельному вызову '[]' является одним из способов. См. Мое редактирование. – mnel

Смежные вопросы