【问题标题】:combine rows in data frame containing NA to make complete row将包含 NA 的数据框中的行组合成完整的行
【发布时间】:2018-01-12 21:20:20
【问题描述】:

我知道这是一个重复的 Q,但我似乎无法再次找到该帖子

使用以下数据

df <- data.frame(A=c(1,1,2,2),B=c(NA,2,NA,4),C=c(3,NA,NA,5),D=c(NA,2,3,NA),E=c(5,NA,NA,4))

  A  B  C  D  E
  1 NA  3 NA  5
  1  2 NA  2 NA
  2 NA NA  3 NA
  2  4  5 NA  4

A 分组,我想要使用tidyverse 解决方案的以下输出

  A  B  C  D  E
  1  2  3  2  5
  2  4  5  3  4

我在A 中有很多群组。我想我看到了一个使用 coalesce 的答案,但我不确定如何让它工作。我也想要一个与characters 一起使用的解决方案。谢谢!

【问题讨论】:

标签: r coalesce tidyverse


【解决方案1】:

我还没有弄清楚如何将coalesce_by_column 函数放入dplyr 管道中,但这可行:

coalesce_by_column <- function(df) {
  return(coalesce(df[1], df[2]))
}

df %>%
  group_by(A) %>%
  summarise_all(coalesce_by_column)

##       A     B     C     D     E
##   <dbl> <dbl> <dbl> <dbl> <dbl>
## 1     1     2     3     2     5
## 2     2     4     5     3     4

编辑:包括@Jon Harmon 为超过 2 个组成员提供的解决方案

# Supply lists by splicing them into dots:
coalesce_by_column <- function(df) {
  return(dplyr::coalesce(!!! as.list(df)))
}

df %>%
  group_by(A) %>%
  summarise_all(coalesce_by_column)

#> # A tibble: 2 x 5
#>       A     B     C     D     E
#>   <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1     1     2     3     2     5
#> 2     2     4     5     3     4

【讨论】:

  • 请查看我更新的示例,我已经编辑了我的帖子以表明我在A 中有很多组,这就是我想要dplyr 链接解决方案的原因
  • 来自 dplyr::coalesce 帮助: # 通过将列表拼接成点来提供列表: vecs
  • 看起来这不适用于字符列。只是价值。
【解决方案2】:

我们可以使用fill 来填充所有缺失值。然后为每个组过滤一行。

library(dplyr)
library(tidyr)

df2 <- df %>%
  group_by(A) %>%
  fill(everything(), .direction = "down") %>%
  fill(everything(), .direction = "up") %>%
  slice(1)

感谢@Roger-123,上面的代码可以进一步简化如下。

df2 <- df %>%
  group_by(A) %>%
  fill(everything(), .direction = "downup") %>%
  slice(1)

【讨论】:

  • 这是简单的最佳答案,并提供了一个基于 tidyverse 的答案,正如原始问题所要求的那样。
  • 这也可以通过将第一条填充线从"down"更改为"downup"并删除第二条填充线来简化。
  • @Roger-123 感谢您的评论。我刚刚更新了包含您的建议的帖子。
【解决方案3】:

不是tidyverse,但这是一个基本的 R 解决方案

df <- data.frame(A=c(1,1),B=c(NA,2),C=c(3,NA),D=c(NA,2),E=c(5,NA))
sapply(df, function(x) x[!is.na(x)][1])
#A B C D E 
#1 2 3 2 5 

更新数据

do.call(rbind, lapply(split(df, df$A), function(a) sapply(a, function(x) x[!is.na(x)][1])))
#  A B C D E
#1 1 2 3 2 5
#2 2 4 5 3 4

【讨论】:

  • 谢谢,这可以在mutate 声明中使用。不过,我会等待其他一些答案
【解决方案4】:

这是一个更通用的解决方案(使用uniquena.omit 来排序创建coalesce),它可以处理超过两行的重叠信息。超级简单转发。

> df <- data.frame(A=c(1,1,2,2,2),B=c(NA,2,NA,4,4),C=c(3,NA,NA,5,NA),D=c(NA,2,3,NA,NA),E=c(5,NA,NA,4,4))

> df
  A  B  C  D  E
1 1 NA  3 NA  5
2 1  2 NA  2 NA
3 2 NA NA  3 NA
4 2  4  5 NA  4
5 2  4 NA NA  4

> df %>% group_by(A) %>% summarise_all(funs( na.omit(unique(.)) ))
# A tibble: 2 x 5
      A     B     C     D     E
  <dbl> <dbl> <dbl> <dbl> <dbl>
1     1     2     3     2     5
2     2     4     5     3     4

【讨论】:

    【解决方案5】:

    tidyverse 的另一种可能性可能是:

    df %>%
     gather(var, val, -A, na.rm = TRUE) %>%
     group_by(A, var) %>%
     distinct(val) %>%
     spread(var, val)
    
          A     B     C     D     E
      <dbl> <dbl> <dbl> <dbl> <dbl>
    1     1     2     3     2     5
    2     2     4     5     3     4
    

    在这里,它首先执行从宽到长的数据转换,不包括“A”列并删除缺失值。其次,它按“A”列和变量名分组。第三,它删除了重复的值。最后,它将数据返回到其原始的宽格式。

    【讨论】:

      【解决方案6】:

      这在功能上与@Oriol Mirosa 的答案相同,不需要自定义函数:

      编辑:必须根据@thelatemail 的评论省略 NA。 @MrFlick 在上面链接的重复线程中也给出了这个答案。

      df %>% group_by(A) %>% summarise_all(~first(na.omit(.)))
      

      我想补充一点,因为它似乎经常出现在我身上,而且我已经多次重温这个帖子。 @Oriol Mirosa 的回答很有效,但是我很抗拒它,因为它太复杂以至于难以记住(因此我回到了这个帖子)。

      就我个人而言,我也不喜欢编写不需要的小型自定义函数。尝试用实际的coalesce 调用替换coalesce_by_column 会导致类型错误(我觉得这很奇怪,因为行没有相互交互,但无论如何)。这可以通过首先执行 mutate_all(as.character) 来解决,但我的目标是尽量减少语法,以便在运行中轻松记住它。

      此外,这种替换会改变行为,使得列中的不同值会引发错误(为什么有时函数中的行为会略有不同,这超出了我的理解)。在某些情况下,这种行为可能是首选,但在这种情况下,我会推荐 @Jerry T 的解决方案,因为没有自定义函数,并且使用的函数是熟悉的、可读的,并且它们的顺序(na.omitunique)是'不相关。

      【讨论】:

      • 如果NA 恰好是第一个值,这会在输出中给出一堆NA 值。
      • 谢谢我昨晚没听懂
      猜你喜欢
      • 2012-12-25
      • 2013-06-15
      • 1970-01-01
      • 2013-08-09
      • 1970-01-01
      • 2021-06-02
      • 2011-12-20
      • 1970-01-01
      相关资源
      最近更新 更多