Это продолжение вопроса, который я разместил здесь Создание нового столбца r data.table на основе значений в другом столбце и группировка, на что @Frank дал отличный ответ.
Поскольку мне приходится выполнять несколько таких расчетов с разными интервалами дат, я хочу сделать функцию, которая их выполняет. Тем не менее, я, кажется, столкнулся с проблемой области видимости. Я прочитал виньетки, часто задаваемые вопросы и массу вопросов здесь, и я все еще озадачен.
Мы будем использовать те же данные:
library(data.table)
set.seed(88)
DT <- data.table(date = Sys.Date()-365 + sort(sample(1:100, 10)),
zip = sample(c("2000", "1150", "3000"),10, replace = TRUE),
purchaseAmount = sample(1:20, 10))
Вот ответ @Frank:
DT[, new_col :=
DT[.(zip = zip, d0 = date - 10, d1 = date), on=.(zip, date >= d0, date <= d1),
sum(purchaseAmount)
, by=.EACHI ]$V1
]
DT
date zip purchaseAmount new_col
1: 2016-01-08 1150 5 5
2: 2016-01-15 3000 15 15
3: 2016-02-15 1150 16 16
4: 2016-02-20 2000 18 18
5: 2016-03-07 2000 19 19
6: 2016-03-15 2000 11 30
7: 2016-03-17 2000 6 36
8: 2016-04-02 1150 17 17
9: 2016-04-08 3000 7 7
10: 2016-04-09 3000 20 27
А теперь собственно проблема, с которой я столкнулся. Я создал следующую функцию, которая позволяет динамически изменять интервал:
sumPreviousPurchases = function(dt, newColName, daysFrom, daysUntil){
zip = substitute(zip)
newColName = substitute(newColName)
dt[, newColName :=
dt[.(zip = zip, d0 = (date - daysUntil), d1 = (date - daysFrom))
, on=.(zip, date >= d0, date <= d1),
sum(purchaseAmount)
, by=.EACHI ]$V1
]
}
sumPreviousPurchases(DT, prevPurch1to10, 0, 10)
DT
date zip purchaseAmount newColName
1: 2016-02-07 1150 5 5
2: 2016-02-14 3000 15 15
3: 2016-03-16 1150 16 16
4: 2016-03-21 2000 18 18
5: 2016-04-06 2000 19 19
6: 2016-04-14 2000 11 30
7: 2016-04-16 2000 6 36
8: 2016-05-02 1150 17 17
9: 2016-05-08 3000 7 7
10: 2016-05-09 3000 20 27
Что меня беспокоит, так это обзор. Функция называет новый столбец newColName
независимо от того, что я вставляю в вызове функции. Из чтения я понял, что при вызове имен столбцов data.table в аргументах функции следует использовать substitute()
-функцию. Однако здесь это не работает, результат тот же, даже если я оставлю всю строку newColName = substitute(newColName)
. Я предполагаю, что это потому, что столбца еще не существует, но я не знаю, как решить эту проблему.
В качестве бонуса я хотел бы спросить, есть ли способ динамически именовать столбцы, т.е. в примере, например, «daysFrom
_ to_daysUntil
», а имя будет «0_to_10»?
----- РЕДАКТИРОВАТЬ ----
Я также сам наткнулся на возможный ответ, несколько похожий на ответ @lmo, используя идею отсюда: http://brooksandrew.github.io/simpleblog/articles/advanced-data-table/#assign-a-column-with--named-with-a-character-object
Наиболее важные отличия в вопросе: я полностью удалил newColName = substitute(newColName)
и добавил скобки вокруг (newColName)
на dt[, (newColName) :=
sumPreviousPurchases = function(dt, newColName, daysFrom, daysUntil){
zip = substitute(zip)
#newColName = substitute(newColName)
dt[, (newColName) :=
dt[.(zip = zip, d0 = (date - daysUntil), d1 = (date - daysFrom))
, on=.(zip, date >= d0, date <= d1),
sum(purchaseAmount)
, by=.EACHI ]$V1
]
}
Кроме того, я добавил кавычки в файл "prevPurch1to10"
.
sumPreviousPurchases(DT, "prevPurch1to10", 0, 10)
и получил ответ
date zip purchaseAmount prevPurch1to10
1: 2016-02-17 1150 7 7
2: 2016-02-22 3000 8 8
3: 2016-03-04 1150 2 2
4: 2016-03-16 2000 14 14
5: 2016-04-03 2000 11 11
6: 2016-04-11 3000 12 12
7: 2016-04-21 1150 17 17
8: 2016-04-22 3000 3 3
9: 2016-05-03 2000 9 9
10: 2016-05-11 3000 4 4
Тем не менее, есть еще две следующие странные вещи:
а) substitute()
не требуется при добавлении скобок к (newColName)
. Это почему?
б) кавычки необходимы вокруг "prevPurch1to10"
. Опять же, почему? Есть ли более data.table
ish способ сделать это без кавычек?