Найдите, присутствуют ли значения в нескольких столбцах в строке

#r #string #detect

Вопрос:

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

Примеры данных:

 string.to.search<-c("abc","bc","cd","e","f")
Drug1<-c("b","c","e","f",NA)
Drug2<-c("c","d",NA,NA,NA)
Drug3<-c(NA,NA,NA,NA,NA)

df<-as.data.frame(cbind(string.to.search, Drug1, Drug2, Drug3))
 

Я могу сделать это достаточно легко, обращаясь к столбцам, которые я хочу использовать в качестве поисковых запросов (в данном случае от 1 до 3), и достичь желаемого результата:

 df.new<-df%>%
  mutate(Found = str_detect(string.to.search, paste(Drug1, Drug2, Drug3, sep="|")))
 
Строка.для.поиска Наркотик1 Лекарство2 Лекарство3 Нашел
a b c b c истинный
в с c d истинный
c d e ложный
e f ложный
f ложный

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

 df.new2<-df%>%
  mutate(Found = str_detect(string.to.search, .[[2]]))
 
Строка.для.поиска Наркотик1 Лекарство2 Лекарство3 Нашел
a b c b c истинный
в с c d истинный
c d e ложный
e f ложный
f

Я не могу понять, как заставить это работать с несколькими индексами столбцов, чтобы я мог перейти от второго к последнему столбцу (у меня может быть 1 препарат или в будущем может быть 10). Когда я пытаюсь это сделать, я получаю следующую ошибку:

 df.new3<-df%>%
  mutate(Found = str_detect(string.to.search, .[[2:ncol(df)]]))
 

Ошибка: Проблема с mutate() колонкой Found .
i Found = str_detect(string.to.search, .[[2:ncol(df)]]) .
x сбой рекурсивной индексации на уровне 2

Когда я просто смотрю на то , что возвращается df[2:ncol(df)] , только три столбца с лекарствами возвращаются, как ожидалось, поэтому я чувствую, что должен использовать правильные индексы.

Любая помощь будет очень признательна.

  • ps Я пробовал аналогичный код с grepl и получил те же результаты, но я рад использовать его вместо str_detect, если это более логично.

Комментарии:

1. Если все ваши лекарства не всегда состоят из отдельных букв, то я полагаю, что ваши выборочные данные могут быть чрезмерно упрощены: совпадения подстрок могут давать ложные срабатывания.

Ответ №1:

Если у вас string.to.search всегда есть пробелы (или что-то легко разделяемое), мы можем использовать %in% вместо совпадений строк; последнее может привести к ложным срабатываниям, если у вас есть совпадения подстрок.

 df <- structure(list(string.to.search = c("a b c", "b c", "c d", "e", "f"), Drug1 = c("b", "c", "e", "f", NA), Drug2 = c("c", "d", NA, NA, NA), Drug3 = c(NA_character_, NA_character_, NA_character_, NA_character_, NA_character_)), row.names = c(NA, -5L), class = "data.frame")
df
#   string.to.search Drug1 Drug2 Drug3
# 1            a b c     b     c  <NA>
# 2              b c     c     d  <NA>
# 3              c d     e  <NA>  <NA>
# 4                e     f  <NA>  <NA>
# 5                f  <NA>  <NA>  <NA>

df %>%
  mutate(
    Found = Reduce(`|`,
      lapply(subset(., select=Drug1:Drug3),
             function(z) mapply(`%in%`, z, strsplit(string.to.search, "  "))))
  )
#   string.to.search Drug1 Drug2 Drug3 Found
# 1            a b c     b     c  <NA>  TRUE
# 2              b c     c     d  <NA>  TRUE
# 3              c d     e  <NA>  <NA> FALSE
# 4                e     f  <NA>  <NA> FALSE
# 5                f  <NA>  <NA>  <NA> FALSE
 

Комментарии:

1. Благодаря @r2evans, моя строка для поиска действительно разделена пробелами, я должен был лучше построить свой пример. Ваше решение действительно работает, но я изо всех сил пытаюсь заставить его работать для неизвестного количества наркотиков. Замена select=Drug1:Drug3 select=[2:ncol(df)] результатами приводит к ошибке, в которой R обнаружил неожиданный » [ » , поэтому я думаю, что неправильно ссылаюсь на столбцы. Есть ли какой-либо способ ссылаться на столбцы по индексу? Я всегда ожидаю, что он будет начинаться со столбца 2, но может содержать от 1 до X препаратов.

2. Мне удалось решить это на самом деле, используя: dd<-names(df[2:ncol(df)]) и select=dd большое спасибо @r2evans!

3. Ваше второе решение работает, но [2:ncol(df)] больше похоже на python-y, чем на R-y. Снимите [ скобки, просто select=2:ncol(df) должно получиться. Однако, поскольку вы ищете все, кроме первого, вы также можете сделать select=-1 или select=-string.to.search . Рад, что это помогло!

4. Честно говоря, причина, по которой я выбрал subset(.) , заключалась в том, что я не предполагал количество столбцов, и его способность (то же dplyr::select самое ) разрешать диапазоны столбцов очень приятна. Вместо subset(..) этого вы также могли бы использовать select(., -string.to.search) тот же эффект. Но так как вы знаете, что это первое , вы можете заменить все `подмножество (…) » просто .[,-1] , как в lapply(.[,-1], function(z)...) . (Просто код-гольф; Я предпочитаю select=-string.to.search лично, так как он не зависит от положения столбца и является более декларативным, его легче поддерживать.)

5. Спасибо @r2evans, различные варианты действительно полезны, и я ценю, что вы задумались о том, чтобы не полагаться на позицию столбца. Теперь я смог реализовать это в своем несколько более сложном наборе данных, и это работает именно так, как я надеялся! Я был очень расстроен, так что приятно иметь элегантный способ сделать это, а не создавать ужасный обходной путь.