case-when 字符串匹配

Case-when string matching

我有一个 df(下方)和一个向量 c("B","F"),我想首先根据 ID 将 df 拆分为列表,然后如果有任何值在列 "Name" 中匹配向量 c("B", "F") 然后为列 "Final" 分配向量中所有行的特定值。

ID  Name
1   A   
1   B   
2   C   
1   D   
2   E   
2   F
3   C

到目前为止我尝试过的如下:

df_list <- dlply(df, "ID")
df_list_2 <- lapply(df_list, transform, 
                                  Final = case_when(
                                     sum(str_count(grepl(Name, "B"))) >= 1 ~ "B",
                                     sum(str_count(grepl(Name, "F"))) >= 1 ~ "F",
                                     TRUE ~ "No"))

我的最终结果应该如下

List 1 :

ID  Name    Final
1   A         B
1   B         B
1   D         B

List 2:



ID  Name    Final

2   C         F
2   E         F
2   F         F

List 3 :

 ID Name    Final
 3      C       NO

这只是一个示例数据,我必须 运行 在数百万条记录中使用包含大约 20 个字符串值的向量列表

根据您的描述,这是一个基本的 R 想法,

lapply(split(df, df$ID), function(i) {
       i1 <- i$Name[i$Name %in% v1]; 
       data.frame(i, Final = replace(i1, length(i1) == 0, 'NO'))
      })

这给出了,

$`1`
  ID Name Final
1  1    A     B
2  1    B     B
4  1    D     B

$`2`
  ID Name Final
3  2    C     F
5  2    E     F
6  2    F     F

$`3`
  ID Name Final
7  3    C    NO

数据:

dput(df)
structure(list(ID = c(1L, 1L, 2L, 1L, 2L, 2L, 3L), Name = c("A", 
"B", "C", "D", "E", "F", "C")), row.names = c(NA, -7L), class = "data.frame")

dput(v1)
c("B", "F")

编辑: 如果你有超过 1 个最终元素,那么你可以转换为字符串,即

lapply(split(df, df$ID), function(i) {i1 <- i$Name[i$Name %in% v1]; 
                            data.frame(i, Final = ifelse(length(unique(i1)) > 1, 
                             toString(unique(i1)), ifelse(length(unique(i1)) == 0, 'NO', i1)))})

您还可以使用 dplyr 中的 group_by

library(plyr)  # Load plyr first if you use it with dplyr
library(dplyr)

match_vector <- c("B", "F")

df_new <- df %>% 
  group_by(ID) %>% 
  mutate(Final = if_else(any(Name %in% match_vector), 
                         paste(match_vector[match_vector %in% Name], collapse = ";"), 
                         "No"))

df_new
# A tibble: 7 x 3
# Groups:   ID [3]
#     ID Name  Final
#   <int> <chr> <chr>
# 1     1 A     B    
# 2     1 B     B    
# 3     2 C     F    
# 4     1 D     B    
# 5     2 E     F    
# 6     2 F     F    
# 7     3 C     No   

我在这里使用了 paste(match_vector[match_vector %in% Name], collapse = ";"),如果有多个匹配项,它将在最终列中打印所有匹配项。如果您不希望使用 match_vector[match_vector %in% Name][1] 获得第一个匹配项。

如果你需要列表结构,你可以使用 split (base R) 或 dlply (plyr):

dlply(df_new, "ID")
split(df_new, df_new$ID)

$`1`
# A tibble: 3 x 3
# Groups:   ID [1]
     ID Name  Final
  <int> <chr> <chr>
1     1 A     B    
2     1 B     B    
3     1 D     B    

$`2`
# A tibble: 3 x 3
# Groups:   ID [1]
     ID Name  Final
  <int> <chr> <chr>
1     2 C     F    
2     2 E     F    
3     2 F     F    

$`3`
# A tibble: 1 x 3
# Groups:   ID [1]
     ID Name  Final
  <int> <chr> <chr>
1     3 C     No