Случай-когда совпадение строк - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть df (ниже) и вектор как c ("B", "F"), я хочу сначала разделить df как список на основе идентификатора, а затем, если любое из значений в столбце "Имя" совпадает в векторе 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 строковых значений

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Вы также можете использовать group_by из dplyr:

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 
0 голосов
/ 09 ноября 2018

Вот базовая идея 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)))})
...