Почему `str_extract` захватывает только некоторые из этих значений? - PullRequest
2 голосов
/ 17 апреля 2020

У меня есть таблица со столбцом «тип членства», который включает в себя миллионы различных уровней членства, которые мы использовали на протяжении многих лет.

example <-data.frame(membership = c( "Legacy Payment ID #3564, Payment Record #0, Period Paid: 1 Flag: N", 
                              "Legacy Payment ID #3611, Payment Record #0, Period Paid: 2 Flag: N", 
                              "Legacy Payment ID #4105, Payment Record #0, Period Paid: 1 Flag: G",
                              "Legacy Payment ID #4136, Payment Record #0, Period Paid: 1 Flag: N", 
                              "Legacy Payment ID #5191, Payment Record #0, Period Paid: 1 Flag: N ", 
                              "Individual (2 yr)",
                              "Individual Producer (Yearly)",
                              "Student Membership (Yearly)"  ))

Я ожидаю, что смогу добавить второй столбец, по крайней мере, с грубым набором возможных значений для члена членства с str_extract:

library(stringr)
example$term <-  example$membership %>% 
  str_extract(c("Period Paid: 1","Period Paid: 2","Yearly", "2 yr"))

Но это только ловит половину значений, и я не могу найти образец в том, что он пропускает.

1   Legacy Payment ID #3564, Payment Record #0, Period Paid: 1 Flag: N  Period Paid: 1
2   Legacy Payment ID #3611, Payment Record #0, Period Paid: 2 Flag: N  Period Paid: 2
3   Legacy Payment ID #4105, Payment Record #0, Period Paid: 1 Flag: G  NA
4   Legacy Payment ID #4136, Payment Record #0, Period Paid: 1 Flag: N  NA
5   Legacy Payment ID #5191, Payment Record #0, Period Paid: 1 Flag: N  Period Paid: 1
6   Legacy Payment ID #5238, Payment Record #0, Period Paid: 1 Flag: N  NA
7   Legacy Payment ID #5287, Payment Record #0, Period Paid: 1 Flag: N  NA
8   Legacy Payment ID #5306, Payment Record #0, Period Paid: 1 Flag: N  NA
9   Legacy Payment ID #5739, Payment Record #0, Period Paid: 2 Flag: G  NA
10  Individual (2 yr)                                                   NA
11  Individual Producer (Yearly)                                        Yearly
12  Student Membership (Yearly)                                         NA

Единственная разница между строкой 4 и строкой 5 - это идентификатор платежа. Почему он находит только значение для поиска в строке 5?

И как мне это исправить. Но в основном почему?

Ответы [ 2 ]

1 голос
/ 17 апреля 2020

Вы можете использовать более сложное регулярное выражение, используя lookbehind и lookahead:

example$term <-  example$membership %>% 
    str_extract("Period Paid: \\d+|(?<=\\().*(?=\\))")

Вывод:

example
                                                           membership           term
1  Legacy Payment ID #3564, Payment Record #0, Period Paid: 1 Flag: N Period Paid: 1
2  Legacy Payment ID #3611, Payment Record #0, Period Paid: 2 Flag: N Period Paid: 2
3  Legacy Payment ID #4105, Payment Record #0, Period Paid: 1 Flag: G Period Paid: 1
4  Legacy Payment ID #4136, Payment Record #0, Period Paid: 1 Flag: N Period Paid: 1
5 Legacy Payment ID #5191, Payment Record #0, Period Paid: 1 Flag: N  Period Paid: 1
6                                                   Individual (2 yr)           2 yr
7                                        Individual Producer (Yearly)         Yearly
8                                         Student Membership (Yearly)         Yearly
0 голосов
/ 17 апреля 2020

Мы можем свернуть его в одну строку с помощью |

library(stringr)
library(dplyr)
pattern_vec <- c("Period Paid: 1","Period Paid: 2","Yearly", "2 yr")
example%>% 
      mutate(term = str_extract(membership,
      str_c(pattern_vec, collapse="|")))
#                                                       membership           term
#1  Legacy Payment ID #3564, Payment Record #0, Period Paid: 1 Flag: N Period Paid: 1
#2  Legacy Payment ID #3611, Payment Record #0, Period Paid: 2 Flag: N Period Paid: 2
#3  Legacy Payment ID #4105, Payment Record #0, Period Paid: 1 Flag: G Period Paid: 1
#4  Legacy Payment ID #4136, Payment Record #0, Period Paid: 1 Flag: N Period Paid: 1
#5 Legacy Payment ID #5191, Payment Record #0, Period Paid: 1 Flag: N  Period Paid: 1
#6                                                   Individual (2 yr)           2 yr
#7                                        Individual Producer (Yearly)         Yearly
#8                                         Student Membership (Yearly)         Yearly

str_extract векторизовано как для «строки», так и для «шаблона», за исключением того, что если есть вектор length> 1 в 'pattern', тогда будет выполняться поэлементное совпадение, т.е. 1-е значение 'members' к 1-му значению pattern, 2-е до 2-го и т. д. Здесь, в случае OP, длины отличаются, т.е. длина столбца отличается от длины шаблона. Итак, вектор шаблона выполняет рециркуляцию, повторяя ее с начала после строки 4.

Чтобы проверить рециркуляцию, вы можете использовать rep, чтобы повторить pattern_vec и проверить вывод:

out1 <- example %>% 
      mutate(term = str_extract(membership, rep(pattern_vec, length.out = n())))

out2 <- example %>% 
            mutate(term = str_extract(membership,  pattern_vec))
identical(out1, out2)
#[1] TRUE



out1
#                                                           membership           term
#1  Legacy Payment ID #3564, Payment Record #0, Period Paid: 1 Flag: N Period Paid: 1
#2  Legacy Payment ID #3611, Payment Record #0, Period Paid: 2 Flag: N Period Paid: 2
#3  Legacy Payment ID #4105, Payment Record #0, Period Paid: 1 Flag: G           <NA>
#4  Legacy Payment ID #4136, Payment Record #0, Period Paid: 1 Flag: N           <NA>
#5 Legacy Payment ID #5191, Payment Record #0, Period Paid: 1 Flag: N  Period Paid: 1
#6                                                   Individual (2 yr)           <NA>
#7                                        Individual Producer (Yearly)         Yearly
#8                                         Student Membership (Yearly)           <NA>

Примечание от OP:

Сообщение на RStudio Community , которое помогло мне (OP) понять объяснение выше:

При подаче с одним шаблоном str_replace_all будет сравнивать этот шаблон с каждым элементом. Однако, если вы передадите ему вектор, он будет пытаться соблюдать порядок, поэтому сравните первый шаблон с первым объектом, а затем второй шаблон со вторым объектом.

...