【问题标题】:In R, unexpected result from using group_by() and summarise() in dplyr在 R 中,在 dplyr 中使用 group_by() 和 summarise() 的意外结果
【发布时间】:2017-02-27 03:32:00
【问题描述】:

我不太明白一些分组和摘要是如何使用 dplyr 包在 R 中构建的。

通过下面的可重现示例,我尝试首先按 (PN,GOT,HID) 分组以计算 PC1 的不同实例。然后,我根据第二个分组,按 (PN,GOT) 重新分组,对 PC1 的不同实例求和。这个过程似乎适用于总和,除了对于平均值(TC),当我希望通过(PN,GOT)的分组看到平均值时,我得到了整个数据帧的平均值。我缺少什么来获得(PN,GOT)的那些手段,同时又不失去我建立的 PC1 的总和?我会很感激我在这里出错的地方的一些解释。

PN<- c("Mazda","Mazda","Datsun","Hornet","Hornet","Valiant","Duster","Merc","Merc","Merc","Merc","Merc",
       "Merc","Merc","Fiat","Honda","Toyota","Toyota","Dodge","AMC","Fiat")
GOT<- c("A","A","B","C","C","A","D","B","B","B","B","B","B","B","A","D","B","B","C","E","A")
HID<- c("Mazda_H1","Mazda_H1","Datsus_H1","Hornet_H1","Hornet_H2","Valiant_H1","Duster_H1","Merc_H1","Merc_H1","Merc_H1",
        "Merc_H2","Merc_H2","Merc_H3","Merc_H4","Fiat_H1","Honda_H1","Toyota_H1","Toyota_H2","Dodge_H1","AMC_H1","Fiat_H1")
PIC<- c("BB","BB","BB","BB","AA","AA","AA","BA","BA","BA",
        "AA","BB","BB","BB","BB","AA","AA","AA","BA","BA","BA")
TC <- c(110,110,93,175,175,105,245,62,62,62,62,62,62,62,33,52,97,97,150,150,33)
Int <- c(16.46,17.02,18.61,19.44,17.02,20.22,15.84,20.00,22.90,18.30,18.90,
         17.40,17.60,18.00,19.47,18.52,19.90,20.01,16.87,17.30,18.90)
PC1<- c("", "","G1","C1","","G1","", "G1","G1","C1","C1","","","","Z1","Z1","Z1","Z1","","","G1")

df<-data.frame(PN,GOT,HID,PIC,TC,Int,PC1)

df

df%>% filter(PC1!="") %>%
  group_by(PN, GOT, HID) %>%
  summarize(new = n_distinct(PC1)) %>%
  group_by(PN, GOT) %>%
  mutate(TOT_new = sum(new),
            meanTC = mean(TC))

我认为我正在寻找的答案是这样的:

       PN    GOT        HID   TOT_new meanTC
   <fctr> <fctr>     <fctr>   <int>  <dbl>
1  Datsun      B  Datsus_H1     1     93
2    Fiat      A    Fiat_H1     2     33
3   Honda      D   Honda_H1     1     52
4  Hornet      C  Hornet_H1     1    175
5    Merc      B    Merc_H1     3     62
6  Toyota      B  Toyota_H1     2     97
7 Valiant      A Valiant_H1     1    105

或者至少是这样的:

       PN    GOT        HID   new TOT_new meanTC
   <fctr> <fctr>     <fctr> <int>   <int>  <dbl>
1  Datsun      B  Datsus_H1     1       1     93
2    Fiat      A    Fiat_H1     2       2     33
3   Honda      D   Honda_H1     1       1     52
4  Hornet      C  Hornet_H1     1       1    175
5    Merc      B    Merc_H1     2       3     62
6    Merc      B    Merc_H2     1       3     62
7  Toyota      B  Toyota_H1     1       2     97
8  Toyota      B  Toyota_H2     1       2     97
9 Valiant      A Valiant_H1     1       1    105

【问题讨论】:

  • 当您第一次group_by(PN,GOT,HID) 并总结时,未分组的变量会丢失。如果您通过summarize 单步执行前几个命令,您会看到发生了什么。也许你应该做单独的组/汇总管道和left_join 结果? (如果您提供预期的输出,将会有所帮助。)
  • @r2evans:我会尽快发布预期结果 - 谢谢。对于想要在不同摘要之间来回切换的情况,是否有任何方法可以保留或调用丢失的变量?
  • 这就是我想要找出的。什么也没看到,我会坚持我对多个管道的第一个建议(一次分组/汇总df,然后再次对df 进行完全独立的分组/汇总,然后将它们合并在一起)。

