基于数据表j中的多个条件对列列值求和

时间:2017-01-20 14:45:55

标签: r data.table

我有以下数据表data1(更多行和更多变体,但这是一个示例):

    item cat1 cat2 cat3 amounts
 1:    1   99 9999 9990     100
 2:    2   12 8199 9990     100
 3:    3   12 8199 9990     100
 4:    4   12 8199 9990     100
 5:    5   12 8199 9990     100
 6:    6   12 8199 9990     100
 7:    7   12 8199 9990     100
 8:    8   12 4129 9990     100
 9:    9   12 8199 9990     100
10:   10   12 8199 9990     100

library(data.table)
data1 <- setDT(structure(list(item = 1:10, cat1 = c("99", "12", "12", "12", 
"12", "12", "12", "12", "12", "12"), cat2 = c("9999", "8199", 
"8199", "8199", "8199", "8199", "8199", "4129", "8199", "8199"
), cat3 = c("9990", "9990", "9990", "9990", "9990", "9990", "9990", 
"9990", "9990", "9990"), amounts = c("100", "100", "100", "100", 
"100", "100", "100", "100", "100", "100")), .Names = c("item", 
"cat1", "cat2", "cat3", "amounts"), class = c("data.table", "data.frame"
), row.names = c(NA, -10L)))

最初我想获得一些基于cat1,cat2,cat3符合某些标准的行的信息。所以我做了这样的事情:

data1[, .(  items = .N,
            group1 = sum(grepl("^[1-8]{2}$", cat1)),
            group2 = sum(grepl("^[1-8]9$", cat1)),
            group3 = sum(grepl("^9[1-8]$", cat1)),
            group4 = sum(cat1 == "99"))]

结果是:

    items group1 group2 group3 group4
1:    10      9      0      0      1

分析中还包含许多其他标准,但这也只是一个样本。我的要求发生了变化,现在对于指定的每个组我都需要对金额求和。 所以我有两个问题:

1)数据表中是否有办法以类似于计算计数的方式进行求和(因此基本思想就像sum(amounts)其中grepl("^[1-8]{2}$", cat1)

2)有没有一种有效的方法可以解决这个问题?除了为原始数据集添加新列以获得我拥有的每个标准,然后进行过滤求和之外,我无法想到获得结果的任何好方法。

我理想的结果是:

    items group1 group2 group3 group4 total_amounts  group1_amounts   group2_amounts group3_amounts group4_amounts
1:    10      9      0      0      1          1000            900              0              0            100

1 个答案:

答案 0 :(得分:2)

我会说:为表格的完整映射创建一个表(它们是互斥的):

m = data.table(g = paste0("group", 1:4))[,.(cat1 = as.character(
  if (.GRP==1L) combn(1:8, 2, paste0, collapse = "") else
  if (.GRP==2L) paste0(1:8, 9) else
  if (.GRP==3L) paste0(9, 1:8) else
  if (.GRP==4L) "99"
)), by=g]

验证映射是否为......

stopifnot(m[duplicated(cat1), .N == 0L])   # mutually exclusive
stopifnot(data1[!m, on=.(cat1), .N == 0L]) # exhaustive

将组作为变量添加到主表中:

data1[m, on=.(cat1), g := i.g]

加入小组,按小组汇总:

res = data1[.(g = unique(m$g)), on=.(g), .(.N, tot_amt = sum(as.numeric(amounts), na.rm=TRUE)), by=.EACHI]

#         g N tot_amt
# 1: group1 9     900
# 2: group2 0       0
# 3: group3 0       0
# 4: group4 1     100

我认为这是输出的更有用的格式,但如果你真的想要单行输出......

cbind(N = sum(res$N), dcast(res, . ~ g, value.var=c("N","tot_amt")))[, !"."]

#     N N_group1 N_group2 N_group3 N_group4 tot_amt_group1 tot_amt_group2 tot_amt_group3 tot_amt_group4
# 1: 10        9        0        0        1            900              0              0            100

“加入”步骤的工作原理

语法为x[i, on=cols, j, by=.EACHI],其中i是列表或data.table。

  • .()list()的某些参数中x[...]的别名。
  • by=.EACHI表示i每行的分组(即使是i中无法匹配的x行。)
  • 像往常一样,为j确定的每个组计算by=

评论

在创建组列时,我认为创建表而不是使用一系列正则表达更好,例如data1[grepl(yada), g := 1L][grepl(yada2) & is.na(g), g := 2L][grepl(yada3) & is.na(g), g := 3L],因为对于后者,没有办法捕获重复赋值的情况({ {1}}分配给多个cat1)或错过了分配(g已分配给无cat1)。

当按小组进行总结时,我认为最好是g而不是data1[.(all_groups), on=.(g), ..., by=.EACHI],因为后者会跳过碰巧没有出现在表格中的群组。