合并数据框中的行,其中行是不相交的且包含NA值。

17

我有一个包含两行的数据框:

| code | name  | v1 | v2 | v3 | v4 |
|------|-------|----|----|----|----|
| 345  | Yemen | NA | 2  | 3  | NA |
| 346  | Yemen | 4  | NA | NA | 5  |

有没有简单的方法可以合并这两行? 如果我将“345”重命名为“346”,会不会更容易一些?


1
您需要一些规则来组合非NA列,例如您是否总是选择第一个或最后一个出现的值,在数值列中取平均值等。 - mnel
1
这里需要使用coalesce()功能。在这个帖子中找到了一个很好的讨论:[链接]https://dev59.com/WGIk5IYBdhLWcg3wdd_Y[链接] - GoodGuyIroh
2个回答

12
你可以使用 aggregate。假设你想合并列 name 中相同值的行:
aggregate(x=DF[c("v1","v2","v3","v4")], by=list(name=DF$name), min, na.rm = TRUE)
   name v1 v2 v3 v4
1 Yemen  4  2  3  5

这就像SQL中的 SELECT name, min(v1) GROUP BY namemin函数是任意的,你也可以使用maxmean,所有这些函数都将返回非NA值,如果na.rm = TRUE,则从NA和非NA值中返回。

然而,你首先应该检查给定name的所有非NA值是否相同。例如,分别使用minmax来运行aggregate并进行比较,或者使用range运行它。

最后,如果你有比v1-4更多的变量,你可以使用DF[,!(names(DF) %in% c("code","name"))]来定义列。


运行您的示例代码会出现错误:DF$name: $ operator is invalid for atomic vectors - tumultous_rooster
@MattO'Brien 你的DF是什么样子的?它是一个数据框吗?它有多个列吗?你有复制错误的代码吗? - Daniel Sparing

4

为了让内容更加完整,我们将介绍使用 dplyrdata.table解决方案。

使用 dplyr::coalesce()

library(dplyr)

sum_NA <- function(x) {if (all(is.na(x))) x[NA_integer_] else sum(x, na.rm = TRUE)}

df %>% 
  group_by(name) %>% 
  summarise_all(sum_NA)
#> # A tibble: 1 x 6
#>   name   code    v1    v2    v3    v4
#>   <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Yemen   691     4     2     3     5

# Ref: https://dev59.com/M1cO5IYBdhLWcg3wny6-#45515491
# Supply lists by splicing them into dots:
coalesce_by_column <- function(df) {
  return(dplyr::coalesce(!!! as.list(df)))
}

df %>% 
  group_by(name) %>% 
  summarise_all(coalesce_by_column)
#> # A tibble: 1 x 6
#>   name   code    v1    v2    v3    v4
#>   <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Yemen   345     4     2     3     5

使用data.table
# Ref: https://dev59.com/JV4c5IYBdhLWcg3wVpFI/
library(data.table)
setDT(df)[, lapply(.SD, na.omit), by = name]
#>     name code v1 v2 v3 v4
#> 1: Yemen  345  4  2  3  5
#> 2: Yemen  346  4  2  3  5

setDT(df)[, code := NULL][, lapply(.SD, na.omit), by = name]    
#>     name v1 v2 v3 v4
#> 1: Yemen  4  2  3  5

setDT(df)[, code := NULL][, lapply(.SD, sum_NA), by = name]
#>     name v1 v2 v3 v4
#> 1: Yemen  4  2  3  5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接