[英]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.