поиск слов в текстовом абзаце и последующая пометка их в R

#r #text-mining

#r #интеллектуальный анализ текста

Вопрос:

У меня есть набор текстовых данных, и я хочу выполнить поиск различных слов в нем, а затем отметить их, когда, когда я их найду. Вот пример данных:

 df <- data.table("id" = c(1:3), "report" = c("Travel opens our eyes to art, history, and culture – but it also introduces us to culinary adventures we may have never imagined otherwise."
                                             , "We quickly observed that no one in Sicily cooks with recipes (just with the heart), so we now do the same."
                                             , "We quickly observed that no one in Sicily cooks with recipes so we now do the same."), "summary" = c("On our first trip to Sicily to discover our family roots,"
                                                                      , "If you’re not a gardener, an Internet search for where to find zucchini flowers results."
                                                                      , "add some fresh cream to make the mixture a bit more liquid,"))
  

До сих пор я использовал SQL для обработки этого, но это становится сложным, когда у вас есть большой список слов для поиска.

 dfOne <- sqldf("select id
              , case when lower(report) like '%opens%' then 1 else 0 end as opens
, case when lower(report) like '%cooks%' then 1 else 0 end as cooks
, case when lower(report) like '%internet%' then 1 else 0 end as internet
, case when lower(report) like '%zucchini%' then 1 else 0 end as zucchini
, case when lower(report) like '%fresh%' then 1 else 0 end as fresh
      from df
      ")
  

Я ищу идеи, как сделать это более эффективным способом. Представьте, что если у вас есть длинный список целевых терминов, этот код может стать излишне длинным.

Спасибо,

SM.

Ответ №1:

1) sqldf

Определите вектор слов, а затем преобразуйте его в SQL. Обратите внимание, что это case when не требуется, поскольку like уже выдает результат 0/1. Предварение sqldf с fn$ позволяет $like заменить строку символов R like в инструкции SQL. Используйте verbose=TRUE аргумент to sqldf , чтобы просмотреть сгенерированную инструкцию SQL. Это всего лишь две строки кода, независимо от того, какой длины words .

 words <- c("opens", "cooks", "internet", "zucchini", "fresh", "test me")

like <- toString(sprintf("nlower(report) like '%%%s%%' as '%s'", words, words))
fn$sqldf("select id, $like from df", verbose = TRUE)
  

предоставление:

   id opens cooks internet zucchini fresh test me
1  1     1     0        0        0     0       0
2  2     0     1        0        0     0       0
3  3     0     1        0        0     0       0
  

2) внешний

Используя words вышеизложенное, мы можем использовать outer следующим образом. Обратите внимание, что функция (третий аргумент) во внешнем должна быть векторизована, и мы можем сделать grepl векторизованную, как показано. Опустите check.names = FALSE , если не возражаете, имена столбцов, связанные со словами, в которых пробелы или знаки препинания вставлены в синтаксические имена переменных R. Это приводит к тому же результату, что и (1).

 with(df, data.frame(
    id, 
     t(outer(setNames(words, words), report, Vectorize(grepl))), 
    check.names = FALSE
))
  

3) sapply

Используя sapply , мы можем получить немного более короткое решение в тех же строках, что и (2). Результат такой же, как в (1) и (2).

 with(df, data.frame(id,  sapply(words, grepl, report), check.names = FALSE))
  

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

1. Мне нравится, что ваш код состоит из нескольких строк. Я протестирую это и приму решение, если оно подтвердится. Большое вам спасибо за то, что согласились.

2. Спасибо Г. Гротендику. Решение 1 завершается ошибкой, когда что-то вроде этого «test-me» или «test me» используется в списке слов « слова <- c(«открывает», «готовит», «интернет», «цуккини», «свежий», «протестируй меня»)« . Два других работают нормально и создают столбцы с именами test.me . Я думаю, что первое связано с соглашениями об именовании имен столбцов в SQLLite?

3. В вопросе, похоже, не было определения слов как имеющих знаки препинания или пробелы, но если у вас есть такие, просто заключите имя столбца в кавычки в инструкции SQL. Я изменил это выше, чтобы сделать это. Также добавьте check.names=FALSE в (2) и (3), если вы не хотите, чтобы имя менялось — что мы также сделали выше.

4. Еще раз спасибо. Я изучу эти функции и пойму, что они делают под капотом.

Ответ №2:

Вот простой способ. Предполагается, что вы хотите выполнить поиск по двум отдельным столбцам.

 library(tidyverse)

df <- tibble(id = c(1:3), report = c("Travel opens our eyes to art, history, and culture – but it also introduces us to culinary adventures we may have never imagined otherwise."
                                             , "We quickly observed that no one in Sicily cooks with recipes (just with the heart), so we now do the same."
                                             , "We quickly observed that no one in Sicily cooks with recipes so we now do the same."), 
                 summary = c("On our first trip to Sicily to discover our family roots,"
                                                                                                                                                     , "If you’re not a gardener, an Internet search for where to find zucchini flowers results."
                                                                                                                                                     , "add some fresh cream to make the mixture a bit more liquid,"))


# Vector of words
vec <- c('eyes','art','gardener','mixture','trip')

df %>% 
  mutate(reportFlag = case_when(
    str_detect(report,paste(vec,collapse = '|')) ~ T,
    T ~ F)
) %>% 
  mutate(summaryFlag = case_when(
    str_detect(report,paste(vec,collapse = '|')) ~ T,
    T ~ F))
  

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

1. хорошо, это выглядит как элегантное решение. Однако я пока не могу это протестировать, у меня возникли проблемы с установкой tidyverse. Предупреждение в install.packages : установка пакета ‘reprex’ имела ненулевую ошибку статуса завершения: зависимости ‘broom’, ‘rlang’, ‘tidyselect’, ‘vctrs’ недоступны для пакета ‘modelr’. Я решу эту проблему и оценю ваше решение. В то же время, что делают ~ T, T, F?

2. Да, это какой-то не совсем интуитивный case_when синтаксис. Первый аргумент str_detect... ищет слова и помечает T, если они найдены. Если нет, то все остальные случаи отмечены знаком F. Это последний T.

3. Создает ли ваше решение 5 новых столбцов, как это делает мой sql? Каждый столбец для каждого слова? Отображение 1 для строки или регистра с этим словом и 0 в противном случае?