data.table中列系列的第一次/最后一次出现

时间:2015-11-30 21:38:04

标签: r data.table time-series

作为这个老人的后续行动,但是好东西:efficient row-wise operations on a data.table

我有一些数据(不幸的是):

library('data.table')
set.seed(1234)
m <- 5
n <- 7
rb <- function() runif(m,1000,2000) * rbinom(m,1,0.5)   
series_col_nms <- paste0('YearNo',1:n)    
rev <- data.table(cust_id = paste0('CustNo',1:m), 
                other_stuff = sample(letters,m, replace=TRUE))
for(col in series_col_nms){
  set(rev, j=col, value=rb())
}
setkey(rev, cust_id)

每位客户一行,包含各种列,包括第1年,第2年的年收入......

我想获得第一年和最后几年的年度指数以及每位客户的任何收入。

我可以产生所需的结果,但是有点hacky加入:

years_active <- rev[, which(.SD>0), .SDcols = series_col_nms, 
                    keyby=cust_id][, .(min_year_active = min(V1),
                                       max_year_active = max(V1)), keyby=cust_id]
years_active[rev]

这些尝试获得最小索引失败:

rev[, apply(.SD, 1, function(x) min(which(x>0))), .SDcols=series_col_nms, by=cust_id] # returns data type error    
rev[, do.call(pmin, lapply(.SD, function(x) which(x>0))), .SDcols=series_col_nms, by=cust_id] # returns empty

data.table这样做的方法是什么?

2 个答案:

答案 0 :(得分:3)

如果您希望逐行操作,通常会先对melt数据集进行操作,然后对单个列进行操作。

在您的情况下,一个相对简单的解决方案可能类似于

res <- melt(rev, id = 1:2)[, 
         as.list({
            temp <- value != 0
            if (any(temp)) range(which(temp)) else rep(NA_integer_, 2)
         }), 
        by = cust_id]

rev[, c("Min", "Max") := res[, .(V1, V2)]]
rev
#    cust_id other_stuff  YearNo1 YearNo2  YearNo3  YearNo4  YearNo5  YearNo6  YearNo7 Min Max
# 1: CustNo1           c 1640.311       0    0.000 1759.671    0.000 1503.933    0.000   1   6
# 2: CustNo2           q 1009.496       0    0.000 1201.248    0.000    0.000 1308.095   1   7
# 3: CustNo3           p    0.000       0    0.000    0.000 1484.991    0.000    0.000   5   5
# 4: CustNo4           q 1666.084       0 1831.345 1992.150 1243.929    0.000 1051.647   1   7
# 5: CustNo5           w    0.000       0    0.000    0.000    0.000    0.000    0.000  NA  NA

更清洁的版本但有警告可能

melt(rev, id = 1:2)[, as.list(as.integer(range(which(value != 0)))), by = cust_id]

答案 1 :(得分:2)

重塑我会以长格式存储数据:

mrev = melt(rev, 
  id=c("cust_id","other_stuff"), 
  variable.name="YearNo", 
  value.name="revenue")[revenue > 0]

您在revenue > 0条件下失去了客户5,但我怀疑这很重要。

然后根据需要收集汇总统计数据:

mrev[ , list(first = YearNo[1], last = YearNo[.N]), by=cust_id]

#    cust_id   first    last
# 1: CustNo1 YearNo1 YearNo6
# 2: CustNo2 YearNo1 YearNo7
# 3: CustNo4 YearNo1 YearNo7
# 4: CustNo3 YearNo5 YearNo5

当然,从你一直使用的字符串中解析数字很简单。

max.col 我认为这是一个糟糕的问题,但......

max.col(rev[,!c("cust_id","other_stuff"),with=FALSE] > 0, "first")
max.col(rev[,!c("cust_id","other_stuff"),with=FALSE] > 0, "last")

您必须返回并分别填写所有零(客户5)的特殊情况。