使用以下命令在函数中创建新的r data.table列时的范围:=

时间:2017-02-02 12:48:17

标签: r data.table scoping

这是我在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方法吗?

1 个答案:

答案 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;