簡體   English   中英

在 R 中跨多個列查找不同的值

[英]Finding distinct values across multiple columns in R

R 中的 distinct 函數在同一列中生成唯一值。 但是,無論值出現在哪一列,我都希望擁有唯一值。

示例數據如下所示。

10A 出現在 var 1 下的第二行。它再次出現在第三行,盡管這次它在 var 2 中。 我想刪除第三行,因為至少有一個值(10A)是重復的。

在第 5 行,第 2 行出現了 10B,所以我還想刪除第 5 行,因為至少有一個值是重復的。

在第 6 行,雖然 7A 之前在第 3 和第 5 行中出現過,但第 3 和第 5 行將被刪除,因此 7A 不被視為重復,我想保留第 6 行。

第 7 行和第 8 行具有 NA 值。 NA 不應被視為重復,因此應保留第 7 行和第 8 行。

我如何在 R 中做到這一點?

樣本數據

變量 1 變量 2
5A 5B
10A 10B
7A 10A
6B 5C
10B 7A
10℃ 7A
99A 不適用
不適用 99B

要求的結果

變量 1 變量 2
5A 5B
10A 10B
6B 5C
10℃ 7A
99A 不適用
不適用 99B

如果 df 具有 var1 和 var2 變量,並且您只想維護 var1 不同的值:

df |> 
  filter(!var2 %in% unique(var1))

更新

數據:

dt <- read.table(header=TRUE, text = "
'var1' 'var2'
'5A'   '5B2'  #1
'10A'  '10B'  #2
'7A'   '10A'  #3 - to be removed
'6B'   '5C'   #4
'10B'  '7A'   #5 - to be removed
'10C'  '7A'   #6
'99A'  'NA'   #7 - keep
'2A'   '3B'   #8
'NA'   '99B'   #9 - keep
'3A'   '11B'  #10")

循環解決方案

looper <- function(dt) {
  uniqstock <- unlist(na.omit(dt[1, 1:ncol(dt)]))
  rows2keep <- TRUE # which rows to keep
  
  # loop through data frame row by row
  for(r in 2:nrow(dt)) {
    rowdat <- na.omit(unlist(dt[r, ])) # na.omit to ignore NAs in row
    # Are *any* values in current row a duplicate to previous ones
    dupl <- any(rowdat %in% uniqstock)
    
    rows2keep <- c(rows2keep, !dupl)
    ### Set all values in current row to NA (in doing so removing them from future duplicate checks)
    if (!dupl)
      uniqstock <- c(uniqstock, rowdat)
  }
  
  dt[rows2keep,] # return but not before removing rows with NA
}

應用解決方案

applier <- function(dt) {
  uniqstock <- character()
  
  unqrows <- function(x) {
    # Are *any* values in current row a duplicate to previous ones
    dupl <- any(x %in% uniqstock)
    # Set all values in current row to NA (in doing so removing them from future duplicate checks)
    if (dupl) return(FALSE)
    
    uniqstock <<- c(uniqstock, na.omit(x))
    return(TRUE)
  }
  
  rows2keep <- apply(dt, 1, unqrows)
  dt[rows2keep,]
}

@onyambu 的遞歸解決方案,稍作修改即可正確處理NA

recursor <- function(dt) {
  relation <- function(dat){
    if(nrow(dat) == 1) dat
    else
    {
      # Include <- unlist(dat) %in% dat[1,]
      Include <- match(unlist(dat), dat[1,], nomatch = 0, incomparables = NA) > 0
      rbind(dat[1,],
            relation(dat[!tapply(Include, row(dat), sum),]))
    }
  }
  
  relation(dt)
}

基准 比較解決方案的性能,因為速度在這里很重要:

library(microbenchmark)
microbenchmark(
  looper(dt), recursor(dt), applier(dt)#, check = "equivalent"
)
#> Unit: microseconds
#>          expr    min      lq     mean median      uq     max neval
#>    looper(dt)  369.8  393.00  512.402  404.5  420.60  9094.1   100
#>  recursor(dt) 1408.5 1446.75 1725.944 1459.6 1492.75 16427.9   100
#>   applier(dt)  144.8  155.60  260.622  164.3  173.65  6143.0   100

檢查解決方案的結果

looper(dt)
#>    var1 var2
#> 1    5A  5B2
#> 2   10A  10B
#> 4    6B   5C
#> 6   10C   7A
#> 7   99A <NA>
#> 8    2A   3B
#> 9  <NA>  99B
#> 10   3A  11B
recursor(dt) # considers NA as duplicates
#>    var1 var2
#> 1    5A  5B2
#> 2   10A  10B
#> 4    6B   5C
#> 6   10C   7A
#> 7   99A <NA>
#> 8    2A   3B
#> 9  <NA>  99B
#> 10   3A  11B
applier(dt) # loses column labels
#>    var1 var2
#> 1    5A  5B2
#> 2   10A  10B
#> 4    6B   5C
#> 6   10C   7A
#> 7   99A <NA>
#> 8    2A   3B
#> 9  <NA>  99B
#> 10   3A  11B

reprex 包(v2.0.1)於 2022-06-04 創建

您可以輕松地使用遞歸來完成此操作:

relation <- function(dat){
  if(nrow(dat) == 1) dat
  else
   rbind(dat[1,],
      relation(dat[!tapply(unlist(dat) %in% dat[1,], row(dat), sum),]))
}

 relation(df)
  var.1 var.2
1    5A    5B
2   10A   10B
4    6B    5C
6   10C    7A

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM