2017-01-20 84 views
1

我有以下数据表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 

回答

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是一个list或data.table。

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

评论

当制作组列,我认为这是更好地做一个表,而不是使用一系列的正则表达式,如data1[grepl(yada), g := 1L][grepl(yada2) & is.na(g), g := 2L][grepl(yada3) & is.na(g), g := 3L]因为后者,有没有办法在存在重复分配的情况下(cat1分配给多个g)或错过的分配(cat1分配到否g)。

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

+1

非常感谢! – User2321