【问题标题】:summarize for all other values per group in dplyr汇总 dplyr 中每组的所有其他值
【发布时间】:2020-02-17 00:00:13
【问题描述】:

我有一个数据集,其中包含分组做出的个人决定。对于每个人,我需要他/她的小组成员的所有决定的汇总(比如说总和)。 所以假设数据看起来像:

set.seed(123)
group_id <- c(sapply(seq(1, 3), rep, times = 3))
person_id <- rep(seq(1,3),3)
decision <- sample(1:10, 9, replace=T)
df <-data.frame(group_id, person_id, decision)
df

结果是:

  group_id person_id decision
1        1         1        3
2        1         2        8
3        1         3        5
4        2         1        9
5        2         2       10
6        2         3        1
7        3         1        6
8        3         2        9
9        3         3        6

我需要制作类似的东西:

  group_id person_id decision others_decision
1        1         1        3 13
2        1         2        8  8
3        1         3        5 11

因此,对于组中的每个元素,我让同一组的所有其他成员做某事(总和)。我可以只用一个for 循环来做到这一点,但它看起来丑陋且效率低下。有没有更好的解决方案?

更新:

这是我目前想出的解决方案,丑陋见谅:

df$other_decision=unlist(by(df, 1:nrow(df), function(row) {
  df %>% filter(group_id==row$group_id, person_id!=row$person_id) %>% summarize(sum(decision))
}
  ))
df

【问题讨论】:

  • 如果它“只是”一个sumdf %&gt;% group_by(group_id) %&gt;% mutate(other = sum(decision) - decision)

标签: r dplyr


【解决方案1】:

你可以这样做:

df %>%
 inner_join(df, by = c("group_id" = "group_id")) %>%
 filter(person_id.x != person_id.y) %>%
 group_by(group_id, person_id = person_id.x) %>%
 summarise(decision = first(decision.x),
           others_decison = sum(decision.y))

  group_id person_id decision others_decison
     <int>     <int>    <int>          <int>
1        1         1        3             13
2        1         2        8              8
3        1         3        5             11
4        2         1        9             11
5        2         2       10             10
6        2         3        1             19
7        3         1        6             15
8        3         2        9             12
9        3         3        6             15

根据您的实际数据集(其大小),它可能会在计算上变得相当苛刻,因为它涉及内部连接。

不涉及内部连接的另一种可能性是:

df %>% 
 group_by(group_id) %>% 
 mutate(others_decison = list(decision),
        rowid = 1:n()) %>%
 ungroup() %>%
 rowwise() %>%
 mutate(others_decison = sum(unlist(others_decison)[-rowid])) %>%
 ungroup() %>%
 select(-rowid)

【讨论】:

  • 这是一个非常好的解决方案,而且它有效。尽管在将其标记为解决方案之前我可能会稍等片刻:在我的 mre 比中等数据集中有 2400 条记录。所以 inner_joint 将产生一个包含 5760000 条记录的数据集,这没关系,但对于较大的数据集,这可能是一个问题,不是吗?
  • 是的,对于大型和非常大的数据集,它可能非常低效。也许有人会发布更有效的可能性:)
【解决方案2】:

这可以通过创建一个函数来完成,该函数将函数作为参数并依次从传递给它的向量中删除每个观察值。

library(dplyr)

my_summarise <- function(x, FUN, ...) {
  sapply(seq_along(x), function(y)
    FUN(x[-y], ...))
} 

df %>%
  group_by(group_id) %>%
  mutate(dsum = my_summarise(decision, sum),
         dmean = my_summarise(decision, mean),
         dmax = my_summarise(decision, max))

# A tibble: 9 x 6
# Groups:   group_id [3]
  group_id person_id decision  dsum dmean  dmax
     <int>     <int>    <int> <int> <dbl> <int>
1        1         1        3    13   6.5     8
2        1         2        8     8   4       5
3        1         3        5    11   5.5     8
4        2         1        9    11   5.5    10
5        2         2       10    10   5       9
6        2         3        1    19   9.5    10
7        3         1        6    15   7.5     9
8        3         2        9    12   6       6
9        3         3        6    15   7.5     9

【讨论】:

    【解决方案3】:

    这里有几个 方法:

    library(data.table)
    dt <- as.data.table(df)
    
    # don't update original dt
    dt[dt, on = .(group_id), allow.cartesian = T
       ][person_id != i.person_id,
         .(decison = first(i.decision), others = sum(decision)),
         by = .(group_id, person_id = i.person_id)]
    
    #update the original dt way 1
    dt[,
       others_decision := .SD[.SD, on = .(group_id), allow.cartesian = T
                              ][person_id != i.person_id, sum(decision), by = .(group_id,i.person_id)]$V1
       ]
    
    #update the original dt way 2
    dt1[, 
       others_decision := dt[group_id == .BY[[1]] & person_id != .BY[[2]], sum(decision)],
       by = .(group_id, person_id)]
    

    前两个主要的事情或多或少是@tmfmnk 的方法,但通过data.table。最后一个对我来说更直观,但可能是最慢的。

    【讨论】:

      猜你喜欢
      • 2022-01-06
      • 2016-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-20
      • 1970-01-01
      • 2016-07-26
      • 2022-07-21
      相关资源
      最近更新 更多