2017-02-02 2 views
0

Это продолжение для вопроса, который я разместил здесь Creating a new r data.table column based on values in another column and grouping, и на который @Frank дал отличный ответ.Показывать при создании нового столбца r data.table в функции, используя: =

Как я должен выполнить несколько этих вычислений с разными интервалами дат, я хочу выполнить функцию, которая их выполняет. Однако, похоже, я сталкиваюсь с проблемой обзора. Я читал 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). Полагаю, это потому, что столбец еще не существует, но я не знаю, как решить эту проблему.

В качестве бонуса, который я хотел бы задать, есть также способ динамически назвать столбцы, т.е. в примере, например, «daysFrom _ to_ daysUntil», и имя будет «0_to_10»?

----- EDIT ----

я наткнулся на возможный ответ сам, несколько аналогично ответу @ 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). Почему это?

b) котировки требуются в пределах "prevPurch1to10". Опять же, почему? Есть ли еще data.table ish способ сделать это без кавычек?

ответ

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, требует кавычек, поскольку объект не существует до вызова функции. Использование такого аргумента без кавычек обычно приводит к ошибке: «объект X не найден».

+0

Привет, спасибо. Я также добавил свой собственный ответ, потому что 'substitute' не кажется необходимым, и вы также добавили цитаты вокруг' 'prevPurch1to10'', о необходимости которых я не понимаю. – Mantelimies