标签: r dplyr grouping summarization group-summaries


【解决方案1】:

正如@r2evans 所评论的,您获得全局平均值的原因是 TC 列在第一个汇总阶段被删除。除了注释中建议的join 选项外,您还可以通过计算两个中间变量,在第一个汇总阶段将TC 列信息向前传递:

df %>% filter(PC1 != "") %>%

    group_by(PN, GOT, HID) %>%
    # create two columns with the sum and length of TC in each group which you can use later
    # for average calculation
    summarize(new = n_distinct(PC1), n = n(), TC_sum = sum(TC)) %>%

    group_by(PN, GOT) %>%
    summarise(TOT_new = sum(new), meanTC = sum(TC_sum)/sum(n))

# Source: local data frame [7 x 4]
# Groups: PN [?]

#       PN    GOT TOT_new meanTC
#   <fctr> <fctr>   <int>  <dbl>
#1  Datsun      B       1     93
#2    Fiat      A       2     33
#3   Honda      D       1     52
#4  Hornet      C       1    175
#5    Merc      B       3     62
#6  Toyota      B       2     97
#7 Valiant      A       1    105

【讨论】:

  • 我比双管道更喜欢这个......它适用于sumsum 相关的统计信息,但当聚合不能正常工作时,您可能需要其他解决方案(例如, median)。
  • @r2evans 对,在这种情况下。如果没有加入,可能没有简单的方法来做到这一点。
  • @Psidom:这不应该按 PN 和 GOT 分组吗?为什么这些列中会有重复项(例如 Merc 和 Toyota) - 这两个列应该被分组为一个,在 TOT_new 和 meanTC 中各有一个值。似乎这样做 mutate() 需要更改为 summarise()。
  • 是的。如果不需要中间的new 列,最好使用summary,而且代码也更短。
【解决方案2】:

我们也可以使用data.table。将'data.frame'转换为'data.table'(setDT(df)),在'i'(PC1 != "")中指定逻辑条件,按'PN'、'GOT'、'HID'分组,我们得到length of unique'PC1 ('new') 的元素,每组的元素数 (.N) 和'TC' 的sum,然后按'PN'、'GOT' 分组,我们分配'new' 的sum 和'TC_sum' 的sum 与'n' 的sum 与'TOT_new' 和'meanTC' 的比率。将不需要的列分配给NULL

library(data.table)
setDT(df)[PC1 != "", .(new = uniqueN(PC1), n = .N, TC_sum = sum(TC)) ,.(PN, GOT, HID)
       ][, c("TOT_new", "meanTC") := .(sum(new), sum(TC_sum)/sum(n)) ,.(PN, GOT)
         ][, c("n", "TC_sum") := NULL][]
#        PN GOT        HID new TOT_new meanTC
#1:  Datsun   B  Datsus_H1   1       1     93
#2:  Hornet   C  Hornet_H1   1       1    175
#3: Valiant   A Valiant_H1   1       1    105
#4:    Merc   B    Merc_H1   2       3     62
#5:    Merc   B    Merc_H2   1       3     62
#6:    Fiat   A    Fiat_H1   2       2     33
#7:   Honda   D   Honda_H1   1       1     52
#8:  Toyota   B  Toyota_H1   1       2     97
#9:  Toyota   B  Toyota_H2   1       2     97

【讨论】:

  • 这个方法能不能把一开始没有马上引入的df的原始列带回来?你的解释对我来说很清楚,谢谢。
  • @val 您可以使用此数据集进行连接。如果您注意到数据集,它只有 9 行,而原始数据集有更多行。因此,这取决于您希望在输出中包含哪些值
【解决方案3】:

这是使其工作的一种方法,基于上面的一些 cmets。但它看起来是多余的。

df%>% filter(PC1!="") %>%
  group_by(PN, GOT, HID) %>%
  summarize(new = n_distinct(PC1),
            meanTC = mean(TC)) %>%
  group_by(PN, GOT) %>%
  mutate(TOT_new = sum(new),
         meanTC = mean(meanTC))%>%
  select(-HID)

       PN    GOT   new meanTC TOT_new
   <fctr> <fctr> <int>  <dbl>   <int>
1  Datsun      B     1     93       1
2    Fiat      A     2     33       2
3   Honda      D     1     52       1
4  Hornet      C     1    175       1
5    Merc      B     2     62       3
6    Merc      B     1     62       3
7  Toyota      B     1     97       2
8  Toyota      B     1     97       2
9 Valiant      A     1    105       1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-03
    • 2022-11-23
    • 2018-05-20
    • 2019-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多