【问题标题】:Finding 2 & 3 word Phrases Using R TM Package使用 R TM 包查找 2 和 3 词短语
【发布时间】:2012-02-12 11:41:05
【问题描述】:

我正在尝试找到一个代码,该代码实际上可以在 R 文本挖掘包中找到最常用的两个和三个单词短语(也许还有另一个我不知道的包)。我一直在尝试使用标记器,但似乎没有运气。

如果您过去曾处理过类似情况,您能否发布一个经过测试且实际有效的代码?非常感谢!

【问题讨论】:

  • 有序短语,是吗?还是同时出现?
  • 两者都有用。谢谢!

标签: r data-mining text-mining


【解决方案1】:

corpus 库有一个名为 term_stats 的函数,可以满足您的需求:

library(corpus)
corpus <- gutenberg_corpus(55) # Project Gutenberg #55, _The Wizard of Oz_
text_filter(corpus)$drop_punct <- TRUE # ignore punctuation
term_stats(corpus, ngrams = 2:3)
##    term             count support
## 1  of the             336       1
## 2  the scarecrow      208       1
## 3  to the             185       1
## 4  and the            166       1
## 5  said the           152       1
## 6  in the             147       1
## 7  the lion           141       1
## 8  the tin            123       1
## 9  the tin woodman    114       1
## 10 tin woodman        114       1
## 11 i am                84       1
## 12 it was              69       1
## 13 in a                64       1
## 14 the great           63       1
## 15 the wicked          61       1
## 16 wicked witch        60       1
## 17 at the              59       1
## 18 the little          59       1
## 19 the wicked witch    58       1
## 20 back to             57       1
## ⋮  (52511 rows total)

这里,count 是出现次数,support 是包含该词条的文档数。

