【问题标题】:Nesting tibbles and performing calculations on each with a group_by嵌套小标题并使用 group_by 对每个小标题执行计算
【发布时间】:2020-02-18 10:02:03
【问题描述】:

我想找出每个 id_b 的主要类别是什么。要计算它,我需要找出每个 id_b 的每个 classsize 总和。无论哪个类最大,都是分配给 id_b 的新主导类。

下面的脚本做了我想做的事,但感觉很笨重而且过于复杂。我以前很少使用嵌套数据,所以我不确定我是否使用了最好的方法 谁能想到在 tidyverse 或 data.table 中实现相同输出的更简洁的方法?

谢谢!

library(tidyverse)

# sample data
set.seed(123)
input <- tibble(id_a = c(letters[seq(1,10)]),
                size = runif(10, min = 10, max = 50),
                class = c("x","x","y","x","y",
                          "y","x","y","x","x"),
                id_b = c("A1","A1","B1","B1","B1",
                         "C1","C1","C1","D1","E1"))
print(input)

   id_a   size class id_b 
   <chr> <dbl> <chr> <chr>
 1 a      23.6 x     A1   
 2 b      43.6 x     A1   
 3 c      23.9 y     B1   
 4 d      23.4 x     B1   
 5 e      29.1 y     B1   
 6 f      45.7 y     C1   
 7 g      44.6 x     C1   
 8 h      25.6 y     C1   
 9 i      41.1 x     D1   
10 j      48.4 x     E1 
# nest input to create a nested tibble for each id_b
input_nest <- input %>% group_by(id_b) %>% nest()

# calculate dominant class
input_nest_dominant <- input_nest %>% mutate(DOMINANT_CLASS = lapply(data, function(x){
  # group each nested tibble by class, and calculate total size. Then find the biggest size and extract 
  # the class value
  output <- x %>% group_by(class) %>% 
            summarise(total_size = sum(size)) %>% 
            top_n(total_size, n = 1) %>% 
            pull(class)
  return(output)
} ))

# unnest to end up with a tibble
input_nest_dominant_clean <- input_nest_dominant %>% 
                             unnest(cols = c(DOMINANT_CLASS)) %>% 
                             select(-data) %>% 
                             ungroup()


print(input_nest_dominant_clean)
  id_b  DOMINANT_CLASS
  <chr> <chr>         
1 A1    x             
2 B1    y             
3 C1    y             
4 D1    x             
5 E1    x 

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    在这个例子中,您根本不需要nest,只需使用group_bysummarize 计算即可。

    
    input %>%
      group_by(id_b, class) %>%
      summarize(size = sum(size)) %>%
      group_by(id_b) %>%
      summarize(DOMINANT_CLASS = class[which.max(size)])
    #> # A tibble: 5 x 2
    #>   id_b  DOMINANT_CLASS
    #>   <chr> <chr>         
    #> 1 A1    x             
    #> 2 B1    y             
    #> 3 C1    y             
    #> 4 D1    x             
    #> 5 E1    x
    

    【讨论】:

    • 嗯,这很明显......谢谢!
    【解决方案2】:

    这是一个基本的 R 解决方案,它使用了两次aggregate,即,

    agg <-aggregate(size ~ class + id_b, input, FUN = sum)
    output <- aggregate(agg[-2],agg[2],FUN = max)[-3]
    

    或更紧凑的版本

    output <- aggregate(.~id_b,
                        aggregate(size ~ class + id_b, 
                                  input, 
                                  FUN = function(v) sum(v)),
                        FUN = function(v) tail(sort(v),1))[-3]
    

    这样

    > output
      id_b class
    1   A1     x
    2   B1     y
    3   C1     y
    4   D1     x
    5   E1     x
    

    【讨论】:

      【解决方案3】:

      您可以只进行 1 次排序,并删除所有重复项。比如:

      input %>% arrange(desc(size)) %>% filter(!duplicated(id_b)) %>% arrange(id_b)
      
      # A tibble: 5 x 4
        id_a   size class id_b 
        <chr> <dbl> <chr> <chr>
      1 b      41.5 x     A1   
      2 e      47.6 y     B1   
      3 h      45.7 y     C1   
      4 i      32.1 x     D1   
      5 j      28.3 x     E1  
      

      如果 id_b 的顺序不重要,可以省略最后的arrange

      或者在基础 R 中:

      input = input[order(-input$size),]
      input[!duplicated(input$id_b),]
      

      【讨论】:

        猜你喜欢
        • 2018-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-01
        • 1970-01-01
        • 2021-11-20
        • 1970-01-01
        相关资源
        最近更新 更多