Как лучше всего объединить один столбец data.table с другим столбцом того же data.table?

My data

У меня есть data.tableDT с текущей (F0YR) и следующий (F1YR) конец финансового года (FYE), закодированный в виде целых чисел. Поскольку каждый следующий FYE в конечном итоге станет текущий FYE, целое число будет как в столбцеF1YR а такжеF0YR, Кроме того, мои данные содержат ежемесячные наблюдения, поэтому тот же FYE будет в наборе данных многократно:

library(data.table)
DT <- data.table(ID     = rep(c("A", "B"), each=9),
                 MONTH  = rep(100L:108L, times=2),
                 F0YR   = rep(c(1L, 4L, 7L), each=3, times=2),
                 F1YR   = rep(c(4L, 7L, 9L), each=3, times=2),
                 value  = c(rep(1:5, each=3), 6, 6, 7),
                 key    = "ID,F0YR")
DT
      ID MONTH F0YR F1YR value
 [1,]  A   100    1    4     1
 [2,]  A   101    1    4     1
 [3,]  A   102    1    4     1
 [4,]  A   103    4    7     2
 [5,]  A   104    4    7     2
 [6,]  A   105    4    7     2
 [7,]  A   106    7    9     3
 [8,]  A   107    7    9     3
 [9,]  A   108    7    9     3
[10,]  B   100    1    4     4
[11,]  B   101    1    4     4
...
What I want to do

Для каждогоID а такжеF1YR комбинацию, я хочу получить значение дляID а такжеF0YR сочетание. Как пример: компания А имела значение2 заFOYR==4, Сейчас, Я хочу дополнительный столбец для всех комбинаций сID=="A" а такжеF1YR==4 который установлен в 2, рядом с уже существующим значением 1.

What I tried
intDT <- DT[CJ(unique(ID), unique(F0YR)), list(ID, F0YR, valueNew = value), mult="last"]
setkey(intDT, ID, F0YR)
setkey(DT, ID, F1YR)
DT <- intDT[DT]
setnames(DT, c("F0YR.1", "F0YR"), c("F0YR", "F1YR"))
DT
      ID F1YR valueNew MONTH F0YR value
 [1,]  A    4        2   100    1     1
 [2,]  A    4        2   101    1     1
 [3,]  A    4        2   102    1     1
 [4,]  A    7        3   103    4     2
 [5,]  A    7        3   104    4     2
 [6,]  A    7        3   105    4     2
 [7,]  A    9       NA   106    7     3
 [8,]  A    9       NA   107    7     3
 [9,]  A    9       NA   108    7     3
[10,]  B    4        5   100    1     4
[11,]  B    4        5   101    1     4
...

(Обратите внимание, что я используюmult="last" здесь, потому что, хотя значения должны изменяться только с изменениями F0YR или F1YR, иногда они не меняются, и это только мое прерыватель связи).

What I want

Это выглядит невероятно. Прежде всего, я должен сделать копию моего DT. Во-вторых, так как я присоединяюсь в основном то же самоеdata.tableвсе имена столбцов имеют одинаковое имя и я должен переименовать их. Я думал, чтоself join был бы путь вперед, но я пытался и не мог найти хорошее решение. У меня есть надежда что есть что-то простое, чего я просто не вижу ... У кого-нибудь есть подсказка? Или мои данные настроены таким образом, что это на самом деле трудно (возможно, потому что у меня есть ежемесячные наблюдения, но я хочу присоединиться только к ежеквартальным или ежегодным изменениям значений).

 Matt Dowle14 июн. 2012 г., 17:05
@ Джош Отлично. Нет, это должно добавить новые столбцы в порядке. Вы можете даже назначить новый столбец, и он заполнит оставшуюся часть столбцаNA для тебя. Если ни одна из них не работает, пожалуйста, отправьте отчет об ошибке или новый вопрос. Удостоверитьсяtest.data.table() возвращается653 tests ok как-то исключить, используя старую версию v1.8.1.
 Matt Dowle14 июн. 2012 г., 18:12
Нет проблем, добавили ответ. Ушел прямо к:= по группам, группировка поi неbyи используя унаследованную область видимости (V1 происходит отi сфера) для загрузки. Точно не планировал заходить так далеко в первом демо:= по группам, но это так, как это получилось!
 Josh O'Brien14 июн. 2012 г., 16:17
