我想获得data.table中某个列中值的总和和净值。总和,我的意思是忽略负值,因此在本例中,对于a
,净额为4,总和为5。
>dt = data.table(id = c("a","a","a","b","b","b","b","c","c"),value = c(-1,2,3,-3,4,-2,3,-1,1))
>head(dt,3)
id value
1: a -1
2: a 2
3: a 3
我可以通过添加一个额外的列来实现,如下所示:
>dt$grossValue = dt$value
>dt$grossValue[dt$grossValue < 0] = 0
>dt[,.(netTotal = sum(value),grossTotal= sum(grossValue)),by=id]
id netTotal grossTotal
1: a 4 5
2: b 2 7
3: c 0 1
但我真的不想为数据添加额外的列,因为有数百万行,我可能希望跨多个列执行此操作。有没有办法直接这样做?我可以弄清楚如何获得总计或总计(通过在value > 0
中添加i
获得总计),但不能同时计算两者。
答案 0 :(得分:4)
这是你在找什么?
dt[, .(netTotal = sum(value), grossTotal = sum(value * (value > 0))), by=id]
我在一次通过中计算了两列。 (value > 0)
用作从sum
中删除负值的逻辑。
答案 1 :(得分:1)
我显然误解了这个请求,因为我认为你也要求总计。所以这就是无偿的解决方案:
rbind( dt[,.(netTotal = sum(value),grossTotal= sum(value*(value>0))),by=id],
data.table( id="all", netTotal=dt[,sum(value)], grossTotal=dt[,sum(value*(value>0))]))
#-------------
id netTotal grossTotal
1: a 4 5
2: b 2 7
3: c 0 1
4: all 6 13
答案 2 :(得分:0)
library(dplyr)
dt %>% group_by(id) %>% summarize(net = sum(value), gross = sum(ifelse(value > 0, value, 0)))
答案 3 :(得分:0)
我们也可以通过逻辑索引
进行子集化而不是乘以dt[, .(netTotal = sum(value), grossTotal = sum(value[value>0])) , id]
# id netTotal grossTotal
#1: a 4 5
#2: b 2 7
#3: c 0 1