在每一列中找到唯一的行并在 r 中标记它们

find unique rows in every column and mark them in r

我有一个包含 1000 行和几列的数据框,我想在其中找到唯一的行并标记每列是否具有唯一值。

例如,我有一个如下所示的数据框。

数据框:structure(list(X = c("Row1", "Row2", "Row3", "Row4", "Row5", "Row6", "Row7"), Col1 = c(0L, 1L, 1L, 0L, 1L, -1L, 0L), Col2 = c(1L, 0L, 1L, 1L, 1L, 0L, -2L), Col3 = c(-1L, 0L, 1L, 0L, 0L, 1L, 1L )), class = "data.frame", row.names = c(NA, -7L))

      Col1 Col2 Col3
Row1    0   1   -1
Row2    1   0   0
Row3    1   1   1
Row4    0   1   0
Row5    1   1   0
Row6    -1  0   1
Row7    0   -2  1

我想获取以下数据框。

        Col1  Col2  Col3    Col1_uni    Col2_uni    Col3_uni
 Row1   0      1    -1      Col1        Col2        Col3
Row2    1      0    0       Col1        NA           NA
Row3    1      1    1       NA          NA           NA
Row4    0      1    0       NA          Col2         NA
Row5    1      1    0       NA          NA           NA
Row6    -1     0    1       Col1       Col2         Col3
Row7    0     -2    1       Col1       Col2         Col3

我已经尝试过 df=df[row.names(unique(df[,c("clo_2")])), c("clo_2")] 但那并不是真的 helps.I 希望有人对此有一个简单的解决方案。提前致谢。

这是一个给出逻辑值但不考虑列名的例子。如有必要,您可以轻松修改以提供向量的名称。它只是应用一个函数来逐行检查

df <- structure(list(Col1 = c(0, 1, 1, 0, 1, -1, 0),
                     Col2 = c(1, 0, 1, 1, 1, 0, -2),
                     Col3 = c(-1, 0, 1, 0, 0, 1, 1)),
                row.names = c(NA, -7L),
                class = c("tbl_df", "tbl", "data.frame"))

chk <- apply(df, 1, function(x) !x %in% x[duplicated(x)])
cbind(df, t(chk))
#>   Col1 Col2 Col3     1     2     3
#> 1    0    1   -1  TRUE  TRUE  TRUE
#> 2    1    0    0  TRUE FALSE FALSE
#> 3    1    1    1 FALSE FALSE FALSE
#> 4    0    1    0 FALSE  TRUE FALSE
#> 5    1    1    0 FALSE FALSE  TRUE
#> 6   -1    0    1  TRUE  TRUE  TRUE
#> 7    0   -2    1  TRUE  TRUE  TRUE

我们可以使用 dplyrrowwise():

library(dplyr)
df %>% rowwise %>%
  mutate(across(starts_with('Col'), ~ sum(c_across(starts_with('Col')) == .x), .names = "{.col}_uni"),
         across(ends_with('uni'), ~ifelse(.x==1, str_remove(deparse(substitute(.x)), '_uni$'), NA)))

# A tibble: 7 × 7
# Rowwise: 
  X      Col1  Col2  Col3 Col1_uni Col2_uni Col3_uni
  <chr> <int> <int> <int> <chr>    <chr>    <chr>   
1 Row1      0     1    -1 Col1     Col2     Col3    
2 Row2      1     0     0 Col1     NA       NA      
3 Row3      1     1     1 NA       NA       NA      
4 Row4      0     1     0 NA       Col2     NA      
5 Row5      1     1     0 NA       NA       Col3    
6 Row6     -1     0     1 Col1     Col2     Col3    
7 Row7      0    -2     1 Col1     Col2     Col3 

我还推荐@caldwellst 建议的更简单的“col_names-less”方法,我的回答中的简化代码是:

libarry(dplyr)

df %>% rowwise %>%
  mutate(across(starts_with('Col'),
                ~sum(c_across(starts_with('Col')) == .x) == 1,
                .names = "{.col}_uni"))

# A tibble: 7 × 7
# Rowwise: 
  X      Col1  Col2  Col3 Col1_uni Col2_uni Col3_uni
  <chr> <int> <int> <int> <lgl>    <lgl>    <lgl>   
1 Row1      0     1    -1 TRUE     TRUE     TRUE    
2 Row2      1     0     0 TRUE     FALSE    FALSE   
3 Row3      1     1     1 FALSE    FALSE    FALSE   
4 Row4      0     1     0 FALSE    TRUE     FALSE   
5 Row5      1     1     0 FALSE    FALSE    TRUE    
6 Row6     -1     0     1 TRUE     TRUE     TRUE    
7 Row7      0    -2     1 TRUE     TRUE     TRUE  

A base R 解决方案,按行应用

data.frame( dat, setNames( data.frame( t(apply( dat, 1, function(x){ 
   tf=!duplicated(x, fromLast=F)&!duplicated(x, fromLast=T);
   ifelse( tf,colnames(dat)[tf],NA) } ) )), paste0(colnames(dat),"_uni") ) )

     Col1 Col2 Col3 Col1_uni Col2_uni Col3_uni
Row1    0    1   -1     Col1     Col2     Col3
Row2    1    0    0     Col1     <NA>     <NA>
Row3    1    1    1     <NA>     <NA>     <NA>
Row4    0    1    0     <NA>     Col2     <NA>
Row5    1    1    0     <NA>     <NA>     Col3
Row6   -1    0    1     Col1     Col2     Col3
Row7    0   -2    1     Col1     Col2     Col3

数据

dat <- structure(list(Col1 = c(0L, 1L, 1L, 0L, 1L, -1L, 0L), Col2 = c(1L, 
0L, 1L, 1L, 1L, 0L, -2L), Col3 = c(-1L, 0L, 1L, 0L, 0L, 1L, 1L
)), class = "data.frame", row.names = c("Row1", "Row2", "Row3", 
"Row4", "Row5", "Row6", "Row7"))