【问题标题】:How to remove duplicated rows and columns from a data frame disregarding NAs?如何在不考虑 NA 的情况下从数据框中删除重复的行和列?
【发布时间】:2019-07-03 00:19:43
【问题描述】:

我想从数据框中删除重复的列,而不考虑 NA。数据框的所有列都是长度相等的数字向量。这是一个例子:

> df <- data.frame(a = c(1,2,NA,4,4), b= c(5,6,7,8,8), c= c(5,6,7,8,8), d = c(9,8,7,6,NA), e = c(NA,8,7,6,6))
> df
   a b c  d  e
1  1 5 5  9 NA
2  2 6 6  8  8
3 NA 7 7  7  7
4  4 8 8  6  6
5  4 8 8 NA  6

结果我想得到这个数据框:

> df_clear
   a b d
1  1 5 9
2  2 6 8
3 NA 7 7
4  4 8 6

我尝试过“唯一”,但没有任何成功。只删除了没有 NA 的重复项。

> df_clear <- 
+   df %>%
+     unique %>%
+     t %>%
+     as.matrix %>%
+     unique %>%
+     t %>%
+     as.data.frame
> df_clear
   a b  d  e
1  1 5  9 NA
2  2 6  8  8
3 NA 7  7  7
4  4 8  6  6
5  4 8 NA  6

dplyr 中的“distinct”也没有帮助。我什至用这种方法丢失了列名,这是一个问题。

> df_clear <- 
+   df %>%
+     distinct %>%
+     t %>%
+     as.data.frame %>%
+     distinct %>%
+     t %>%
+     as.data.frame
> df_clear
   V1 V2 V3 V4
V1  1  5  9 NA
V2  2  6  8  8
V3 NA  7  7  7
V4  4  8  6  6
V5  4  8 NA  6

我想知道是否有任何功能可以完成这项工作,或者我应该为自己编写它。真实的数据框有超过 1000 行和列。

非常感谢您的帮助!

编辑

阅读 cmets 后,我意识到我对原始问题的定义不足。这里有一些澄清。为了简单起见,我只关注行:
- 在重复的情况下,剩余行应包含尽可能少的 NA。例如。 df1 应该显示为 df1_clear

> df1
   a b  d e
1  1 4  7 1
2  3 6 NA 3
3  2 5  8 2
4 NA 6  9 3
> df1_clear
  a b d e
1 1 4 7 1
2 2 5 8 2
3 3 6 9 3
  • 重复项不一定是连续的。
  • 连续可能有多个 NA。

【问题讨论】:

  • 我不清楚您要求的输出是否定义明确。为什么删除第 5 行并在结果中包含 d 列,而不是删除第 1 行并包含 e 列?
  • 感谢您的提问。我已经编辑了原始帖子以澄清这一点。
  • 您的编辑引入了显然需要的记录合并,这使您尝试做的事情变得复杂。我仍然不清楚所需的输出到底是什么。例如,给定df &lt;- data.frame(a=c(1,2,NA,NA), b=c(NA,NA,4,5),c=c(9,9,9,9))df_clear 会是什么样子?如果有多个选项,您将如何从其他匹配的行中填写 NA?
  • 我也没有想到,非常感谢您的提问!在这种情况下,我不会合并任何一行。我还意识到,在某些情况下,行和列的合并顺序(即行优先或列优先)可能会导致不同的结果。我不希望我的数据如此模棱两可,但我永远无法知道。因此,根据您的问题,首先我将检查是否存在这种歧义。如果是,我将分别查看这些行和列,并尝试找到解释并相应地合并特定的行和列。然后,我将对整个数据集进行合并。

标签: r


【解决方案1】:

以下内容有点复杂,但可以完成工作。
它在fun 中调用一个函数两次,以删除原始数据帧的重复项,然后是其转置。

fun <- function(DF){
  f <- function(DF1){
    df1 <- DF1
    df1[] <- lapply(df1, function(x){
      y <- zoo::na.locf(x)
      if(length(y) < length(x)) y <- zoo::na.locf(x, fromLast = TRUE)
      y
    })
    DF1[!duplicated(df1), ]
  }
  df2 <- f(DF)
  df2 <- as.data.frame(t(df2))
  df2 <- t(f(df2))
  as.data.frame(df2)
}

fun(df)
#   a b d
#1  1 5 9
#2  2 6 8
#3 NA 7 7
#4  4 8 6

基于上述,可以使用fundplyr 管道中的函数f() 来实现。下面的函数f()只是上面函数的复制粘贴。

library(dplyr)


f <- function(DF1){
  df1 <- DF1
  df1[] <- lapply(df1, function(x){
    y <- zoo::na.locf(x)
    if(length(y) < length(x)) y <- zoo::na.locf(x, fromLast = TRUE)
    y
  })
  DF1[!duplicated(df1), ]
}


df %>%
  f() %>% t() %>% as.data.frame() %>%
  f() %>% t() %>% as.data.frame()

#   a b d
#1  1 5 9
#2  2 6 8
#3 NA 7 7
#4  4 8 6

【讨论】:

  • 感谢您的回答!据我了解,它仅适用于连续的行/列。我没有在原始帖子中指定重复项不一定是连续的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-13
  • 2022-12-22
相关资源
最近更新 更多