#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, различные варианты действительно полезны, и я ценю, что вы задумались о том, чтобы не полагаться на позицию столбца. Теперь я смог реализовать это в своем несколько более сложном наборе данных, и это работает именно так, как я надеялся! Я был очень расстроен, так что приятно иметь элегантный способ сделать это, а не создавать ужасный обходной путь.