@ MatthewDowle - Очень мило! Я только что попробовал это. Похоже, это работает для перезаписи существующего столбца, но еще не для создания нового. Это правильно?
 Christoph_J14 июн. 2012 г., 17:39
@ MatthewDowle Это действительно очень приятно. Я не знал, как просто установить пакет таким образом ... В любом случае, я также не вижу, как:= по группе может помочь здесь. Пробовал в течение часа и ничего не мог понять. Так что я думаю, что мое решение в порядке. В любом случае объединение одной таблицы data.table двумя столбцами этой таблицы data.table является очень конкретным случаем использования.
 Matt Dowle14 июн. 2012 г., 12:58
Я не думаю, что это необходимо для этого вопроса, но:= группа сейчас работает в 1.8.1 и может быть использована для этого, возможно. R-Forge работает нормально, а бинарный файл установлен нормально (в R 2.15.0, поскольку R-Forge работает только для последних), используяinstall.packages("data.table", repos="http://R-Forge.R-project.org"), Проверь этоtest.data.table() возвращает & quot; 653 теста завершено нормально & quot; чтобы быть уверенным, что это последняя версия. Смотрите последние новости, чтобы увидеть, если какие-либо новые функции полезны для этого.

Ответы на вопрос(1)

Решение Вопроса

а затем соединяется с этим. часто помогает. Итак, начиная с вашегоDTи используя v1.8.1:

> agg = DT[,last(value),by=list(ID,F0YR)]
> agg
   ID F0YR V1
1:  A    1  1
2:  A    4  2
3:  A    7  3
4:  B    1  4
5:  B    4  5
6:  B    7  7

Я назвал этоagg потому что я не мог придумать лучшего имени. В этом случае вы хотелиlast который на самом деле не является совокупностью как таковой, но вы понимаете, о чем я.

Тогда обновитеDT по ссылке по группам. Здесь мы группируем поi.

setkey(DT,ID,F1YR)
DT[agg,newcol:=V1]
    ID MONTH F0YR F1YR value newcol
 1:  A   100    1    4     1      2
 2:  A   101    1    4     1      2
 3:  A   102    1    4     1      2
 4:  A   103    4    7     2      3
 5:  A   104    4    7     2      3
 6:  A   105    4    7     2      3
 7:  A   106    7    9     3     NA
 8:  A   107    7    9     3     NA
 9:  A   108    7    9     3     NA
10:  B   100    1    4     4      5
11:  B   101    1    4     4      5
12:  B   102    1    4     4      5
13:  B   103    4    7     5      7
14:  B   104    4    7     5      7
15:  B   105    4    7     5      7
16:  B   106    7    9     6     NA
17:  B   107    7    9     6     NA
18:  B   108    7    9     7     NA

Это правильно? Не уверен, что я полностью следовал. Эти операции должны быть очень быстрыми, без каких-либо копий и масштабироваться до больших данных. По крайней мере, таково намерение.

 Christoph_J14 июн. 2012 г., 21:53
Отличный ответ, Мэтью, большое спасибо. Это именно то, что я хочу. Хотя один вопрос: ваш ответ выглядит, за исключениемnewcol:=V1 часть, довольно простая, и я думал, что попробовал каждую возможную комбинацию, которая включает совокупность сначала и затем присоединяется к мантре. Поэтому я просто запускаю ваш ответ сDT[agg] вместоDT[agg,newcol:=V1], Теперь мой DT выглядит по-другому: у него всего 14 рядов и несколько NA на МЕСЯЦ. Это почему? Я просто подумалnewcol:=V1 переименовывает V1 в newcol. Что мне здесь не хватает?
 Christoph_J15 июн. 2012 г., 08:55
Спасибо, я обязательно посмотрю на это! В вашем пакете слишком много классных вещей, чтобы не отставать от него ;-)
 14 июн. 2012 г., 23:38
@Christoph_J Отлично. Нет,:= никогда не переименовывает столбцы.setnames() переименовывает столбцы.:= присваивает по ссылке на существующие или новые столбцы. Часть, которую вы можете не заметить, состоит в том, чтоi (т.е. в этом случае столбцы не участвуют в объединенииV1) можно использовать вjСпасибо присоединиться к унаследованной области. Попробуйте удалитьnewcol:= немного вместо этого, чтобы увидеть это. Или изучите пример в?data.table из# join inherited scope. DT[agg] возвращаетсяNAс нет совпадений.:= с другой стороны обновленияDT по ссылке; обновлять нечего, когдаi строка не соответствуетDT.

Ваш ответ на вопрос