2017-02-21 24 views
0

У меня есть кадр данных с конкатенированной строкой, последние 11 цифр которой являются переписным трактом. У меня есть отдельный список строк, в которых последние 2 или 5 цифр представляют собой состояния или округа, соответственно. Я конкатенировал * на конце идентификатора 2 или 5 цифр. Мне нужно пройти через фрейм данных и указать, является ли переменная trans (тракт переписи) в векторе patterns (состоянии или округе), позволяя * представлять остальные 9 или 6 цифр в trans.R:% in% Operator with Wildcard/REGEX

Как показано в приведенном ниже коде, я получил эту работу, свернув все pattern сек в одну строку с collapse="|" и grepl двух форм. Тем не менее, мне интересно, могу ли я выполнить это с помощью векторной операции, потому что 1) он чувствует, что я должен быть в состоянии, и 2) на практике список шаблонов огромен, и кажется глупым помещать их в один символ переменная.

Есть ли что-нибудь подобное с оператором %in%, но с поддержкой символов регулярного выражения/подстановки?

library(dplyr) 

trans <- c("1-IA-45045000100", 
      "2-IA-23003001801", 
      "3-LITP-01001000100", 
      "4-OTP-06006000606", 
      "4-OTP-06010001001", 
      "1-IA-45001010002", 
      "2-IA-45045000101", 
      "2-LITP-23005005002") 
df <- data.frame(id = 1:8, trans) 

patterns <- c("1-IA-45*", 
       "2-LITP-23005*", 
       "4-OTP-06*") 

# This works, but I'm looking for a better way 
patterns_string <- paste(patterns, collapse="|") 
df <- df %>% mutate(match = ifelse(grepl(patterns_string, df$trans), TRUE, FALSE)) 

# Is there anyway to keep the patterns in a vector and check for whether they 
# any of them grepl with each row or my data frame or to use %in% with a 
# wildcard character? 

# "argument 'pattern' has length > 1 and only first element will be used" 
df <- df %>% mutate(match = ifelse(grepl(patterns, df$trans), TRUE, FALSE)) 

# Can't take advantage of the 'wild character '*' 
df <- df %>% mutate(match = trans %in% patterns) 

ответ

4

Вы можете запускать каждый образец через grepl() через lapply(), а затем использовать Reduce() с логическим «или» оператора | объединить результаты.

df$match <- Reduce("|", lapply(patterns, grepl, df$trans)) 
df 
# id    trans match 
# 1 1 1-IA-45045000100 TRUE 
# 2 2 2-IA-23003001801 FALSE 
# 3 3 3-LITP-01001000100 FALSE 
# 4 4 4-OTP-06006000606 TRUE 
# 5 5 4-OTP-06010001001 TRUE 
# 6 6 1-IA-45001010002 TRUE 
# 7 7 2-IA-45045000101 FALSE 
# 8 8 2-LITP-23005005002 TRUE 
+0

Великого решения. Существующий OP, похоже, работает так же элегантно. Интересно, эффективен ли тот или иной компьютер? – jdobres

+0

Легко проверяемый. Но имейте в виду, что строки 'pattern' в регулярных выражениях имеют ограничение символов, поэтому' paste (..., collapse = "|") 'ограничено. –

1

Вот вариант использования tidyverse с stri_detect из stringi

library(stringi) 
library(tidyverse) 
patterns %>% 
     map(~stri_detect_regex(df$trans, .)) %>% 
     reduce(`|`) %>% 
     mutate(df, match = .) 
# id    trans match 
#1 1 1-IA-45045000100 TRUE 
#2 2 2-IA-23003001801 FALSE 
#3 3 3-LITP-01001000100 FALSE 
#4 4 4-OTP-06006000606 TRUE 
#5 5 4-OTP-06010001001 TRUE 
#6 6 1-IA-45001010002 TRUE 
#7 7 2-IA-45045000101 FALSE 
#8 8 2-LITP-23005005002 TRUE