【问题标题】:How to aggregate by names in two columns in R?如何按 R 中两列中的名称聚合?
【发布时间】:2020-04-02 17:50:53
【问题描述】:

我有一个数据框:

a <- c('A','A','B','B','A')
b <- c(1,1,1,1,2)
c <- c(NA,60,NA,100,NA)
d <- c(10,NA,10,NA,100)

frame <- data.frame(a,b,c,d)

> frame
  a  b   c  d
1 A  1  NA  10
2 A  1  60  NA
3 B  1  NA  10
4 B  1 100  NA
5 A  2  NA  100

我想通过 a 和 b 来聚合它

>frame2
  a  b   c  d
1 A  1  60  10
3 B  1 100  10
5 A  2  NA  100

我尝试了一些方法,例如 dplyr 中的 aggregat() 和 group,但不知何故它从来没有奏效。我猜NA是个问题。

【问题讨论】:

    标签: r merge aggregate na


    【解决方案1】:

    使用aggregate,我们可能需要使用na.action

    aggregate(.~ a + b, frame, sum, na.rm = TRUE, na.action = 'na.pass')
    #   a b   c   d
    #1 A 1  60  10
    #2 B 1 100  10
    #3 A 2   0 100
    

    如果我们打算对行进行子集化

    library(dplyr)
    frame %>% 
        group_by(a, b) %>%
        mutate_at(vars(-group_cols()), ~ .[order(is.na(.))]) %>% 
        slice(1)
    # A tibble: 3 x 4
    # Groups:   a, b [3]
    #  a         b     c     d
    #  <fct> <dbl> <dbl> <dbl>
    #1 A         1    60    10
    #2 A         2    NA   100
    #3 B         1   100    10
    

    【讨论】:

    • 起初我想知道为什么复杂,但这个dplyr 解决方案似乎是唯一一个返回NA 的解决方案,就像问题中的预期解决方案一样。
    【解决方案2】:

    使用data.tablehablar::sum_

    library(data.table)
    
    setDT(frame)[,.(c = as.numeric(hablar::sum_(c)), 
                    d = as.numeric(hablar::sum_(d))), .(a,b)]
    #>    a b   c   d
    #> 1: A 1  60  10
    #> 2: B 1 100  10
    #> 3: A 2  NA 100
    

    或者在base 中,我们可以定义自己的函数并将其与aggregate 一起使用,如他们的回答中所示的akrun

    sum__ <- function(x){if(all(is.na(x))) NA_real_ else sum(x, na.rm=T)}
    
    aggregate(.~ a + b, frame, sum__, na.action = 'na.pass')
    

    【讨论】:

      【解决方案3】:

      除了@akrun使用aggreate()之外,还可以使用下面的代码来制作:

      aggregate(frame[-(1:2)], frame[1:2], sum, na.rm = TRUE)
      

      这样

      > aggregate(frame[-(1:2)], frame[1:2], sum, na.rm = TRUE)
        a b   c   d
      1 A 1  60  10
      2 B 1 100  10
      3 A 2   0 100
      

      【讨论】:

        【解决方案4】:

        使用dplyrtidyr,您可以将数据重新整形为长格式,过滤NA 行,然后重新整形为宽格式。这基本上结合了 c 和 d 值,并保留了 c 列中的 NA

        library(dplyr)
        library(tidyr)
        
        frame %>%
          pivot_longer(c:d) %>%
          filter(!is.na(value)) %>%
          arrange(name) %>%
          pivot_wider(names_from = name)
        #> # A tibble: 3 x 4
        #>   a         b     c     d
        #>   <fct> <dbl> <dbl> <dbl>
        #> 1 A         1    60    10
        #> 2 B         1   100    10
        #> 3 A         2    NA   100
        

        IMO 的一个小烦恼是,与之前的 tidyr::spread 不同,tidyr::pivot_wider 保持数据的顺序;如果你不调用arrange,你会得到d列,然后是c,因为过滤后的观察顺序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-12-29
          • 2013-02-24
          • 1970-01-01
          • 2023-04-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-08
          相关资源
          最近更新 更多