【讨论】:

    【解决方案2】:

    试试 tidytext 包

    library(dplyr)
    library(tidytext)
    library(janeaustenr)
    library(tidyr
    

    )

    假设我有一个包含评论列的数据框 CommentData,我想同时查找两个单词的出现。那就试试吧

    bigram_filtered <- CommentData %>%
      unnest_tokens(bigram, Comment, token= "ngrams", n=2) %>%
      separate(bigram, c("word1","word2"), sep=" ") %>%
      filter(!word1 %in% stop_words$word,
             !word2 %in% stop_words$word) %>%
      count(word1, word2, sort=TRUE)
    

    上面的代码创建了标记,然后删除了对分析没有帮助的停用词(例如 the、an、to 等),然后计算这些词的出现次数。然后,您将使用联合函数来组合单个单词并记录它们的出现。

    bigrams_united <- bigram_filtered %>%
      unite(bigram, word1, word2, sep=" ")
    bigrams_united
    

    【讨论】:

      【解决方案3】:

      试试这个代码。

      library(tm)
      library(SnowballC)
      library(class)
      library(wordcloud)
      
      keywords <- read.csv(file.choose(), header = TRUE, na.strings=c("NA","-","?"))
      keywords_doc <- Corpus(VectorSource(keywords$"use your column that you need"))
      keywords_doc <- tm_map(keywords_doc, removeNumbers)
      keywords_doc <- tm_map(keywords_doc, tolower)
      keywords_doc <- tm_map(keywords_doc, stripWhitespace)
      keywords_doc <- tm_map(keywords_doc, removePunctuation)
      keywords_doc <- tm_map(keywords_doc, PlainTextDocument)
      keywords_doc <- tm_map(keywords_doc, stemDocument)
      

      这是您可以使用的二元组或三元组部分

      BigramTokenizer <-  function(x)
      unlist(lapply(ngrams(words(x), 2), paste, collapse = " "), use.names = FALSE)
      # creating of document matrix
      keywords_matrix <- TermDocumentMatrix(keywords_doc, control = list(tokenize = BigramTokenizer))
      
      # remove sparse terms 
      keywords_naremoval <- removeSparseTerms(keywords_matrix, 0.95)
      
      # Frequency of the words appearing
      keyword.freq <- rowSums(as.matrix(keywords_naremoval))
      subsetkeyword.freq <-subset(keyword.freq, keyword.freq >=20)
      frequentKeywordSubsetDF <- data.frame(term = names(subsetkeyword.freq), freq = subsetkeyword.freq) 
      
      # Sorting of the words
      frequentKeywordDF <- data.frame(term = names(keyword.freq), freq = keyword.freq)
      frequentKeywordSubsetDF <- frequentKeywordSubsetDF[with(frequentKeywordSubsetDF, order(-frequentKeywordSubsetDF$freq)), ]
      frequentKeywordDF <- frequentKeywordDF[with(frequentKeywordDF, order(-frequentKeywordDF$freq)), ]
      
      # Printing of the words
      wordcloud(frequentKeywordDF$term, freq=frequentKeywordDF$freq, random.order = FALSE, rot.per=0.35, scale=c(5,0.5), min.freq = 30, colors = brewer.pal(8,"Dark2"))
      

      希望这会有所帮助。这是您可以使用的完整代码。

      【讨论】:

      • 我已经尝试了所有的解决方案,但没有一个能处理我的数据。我不知道为什么。无论我在 ngams 函数中留下什么值(2、3、4 等),结果总是 1 克(即一个单词)
      【解决方案4】:

      我通过使用tmngram 包添加了类似的问题。 调试mclapply后,发现2个字以下的文档有问题,出现如下错误

         input 'x' has nwords=1 and n=2; must have nwords >= n
      

      所以我添加了一个过滤器来删除低字数的文档:

          myCorpus.3 <- tm_filter(myCorpus.2, function (x) {
            length(unlist(strsplit(stringr::str_trim(x$content), '[[:blank:]]+'))) > 1
          })
      

      然后我的 tokenize 函数看起来像:

      bigramTokenizer <- function(x) {
        x <- as.character(x)
      
        # Find words
        one.list <- c()
        tryCatch({
          one.gram <- ngram::ngram(x, n = 1)
          one.list <- ngram::get.ngrams(one.gram)
        }, 
        error = function(cond) { warning(cond) })
      
        # Find 2-grams
        two.list <- c()
        tryCatch({
          two.gram <- ngram::ngram(x, n = 2)
          two.list <- ngram::get.ngrams(two.gram)
        },
        error = function(cond) { warning(cond) })
      
        res <- unlist(c(one.list, two.list))
        res[res != '']
      }
      

      然后您可以使用以下方法测试该功能:

      dtmTest <- lapply(myCorpus.3, bigramTokenizer)
      

      最后:

      dtm <- DocumentTermMatrix(myCorpus.3, control = list(tokenize = bigramTokenizer))
      

      【讨论】:

        【解决方案5】:

        这是我自己为不同目的而创作的作品,但我认为也可能适用于您的需求:

        #User Defined Functions
        Trim <- function (x) gsub("^\\s+|\\s+$", "", x)
        
        breaker <- function(x) unlist(strsplit(x, "[[:space:]]|(?=[.!?*-])", perl=TRUE))
        
        strip <- function(x, digit.remove = TRUE, apostrophe.remove = FALSE){
            strp <- function(x, digit.remove, apostrophe.remove){
                x2 <- Trim(tolower(gsub(".*?($|'|[^[:punct:]]).*?", "\\1", as.character(x))))
                x2 <- if(apostrophe.remove) gsub("'", "", x2) else x2
                ifelse(digit.remove==TRUE, gsub("[[:digit:]]", "", x2), x2)
            }
        unlist(lapply(x, function(x) Trim(strp(x =x, digit.remove = digit.remove, 
            apostrophe.remove = apostrophe.remove)) ))
        }
        
        unblanker <- function(x)subset(x, nchar(x)>0)
        
        #Fake Text Data
        x <- "I like green eggs and ham.  They are delicious.  They taste so yummy.  I'm talking about ham and eggs of course"
        
        #The code using Base R to Do what you want
        breaker(x)
        strip(x)
        words <- unblanker(breaker(strip(x)))
        textDF <- as.data.frame(table(words))
        textDF$characters <- sapply(as.character(textDF$words), nchar)
        textDF2 <- textDF[order(-textDF$characters, textDF$Freq), ]
        rownames(textDF2) <- 1:nrow(textDF2)
        textDF2
        subset(textDF2, characters%in%2:3)
        

        【讨论】:

        • 嗨,@Tyler-Rinker,我知道这已经有几年历史了,但是在测试您的代码时出现此错误:` FUN 中的错误(c(“”,“”,“” , "", "", "", "", "", "", "", "", "", "", "", : 找不到函数 "Trim" `
        • 如果有帮助,添加 Trim
        • 哈哈。谢谢,@Tyler_Rinker。我有一个完全相同的功能,称为trim,但我没有意识到它正在寻找什么。谢谢!
        【解决方案6】:

        这是 包的FAQ 的第5 部分:

        5.我可以在术语文档矩阵中使用二元组而不是单个标记吗?

        是的。 RWeka 为任意 n-gram 提供了一个分词器,它可以是 直接传递给术语文档矩阵构造函数。例如:

          library("RWeka")
          library("tm")
        
          data("crude")
        
          BigramTokenizer <- function(x) NGramTokenizer(x, Weka_control(min = 2, max = 2))
          tdm <- TermDocumentMatrix(crude, control = list(tokenize = BigramTokenizer))
        
          inspect(tdm[340:345,1:10])
        

        【讨论】:

        • 这对我有用。实际上,当前版本的FAQ有一个不需要RWeka的解决方案:tm.r-forge.r-project.org/faq.html#Bigrams
        • 如果你能弄清楚如何让 rJava 工作,以便你可以使用 RWeka 包。很高兴看到一个不依赖于 Java 的解决方案。
        【解决方案7】:

        您可以将自定义标记函数传递给tmDocumentTermMatrix 函数,因此如果您安装了包tau,它就相当简单了。

        library(tm); library(tau);
        
        tokenize_ngrams <- function(x, n=3) return(rownames(as.data.frame(unclass(textcnt(x,method="string",n=n)))))
        
        texts <- c("This is the first document.", "This is the second file.", "This is the third text.")
        corpus <- Corpus(VectorSource(texts))
        matrix <- DocumentTermMatrix(corpus,control=list(tokenize=tokenize_ngrams))
        

        tokenize_ngrams 函数中的n 是每个短语的单词数。这个特性也在包RTextTools中实现,进一步简化了事情。

        library(RTextTools)
        texts <- c("This is the first document.", "This is the second file.", "This is the third text.")
        matrix <- create_matrix(texts,ngramLength=3)
        

        这将返回一个 DocumentTermMatrix 类,用于包 tm

        【讨论】:

        • 我意识到这是一个相当陈旧的线程,但是最近有人尝试过吗?在我的手中,第一种方法给出了以下错误:&gt; matrix &lt;- DocumentTermMatrix(corpus,control=list(tokenize=tokenize_ngrams)) Error in simple_triplet_matrix(i = i, j = j, v = as.numeric(v), nrow = length(allTerms), : 'i, j, v' different lengths In addition: Warning messages: 1: In mclapply(unname(content(x)), termFreq, control) : all scheduled cores encountered errors in user code 2: In simple_triplet_matrix(i = i, j = j, v = as.numeric(v), nrow = length(allTerms), : NAs introduced by coercion.
        • 我在尝试library(RTextTools) 示例时遇到了同样的错误,@MAndrecPhD。
        • 我也有同样的问题。我看到有人建议 SnowballC 包可以解决它,但它不适合我。有什么建议吗?
        • 如果我添加以下 simple_triplet_matrix 错误不再出现 options(mc.cores=1) 但是我得到以下错误,而不是 Error in FUN(X[[i]], ...) :非字符参数
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-15
        • 2011-06-15
        • 2017-03-12
        • 1970-01-01
        • 2015-02-28
        • 1970-01-01
        • 2018-03-31
        相关资源
        最近更新 更多