R 用NA标记冗余行

R 用NA标记冗余行,r,R,我有一个data.frame,包含完整行和不完整行,类似于: dat <- data.frame( "one" = c(1, 1, 1, 3, NA), "two" = c(2, 2, NA, 4, 4), "three" = c(1, 1, NA, 5, 5), "four" = c(2, NA, 2, 6, 6) ) dat我们可以使用 library(dplyr) library(ti

我有一个data.frame,包含完整行和不完整行,类似于:

dat <- data.frame(
  "one" = c(1, 1, 1, 3, NA),
  "two" = c(2, 2, NA, 4, 4),
  "three" = c(1, 1, NA, 5, 5),
  "four"  = c(2, NA, 2, 6, 6)
)
dat我们可以使用

library(dplyr)
library(tidyr)
dat %>% 
     fill(everything()) %>% 
     duplicated
 #[1] FALSE  TRUE  TRUE FALSE  TRUE

您可以
扫描每行的差异,构建
行和
忽略
NA
,忽略上tri和diag。从这里
行和
>0
应指示忽略
NA
的重复行

tt <- sapply(seq_len(nrow(dat)),
 function(i) rowSums(sweep(dat, 2, unlist(dat[i,])), TRUE)==0)
tt[upper.tri(tt, TRUE)] <- FALSE
rowSums(tt) > 0
#[1] FALSE  TRUE  TRUE FALSE  TRUE
还有来自@Peter Ellis的数据(谢谢!):


dat好的,我觉得这很棘手,我可能误解了这个问题。这至少是一个答案的开始。根据我的评论,这里是您原始示例的扩展版本

dat <- data.frame(
  "one" = c(1, 1, 1, 3, NA, NA),
  "two" = c(2, 2, NA, 4, 4, 9),
  "three" = c(1, 1, NA, 5, 5, 5),
  "four"  = c(2, NA, 2, 6, 6,6)
)

# desired behaviour is foo(dat) = c(FALSE, TRUE, TRUE, FALSE, TRUE, FALSE)
当一行既包含NA,又在其任何列中不包含对该列唯一的值时,所需的行为是
TRUE
(唯一的,即在我们删除将被标记为TRUE的其他行后,数据中的列的唯一值-您的问题中可能误解了一个重要的但书)

这是一个非常笨拙的解决方案。它包括一次一个单元格地遍历数据!非常不喜欢

foo <- function(d){
  # we are going to approach this backwards! You are a "good" row if you 
  # are either complete, or one of your cells is unique in its column, compared
  # to the good rows
  
  
  flag1 <- complete.cases(d)
  
  flag2 <- rep(FALSE, nrow(d))
  for(i in 1:nrow(d)){
    for(j in 1:ncol(d)){
      # check if the value in this row, col is NOT IN any of the complete cases
      # of data in other rows or rows that we are keeping
      if(!is.na(d[i, j]) && !d[i, j] %in% d[-i, j][flag1 | flag2]){
        flag2[i] <- TRUE
      }
    }
  }
  
  # so flag3 is EITHER your row is complete, OR it has a unique value
  flag3 <- (flag1 | flag2)
  
  # now we return the not-good rows, so TRUE will be redundant rows
  return(!flag3)

}
但是,我可以想到有问题的边缘情况。如果我们的最后一行数据被重复呢?我不确定这里想要的行为是什么,但是我给第一次在第二列中得到9的时候一个FALSE,然后给TRUE(因为这些是前几行的重复)。见:

>dat2dat2
1234
1   1   2     1    2
2 1 2 1 NA
3 1 NA 2
4   3   4     5    6
5 NA 4 5 6
6NA 956
7 NA 9 5 6
>傅(dat2)
[1] 假真实假真实假真实

因此,您可能需要根据您在这种情况下以及相关边缘情况下的实际期望行为对其进行编辑。但希望这给了你一个开始。

好的,用一种基于grep的方法来结束,我想这有点奇怪,但很有效:

  find_unique_combos <- function(dat) {

    na_count <- rowSums(is.na(dat))

    strings <- apply(dat, MARGIN = 1, function(row) {
      row[is.na(row)] <- '.'
      paste0(row, collapse ='')
    })
    
    sapply(seq_along(strings), function(i) {
      if(na_count[i] == 0) { return(TRUE) }
      test_targets <- strings[na_count <= na_count[i]]
      test_targets <- test_targets[!test_targets %in% strings[i]]
      !any(grepl(strings[i], test_targets))
    })

  }


find_unique_组合如果一列中有NA,但该行中的其他列与其他列不重复(如果我理解OP中的“在同一列中,它们的值等于同一列中的值,在一行中的NASs较少”部分),那么这将不起作用。@PeterEllis感谢您的澄清!希望更新现在能像预期的那样工作。也许可以在
dat-hmm上尝试您的解决方案。这似乎只是在完整的情况下设置为FALSE,unfortunately@obrl_soil那么您希望与
NA
的比较只在一个方向上起作用?像
1==NA
但是
NA!=1
?如何确定最后一行如果示例
dat
中有一行包含NA,但所需的
redundant
值为FALSE,则会更清楚,因为该行的其中一列中存在唯一值。我认为这个例子可以通过不同的方式给出预期的输出。如果这个例子能有点独特就更好了你是对的@PeterEllis,你的例子更好了-你数据中的最后一行。frame应该返回
FALSE
@akrun如果最后一行的NA是3,它会匹配上面的行。我想@akrun的解决方案比我的好得多,但我把这个留给后代。我只是没有想到填写NAs,然后从中识别重复项。我知道你要做什么,我认为你可能是正确的,但是你的函数在我的真实数据上抛出了一个索引错误<代码>错误:必须使用有效的下标向量子集列。i逻辑下标必须与索引输入的大小匹配。x输入的大小为1,但下标
flag1 | flag2`的大小为61。`切换到| |没有帮助我认为您需要一个更完整的演示数据集和对实际算法的全面描述,因为我认为如前所述存在一些歧义。这非常接近,但在某种程度上取决于行的排序顺序。有时
fill()
放置一个返回错误结果的值。@obrl\u所以,您希望如何填充NA?我根本不确定这是正确的方法-我的目标几乎是部分grep,例如,将行值连接到字符串,“12.45”应该与“12345”冗余。需要将每一行与NAs较少的任何其他行进行比较。看起来这会很快变得效率低下…@obrl_soil好的,你还有其他的解决方案。如果有帮助,请检查一下
dat <- data.frame(
  "one" = c(1, 1, 1, 3, NA, NA),
  "two" = c(2, 2, NA, 4, 4, 9),
  "three" = c(1, 1, NA, 5, 5, 5),
  "four"  = c(2, NA, 2, 6, 6,6)
)

# desired behaviour is foo(dat) = c(FALSE, TRUE, TRUE, FALSE, TRUE, FALSE)
> dat
  one two three four
1   1   2     1    2
2   1   2     1   NA
3   1  NA    NA    2
4   3   4     5    6
5  NA   4     5    6
6  NA   9     5    6
foo <- function(d){
  # we are going to approach this backwards! You are a "good" row if you 
  # are either complete, or one of your cells is unique in its column, compared
  # to the good rows
  
  
  flag1 <- complete.cases(d)
  
  flag2 <- rep(FALSE, nrow(d))
  for(i in 1:nrow(d)){
    for(j in 1:ncol(d)){
      # check if the value in this row, col is NOT IN any of the complete cases
      # of data in other rows or rows that we are keeping
      if(!is.na(d[i, j]) && !d[i, j] %in% d[-i, j][flag1 | flag2]){
        flag2[i] <- TRUE
      }
    }
  }
  
  # so flag3 is EITHER your row is complete, OR it has a unique value
  flag3 <- (flag1 | flag2)
  
  # now we return the not-good rows, so TRUE will be redundant rows
  return(!flag3)

}
> foo(dat)
[1] FALSE  TRUE  TRUE FALSE  TRUE FALSE
> dat2 <- rbind(dat, c(NA, 9, 5, 6))
> dat2
  one two three four
1   1   2     1    2
2   1   2     1   NA
3   1  NA    NA    2
4   3   4     5    6
5  NA   4     5    6
6  NA   9     5    6
7  NA   9     5    6
> foo(dat2)
[1] FALSE  TRUE  TRUE FALSE  TRUE FALSE  TRUE
  find_unique_combos <- function(dat) {

    na_count <- rowSums(is.na(dat))

    strings <- apply(dat, MARGIN = 1, function(row) {
      row[is.na(row)] <- '.'
      paste0(row, collapse ='')
    })
    
    sapply(seq_along(strings), function(i) {
      if(na_count[i] == 0) { return(TRUE) }
      test_targets <- strings[na_count <= na_count[i]]
      test_targets <- test_targets[!test_targets %in% strings[i]]
      !any(grepl(strings[i], test_targets))
    })

  }