Удаление нграмм, содержащих запрещенные слова, с помощью tidytext

ОБНОВЛЕНИЕ: Спасибо за ваш вклад. Я переписал вопрос и добавил лучший пример, чтобы выделить неявные требования, которые не были рассмотрены в моем первом примере.

Вопрос Я ищу общее tidy решение для удаления nрограмм, содержащих стоп-слова. Короче говоря, нграммы - это строки слов, разделенных пробелом. Юниграмма содержит 1 слово, биграмма - 2 слова и т. Д. Моя цель - применить это к фрейму данных после использования unnest_tokens(). Решение должно работать с фреймом данных, содержащим смесь ngram любой длины (uni, bi, tri ..) или, по крайней мере, bi & tri и выше.

Новый пример данных

ngram_df <- tibble::tribble(
  ~Document,                   ~ngram,
          1,                    "the",
          1,              "the basis",
          1,                  "basis",
          1,       "basis of culture",
          1,                "culture",
          1,        "is ground water",
          1,           "ground water",
          1, "ground water treatment"
  )
stopword_df <- tibble::tribble(
  ~word, ~lexicon,
  "the", "custom",
   "of", "custom",
   "is", "custom"
  )
desired_output <- tibble::tribble(
  ~Document,                   ~ngram,
          1,                  "basis",
          1,                "culture",
          1,           "ground water",
          1, "ground water treatment"
  )

Создано 21 марта 2019 г. пакетом REPEX (v0.2.1)

Желаемое поведение

  • ngram_df следует преобразовать в desired_output, используя стоп-слова из столбца word в stopword_df.
  • каждая строка, содержащая стоп-слово, должна быть удалена
  • границы слов должны соблюдаться (т.е. поиск is не должен удалять basis)


моя первая попытка представить ниже:

пример данных

library(tidyverse)
library(tidytext)
df <- "Groundwater remediation is the process that is used to treat polluted groundwater by removing the pollutants or converting them into harmless products." %>% 
  enframe() %>% 
  unnest_tokens(ngrams, value, "ngrams", n = 2)
#apply magic here

df
#> # A tibble: 21 x 2
#>     name ngrams                 
#>    <int> <chr>                  
#>  1     1 groundwater remediation
#>  2     1 remediation is         
#>  3     1 is the                 
#>  4     1 the process            
#>  5     1 process that           
#>  6     1 that is                
#>  7     1 is used                
#>  8     1 used to                
#>  9     1 to treat               
#> 10     1 treat polluted         
#> # ... with 11 more rows

пример списка игнорируемых слов

stopwords <- c("is", "the", "that", "to")

желаемый результат

#> Source: local data frame [9 x 2]
#> Groups: <by row>
#> 
#> # A tibble: 9 x 2
#>    name ngrams                 
#>   <int> <chr>                  
#> 1     1 groundwater remediation
#> 2     1 treat polluted         
#> 3     1 polluted groundwater   
#> 4     1 groundwater by         
#> 5     1 by removing            
#> 6     1 pollutants or          
#> 7     1 or converting          
#> 8     1 them into              
#> 9     1 harmless products

Создано 20 марта 2019 г. пакетом REPEX (v0.2.1)

(пример предложения из: https://en.wikipedia.org/wiki/Groundwater_remediation) < / sup>


person Benjamin Schwetz    schedule 20.03.2019    source источник
comment
Думаю, причина в том, чтобы избежать ложных нограмм. Например, если у вас есть предложение Sky is blue, и вы удалите его до того, как найдете биграммы, вы получите небесно-голубой, который не был бы истинной биграммой, если бы учитывались стоп-слова. Может быть, обходным путем может быть замена всех стоп-слов одной и той же уникальной строкой-заполнителем перед поиском ngram и последующим удалением всех ngram, содержащих строку-заполнитель?   -  person TinglTanglBob    schedule 20.03.2019
comment
Правильный @TinglTanglBob   -  person Benjamin Schwetz    schedule 20.03.2019
comment
Ознакомьтесь с Text Mining with R от Silge and Robinson, особенно в этом разделе здесь: tidytextmining.com/ngrams.html#counting-and-filtering-n-grams   -  person Marian Minar    schedule 20.03.2019
comment
спасибо, @MarianMinar. Хорошее начало. Я бы хотел увидеть версию, которая могла бы обрабатывать слова, биграммы и триграммы за один раз. Я понимаю, что из приведенного выше примера это не очевидно. Постараюсь сегодня обновить вопрос.   -  person Benjamin Schwetz    schedule 21.03.2019


Ответы (1)


Здесь у вас есть другой способ использования "stopwords_collapsed" из предыдущего ответа:

swc <- paste(stopwords, collapse = "|")
df <- df[str_detect(df$ngrams, swc) == FALSE, ] #select rows without stopwords

df
# A tibble: 8 x 2
   name ngrams                 
  <int> <chr>                  
1     1 groundwater remediation
2     1 treat polluted         
3     1 polluted groundwater   
4     1 groundwater by         
5     1 by removing            
6     1 pollutants or          
7     1 or converting          
8     1 harmless products 

Вот простой тест, сравнивающий обе системы:

#benchmark
txtexp <- rep(txt,1000000)
dfexp <- txtexp %>% 
    enframe() %>% 
    unnest_tokens(ngrams, value, "ngrams", n = 2)

benchmark("mutate+filter (small text)" = {df1 <- df %>%
        mutate(
            has_stop_word = str_detect(ngrams, stopwords_collapsed)
        ) %>%
        filter(!has_stop_word)},
          "[] row selection (small text)" = {df2 <- df[str_detect(df$ngrams, stopwords_collapsed) == FALSE, ]},
        "mutate+filter (large text)" = {df3 <- dfexp %>%
            mutate(
                has_stop_word = str_detect(ngrams, stopwords_collapsed)
            ) %>%
            filter(!has_stop_word)},
        "[] row selection (large text)" = {df4 <- dfexp[str_detect(dfexp$ngrams, stopwords_collapsed) == FALSE, ]},
          replications = 5,
          columns = c("test", "replications", "elapsed")
)

                           test replications elapsed
4 [] row selection (large text)            5   30.03
2 [] row selection (small text)            5    0.00
3    mutate+filter (large text)            5   30.64
1    mutate+filter (small text)            5    0.00
person César Arquero    schedule 20.03.2019