这是我在Creating a new r data.table column based on values in another column and grouping发布的问题的延续,而@Frank提供了一个很好的答案。
由于我必须使用不同的日期间隔进行多次这些计算,我想做一个能够完成这些计算的函数。但是,我似乎遇到了一个范围问题。我在这里阅读了Vignettes,FAQ和大量问题,但我仍然感到困惑。
我们将使用相同的数据:
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)
行排除在外,结果也是一样的。我想这是因为该列尚不存在,但我不知道如何解决这个问题。
作为奖励,我想问一下,是否还有一种动态命名列的方法,即。例如在&#34; daysFrom
_到_ daysUntil
&#34;中,名称将是&#34; 0_to_10&#34;?
-----编辑----
我自己也偶然发现了一个可能的答案,有点类似于@ 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
然而,仍然存在以下两个奇怪的事情:
a)在substitute()
上添加括号时不需要(newColName)
。那是为什么?
b)"prevPurch1to10"
周围需要引号。再次,为什么?在没有引号的情况下,还有更多的data.table
方法吗?
答案 0 :(得分:1)
您可以直接在作业中使用替补:
sumPreviousPurchases = function(dt, newColName, daysFrom, daysUntil){
zip = substitute(zip)
dt[, substitute(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 prevPurch1to10
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
注意:
解决方案()
中的括号强制评估参数。这是在基础R中实现的,并且是基于操作顺序的数学概念的许多编程语言的常用技术。 (首先评估括号中的对象,然后指数等)。 substitute
的使用使替换明确,可能更容易阅读。
通常,定义未来对象的函数的参数(如prevPurch1to10)需要引号,因为在调用函数之前该对象不存在。使用没有引号的这样的参数通常会导致错误:&#34;找不到对象X。&#34;