计算字符串中逗号分隔的唯一值

Count comma separated unique values in a string

dataframe 的前两列构成了一个复合键,还有一列包含逗号分隔的整数的 char 类型。我的 objective 是创建一个列,其中包含字符串中唯一整数的计数。 我知道使用 str_split_fixed 将字符串转换为列然后计算唯一值的方法,但由于字符串的长度,添加了大量列并且一切都滞后。还有其他方法吗? 实际数据集包含 500k 行和 53 列。 示例数据集:
df

c1      c2    c3  
aa      11   1,13,4,5,4,7,9    
bb      22   2,5,2,4,5,7,11,     
cc      33   11,14,3,1,    
dd      44   1,1,2,4,5,6,15,    
ee      55   4,3,3,1,14,17,

期望的输出:

c1        c2             c3             c4  
------ | ------   | ------          | -----   
aa     | 11       | 1,13,4,5,4,7,9  |  6    
------ | ------   | ------          | -----   
bb     | 22       | 2,5,2,4,5,7,11, |  5   
------ | ------   | ------          | -----   
cc     | 33       | 11,14,3,1,      |  4   
------ | ------   | ------          | -----   
dd     | 44       | 1,1,2,4,5,6,15, |  6       
------ | ------   | ------          | -----   
ee     | 55       | 4,3,3,1,7,17,7, |  5    
------ | ------   | ------          | -----  

如有任何帮助,我们将不胜感激!

我们可以用stri_extract提取所有的数字,然后遍历list,找到unique个元素的length

library(stringi)
df1$Count <- sapply(stri_extract_all_regex(df1$col3, "[0-9]+"), 
                     function(x) length(unique(x)))

假设您的 df 如下所示:

df <- c("1,13,4,5,4,7,9,", "2,5,2,4,5,7,11,","11,14,3,1,4,"," 1,1,2,4,5,6,15,","4,6,3,3,1,14,17,14,")
df <- gsub("\s+|,$","",df) ##Removal of unnecssary spaces and trailing commas

然后你可以使用 baseR :

unlist(lapply(strsplit(df,split=","),function(x)length(unique(x))))

结果会是这样的:

[1] 6 5 5 6 6

strsplitdata.table 软件包中的 uniqueN 一起使用:

df$c4 <- sapply(strsplit(df$c3,','), uniqueN)

给出:

> df
  c1 c2              c3 c4
1 aa 11  1,13,4,5,4,7,9  6
2 bb 22 2,5,2,4,5,7,11,  5
3 cc 33      11,14,3,1,  4
4 dd 44 1,1,2,4,5,6,15,  6
5 ee 55  4,3,3,1,14,17,  5

注意:如果 df$c3 是因子变量,请将其包装在 as.character 中:sapply(strsplit(as.character(df$c3), ','), uniqueN)


用于创建 df$c4 的另一个基本 R 替代方案:

sapply(regmatches(df$c3, gregexpr('\d+', df$c3)), function(x) length(unique(x)))

一个tidyverse备选方案:

library(dplyr)
library(tidyr)
df %>% 
  separate_rows(c3) %>% 
  filter(c3 != '') %>% 
  group_by(c1) %>% 
  summarise(c4 = n_distinct(c3)) %>% 
  left_join(df, .)