2017-01-20 124 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