作为这个老人的后续行动,但是好东西: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
这样做的方法是什么?
答案 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)的特殊情况。