【问题标题】:Data.table: dynamically creating variables over various subsets of data and grouping by variable x, subsetting final resultsData.table:在各种数据子集上动态创建变量并按变量 x 分组,对最终结果进行子集化
【发布时间】:2016-10-12 14:57:37
【问题描述】:

我正在为我的数据中的各个客户 ID 在多个时间段内创建三种类型的变量。这些新变量包括价格向量的总和、价格向量的平均值以及日期向量中连续日期之间的平均差。

使用 data.table,我循环多个时间段,对每个时间段的数据进行子集化,并为各个客户 ID 计算这些变量。当我遍历时间段时,这些变量中的每一个都是动态命名的。就目前而言,这些变量的计算是正确的。

这是我卡住的地方:在计算完所有这些变量之后,我想对数据进行子集化,以包含新的聚合变量以及每个客户最近的 purchase.price 和 date 元素。

我认为 data.table 可能会在与每个客户对应的所有行上复制计算的总数。但是,它仅在与表的 i 索引中指定的周期间隔相对应的行中复制这些总计。由于它不会为每个客户在所有行中复制这些总计,因此我的最终 dplyr 块并不能解决问题。

在第二个和第三个代码块中,我将给出最终 dplyr 代码的输出,然后是我想要实现的输出。

这个问题源于我们在subsetting over fewer variables that are not being created dynamically 的一个类似问题。

library(lubridate)
library(data.table)
library(dplyr)

data <- data.frame(custid = c(rep(1, 25), rep(2, 25), rep(1, 25), rep(2, 25)),
                   purchase.price = seq(1, 200, by=2),
                   date = seq.Date(from=as.Date("2015-01-01"), to=as.Date("2015-04-10"), by="days"))

period_intervals <- list(period_one = interval(as.Date("2015-01-01"), as.Date("2015-01-30")),
                         period_two = interval(as.Date("2015-02-01"), as.Date("2015-02-28")),
                         period_three = interval(as.Date("2015-03-01"), as.Date("2015-03-31")),
                         period_four = interval(as.Date("2015-04-01"), as.Date("2015-04-28")))


data <- as.data.table(data)
data <- data[order(date)]
setkey(data, custid)

time_periods <- c(1:4)

for(i in time_periods[1]:max(time_periods)){
    data <- data[date %within% period_intervals[[i]], 
                 paste("period", i, "price.sum", sep="."):= sum(purchase.price), 
                 by = custid]

    data <- data[date %within% period_intervals[[i]], 
                 paste("period", i, "price.mean", sep="."):= mean(purchase.price), 
                 by = custid]

    data <- data[date %within% period_intervals[[i]],
                 paste("period", i, "mean.diff.date", sep="."):= mean(as.numeric(diff(purchase.price))),
                 by = custid]
}

data_sub <- data %>%
  group_by(custid) %>%
  arrange(desc(date)) %>%
  filter(row_number() == 1)

dplyr 子集的当前结果(显示前 7 列):

  custid purchase.price       date period.1.price.sum period.1.price.mean period.1.mean.diff.date period.2.price.sum ...
   <dbl>          <dbl>     <date>              <dbl>              <dbl>                   <dbl>              <dbl> ...
1      2            199 2015-04-10                 NA                 NA                      NA                 NA ...
2      1            149 2015-03-16                 NA                 NA                      NA                 NA ...

这是我所希望的(显示前 7 列):

      custid purchase.price       date period.1.price.sum period.1.price.mean period.1.mean.diff.date period.2.price.sum ...
       <dbl>          <dbl>     <date>              <dbl>              <dbl>                   <dbl>              <dbl> ...
    1      2            199 2015-04-10                625                 25                       2                981 ...
    2      1            149 2015-03-16                275                 55                       2                1539 ...

注意:

在我的完整数据集中,我在 10-20 个时间段之间循环。要计算的周期数可能会发生变化,因此我的方法是动态创建新变量。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    我们可以像上一篇一样使用Map

    nm1 <- sprintf("%s.%d.%s", "period", seq_along(period_intervals), "price.sum")
    nm2 <- sprintf("%s.%d.%s", "period", seq_along(period_intervals), "price.mean")
    nm3 <- sprintf("%s.%d.%s", "period", seq_along(period_intervals), "mean.diff.date")
    data[,   c(rbind(nm1, nm2, nm3)) := unlist(Map(function(x,y) {
             x1 <- purchase.price[x %within% y]
             list(sum(x1), mean(x1), mean(as.numeric(diff(x1))))},
                       list(date), period_intervals), recursive = FALSE), by = custid]
    data[order(custid, -date)][,.SD[1] , custid]
    

    【讨论】:

    • 看起来很棒!我想知道为什么客户 1 在周期 3 中的平均日期差异是 NaN。查看 cust1_period3 &lt;- data %&gt;% filter(custid == 1 &amp; date %within% period_intervals[[3]]) %&gt;% mutate(period.3.mean.diff.date = mean(as.numeric(diff(date)))) 返回平均日期差 1?
    • @ToddYoung 我认为列名互换了
    • @ToddYoung 您在帖子中的代码是 diff(purchase.price),而在 cmets 中是 diff(date)。我一直在关注你的帖子。否则,它看起来对我来说很好。
    • 我不太清楚你的意思。这可能是我将原始数据集称为“数据”的错,如果我们复制原始数据示例并将其称为“data.check”,然后运行cust1_period3 &lt;- data.check %&gt;% filter(custid == 1 &amp; date %within% period_intervals[[3]]) %&gt;% mutate(period.3.mean.diff.date = mean(as.numeric(diff(date)))),结果给出日期的平均差异对于客户 1 = 1。这样可以解决问题吗?
    • 开枪,你是对的。那是一个错字。这样,一切都按预期进行。
    猜你喜欢
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 2016-01-07
    • 2013-01-02
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多