我有以下数据表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
答案 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]
,因为后者会跳过碰巧没有出现在表格中的群组。