【问题标题】:Removing ngrams containing stopwords using tidytext使用 tidytext 删除包含停用词的 ngram
【发布时间】:2019-08-11 08:19:33
【问题描述】:

更新:感谢您迄今为止的意见。我重写了问题并添加了一个更好的示例来突出我的第一个示例中未涵盖的隐含要求。

问题 我正在寻找一个通用的tidy 解决方案来删除包含停用词的 ngram。简而言之,ngram 是由空格分隔的单词字符串。一个unigram包含1个单词,一个bigram包含2个单词,依此类推。我的目标是在使用unnest_tokens() 后将其应用于数据框。该解决方案应适用于包含任意长度(uni、bi、tri..)或至少 bi & tri 及以上的 ngram 混合的数据帧。

新示例数据

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"
  )

reprex package (v0.2.1) 于 2019 年 3 月 21 日创建

期望的行为

  • 应使用stopword_dfword 列中的停用词将ngram_df 转换为desired_output
  • 应删除包含停用词的每一行
  • 应遵守单词边界(即查找 is 不应删除 basis


我第一次尝试下面的reprex:

示例数据

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

reprex package (v0.2.1) 于 2019 年 3 月 20 日创建

(例句来自:https://en.wikipedia.org/wiki/Groundwater_remediation)

【问题讨论】:

  • 我猜原因是为了避免得到“假”ngram。例如,如果您有句子“Sky is blue”,并且在找到二元组之前删除了 is,那么您最终会找到天蓝色,如果考虑停用词,这将不是真正的二元组。也许一种解决方法是在查找 ngram 之前用一个相同的唯一占位符字符串替换所有停用词,然后删除所有包含占位符字符串的 ngram?
  • 正确@TinglTanglBob
  • 查看 Silge 和 Robinson 的“使用 R 进行文本挖掘”,特别是这里的这一部分:tidytextmining.com/ngrams.html#counting-and-filtering-n-grams
  • 谢谢,@MarianMinar。这是一个好的开始。我希望看到一个可以一次性处理单词、二元组和三元组的版本。我意识到这在我上面的例子中并不明显。我今天会尝试更新问题。

标签: r tidyverse tidytext


【解决方案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

【讨论】:

  • 如果要匹配整个单词而不是子字符串,则需要添加单词边界。 swc &lt;- paste(paste0("\\b", stopwords, "\\b"), collapse = "|").
猜你喜欢
  • 1970-01-01
  • 2019-02-19
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
  • 2021-09-26
  • 2019-07-29
  • 1970-01-01
  • 2018-09-19
相关资源
最近更新 更多