R строк фильтрации, которые содержат комбинацию слов - PullRequest
0 голосов
/ 31 августа 2018

Я работаю с текстовыми данными и ищу решение проблемы фильтрации.

Мне удалось найти решение, которое фильтрует строки, содержащие «Слово 1» ИЛИ «Слово 2»

Вот воспроизводимый код

df=data.frame(UID=c(1,2,3,4,5),Text=c("the quick brown fox jumped over the lazy dog",
                                 "long live the king",
                                 "I love my dog a lot",
                                 "Tomorrow will be a rainy day",
                                 "Tomorrow will be a sunny day"))


#Filter for rows that contain "brown" OR "dog"
filtered_results_1=dplyr::filter(df, grepl('brown|dog', Text))

Однако, когда я фильтрую строки, содержащие оба слова «Слово 1» И «Слово 2», это не работает.

#Filter for rows that contain "brown" AND "dog"
filtered_results_2=dplyr::filter(df, grepl('brown & dog', Text))

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

Ответы [ 5 ]

0 голосов
/ 31 августа 2018

Аналогично предыдущим ответам, но с использованием base

df[grepl("(?=.*dog)(?=.*brown)", df$Text, perl = TRUE),]
  UID                                         Text
1   1 the quick brown fox jumped over the lazy dog
0 голосов
/ 31 августа 2018

Вы можете использовать stringr::str_count:

dplyr::mutate(df, test = stringr::str_count(Text,'brown|dog'))
#   UID                                         Text test
# 1   1 the quick brown fox jumped over the lazy dog    2
# 2   2                           long live the king    0
# 3   3                          I love my dog a lot    1
# 4   4                 Tomorrow will be a rainy day    0
# 5   5                 Tomorrow will be a sunny day    0

dplyr::filter(df, stringr::str_count(Text,'brown|dog') == 2)
#   UID                                         Text
# 1   1 the quick brown fox jumped over the lazy dog

Он будет считать dog или brown столько раз, сколько они произошли, хотя

Следующее является более общим, менее элегантным, чем некоторые, но вы можете удобно поместить искомые слова в вектор:

dplyr::filter(df, purrr::map_int(strsplit(as.character(Text),'[[:punct:] ]'),
               ~sum(unique(.) %in% c("brown","dog"))) == 2)

#   UID                                         Text
# 1   1 the quick brown fox jumped over the lazy dog
0 голосов
/ 31 августа 2018

Попробуйте это решение:

filtered_results_2=dplyr::filter(df, grepl('brown.*dog|dog.*brown', Text))
filtered_results_2
  UID                                         Text
1   1 the quick brown fox jumped over the lazy dog
0 голосов
/ 31 августа 2018

Использование sqldf:

library(sqldf)
sqldf("select * from df where Text like '%dog%' AND Text like '%brown%'")

Выход:

    UID                                         Text
     1   1 the quick brown fox jumped over the lazy dog
0 голосов
/ 31 августа 2018

Мы можем использовать двойной grepl

dplyr::filter(df, grepl('\\bbrown\\b', Text) & grepl('\\bdog\\b', Text))

или используйте условие, в котором мы проверяем слово «коричневый», за которым следует слово «собака» (обратите внимание на границу слова (\\b), чтобы убедиться, что оно не будет соответствовать чему-либо еще) или «собака», а затем 'коричневый'

dplyr::filter(df, grepl("\\bbrown\\b.*\\bdog\\b|\\bdog\\b.*\\bbrown\\b", Text))
#   UID                                         Text
#1   1 the quick brown fox jumped over the lazy dog

ПРИМЕЧАНИЕ: проверяет границу слова, слова «коричневый», «собака», наличие их обоих в строке


Это также можно сделать с помощью base R

subset(df, grepl("\\bbrown\\b.*\\bdog\\b|\\bdog\\b.*\\bbrown\\b", Text))
...