如何在R中按两列中的名称聚合?

8aqjt8rx  于 2023-04-03  发布在  其他
关注(0)|答案(4)|浏览(110)

我得到一个数据框:

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

我尝试了一些东西,比如aggregat()和dplyr的group,但不知何故,它从来没有工作过。

fhg3lkii

fhg3lkii1#

对于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
zlhcx6iw

zlhcx6iw2#

  • 使用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')
5hcedyr0

5hcedyr03#

除了@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
xxb16uws

xxb16uws4#

使用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,因为过滤后的观察顺序。

相关问题