应用规则来计算特定的总和

时间:2015-09-02 06:47:30

标签: r

嗨我有这样的数据集。

Num   C     Pr      Value   Volume
111   aa    Alen      111    222
111   aa    Paul      100    200
222   vv    Iva       444    555
222   vv    John      333    444

我想根据Num过滤数据并添加一个新行,其中取值列和值的总和,但保留列Num和C的信息,但在列Pr中放置总计。它看起来应该是这样的。

Num   C     Pr      Value   Volume
222   vv   Total     777     999
你可以建议我怎么做吗?我想只为Num 222。

当我尝试使用res命令时,我最终得到了这个结果。

#  Num  C    Pr   Value Volume 
1: 111 aa  Alen   111    222
2: 111 aa  Paul   100    200
3: 111 aa  Total   NA     NA
4: 222 vv   Iva   444    555
5: 222 vv  John   333    444
6: 222 vv Total    NA     NA

这是什么原因?

我的数据结构如下:

'data.frame':   4 obs. of  5 variables:
  $ Num   : Factor w/ 2 levels "111","222": 1 1 2 2
  $ C     : Factor w/ 2 levels "aa","vv": 1 1 2 2
  $ Pr    : Factor w/ 4 levels "Alen","Iva","John",..: 1 4 2 3
  $ Value : Factor w/ 4 levels "100","111","333",..: 2 1 4 3
  $ Volume: Factor w/ 4 levels "200","222","444",..: 2 1 4 3

3 个答案:

答案 0 :(得分:4)

我们可以使用data.table。我们将'data.frame'转换为'data.table'(setDT(df1)),按'Num','C'列进行转换,并指定要在sum中执行.SDcols的列,我们使用lapply循环这些列,获取sum,并创建“Pr”列。我们可以rbind原始数据集包含新的汇总输出('DT1')和order结果基于'Num'。

library(data.table)#v1.9.5+
DT1 <- setDT(df1)[,lapply(.SD, sum) , by = .(Num,C), 
              .SDcols=Value:Volume][,Pr:='Total'][]
rbind(df1, DT1)[order(Num)]
#   Num  C    Pr Value Volume
#1: 111 aa  Alen   111    222
#2: 111 aa  Paul   100    200
#3: 111 aa Total   211    422
#4: 222 vv   Iva   444    555
#5: 222 vv  John   333    444
#6: 222 vv Total   777    999

这也可以使用base R方法完成。我们得到sum的'Value','Volume'列按'Num','C'分组,使用公式方法aggregatetransform输出创建'Pr '列,rbind包含原始数据集,order输出('res')基于'Num'。

res <- rbind(df1,transform(aggregate(.~Num+C, df1[-3], FUN=sum), Pr='Total'))
res[order(res$Num),]
#  Num  C    Pr Value Volume
#1 111 aa  Alen   111    222
#2 111 aa  Paul   100    200
#5 111 aa Total   211    422
#3 222 vv   Iva   444    555
#4 222 vv  John   333    444
#6 222 vv Total   777    999

编辑:注意到OP提到filter。如果这是一个'Num',我们subset数据,然后执行aggregatetransform步骤。

transform(aggregate(.~Num+C, subset(df1, Num==222)[-3], FUN=sum), Pr='Total')
#  Num  C Value Volume    Pr
#1 222 vv   777    999 Total

或者我们可能不需要aggregate。在subset数据之后,我们将'Num'转换为'factor',循环输出数据集('df2')获取sum,如果列为numeric类或否则我们得到第一个元素并用data.frame换行。

df2 <- transform(subset(df1, Num==222), Num=factor(Num))
data.frame(c(lapply(df2[-3], function(x) if(is.numeric(x)) 
                   sum(x) else x[1]), Pr='Total'))
#  Num  C Value Volume    Pr
#1 222 vv   777    999 Total

数据

df1 <- structure(list(Num = c(111L, 111L, 222L, 222L), C = c("aa", "aa", 
"vv", "vv"), Pr = c("Alen", "Paul", "Iva", "John"), Value = c(111L, 
100L, 444L, 333L), Volume = c(222L, 200L, 555L, 444L)), .Names = c("Num", 
"C", "Pr", "Value", "Volume"), class = "data.frame",
row.names = c(NA, -4L))

答案 1 :(得分:3)

或使用dplyr

library(dplyr)
df1 %>% 
    filter(Num == 222) %>% 
    summarise(Value = sum(Value), 
              Volume = sum(Volume), 
              Pr = 'Total', 
              Num = Num[1], 
              C = C[1]) 
#   Value Volume    Pr Num  C
# 1   777    999 Total 222 vv

我们首先filter仅保留Num == 222,然后使用summarise获取NumC的总和和值。这假定:

  • 您不希望获得每个唯一Num的结果(我在这里选择一个,您可以选择多个)。如果需要,请使用group_by
  • 每个唯一C只有一个Num

答案 2 :(得分:0)

您还可以使用dplyr包:

df %>%
  filter(Num == 222) %>%
  group_by(Num, C) %>%
  summarise(
    Pr = "Total"
    , Value = sum(Value)
    , Volume = sum(Volume)
            ) %>%
  rbind(df, .)

#   Num  C    Pr Value Volume
# 1 111 aa  Alen   111    222
# 2 111 aa  Paul   100    200
# 3 222 vv   Iva   444    555
# 4 222 vv  John   333    444
# 5 222 vv Total   777    999

如果您想要每个Num值的总和,则只需评论filter