Поиск 2 и 3 словосочетаний с использованием пакета R TM - PullRequest
24 голосов
/ 17 января 2012

Я пытаюсь найти код, который на самом деле работает, чтобы найти наиболее часто используемые фразы из двух и трех слов в пакете интеллектуального анализа текста R (возможно, существует другой пакет, который я не знаю). Я пытался использовать токенизатор, но, похоже, не повезло.

Если вы работали с подобной ситуацией в прошлом, не могли бы вы опубликовать код, который тестируется и действительно работает? Большое вам спасибо!

Ответы [ 7 ]

11 голосов
/ 18 января 2012

Вы можете передать пользовательскую функцию токенизации функции tm DocumentTermMatrix, поэтому, если у вас установлен пакет 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))

Где n вtokenize_ngrams функция - количество слов в фразе.Эта функция также реализована в пакете 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.

8 голосов
/ 30 мая 2013

Это часть 5 FAQ пакета :

5.Могу ли я использовать биграммы вместо отдельных токенов в матрице терм-документа?

Да.RWeka предоставляет токенизатор для произвольных n-грамм, которые могут быть непосредственно переданы в конструктор матрицы term-document.Например:

  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])
3 голосов
/ 18 января 2012

Это моё собственное выдуманное творение для разных целей, но я думаю, что оно может быть применимо и к вашим потребностям:

#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)
2 голосов
/ 05 октября 2017

В библиотеке корпус есть функция 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 - количество документов, содержащих термин.

1 голос
/ 11 июля 2017

Попробуйте пакет tidytext

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

)

Предположим, у меня есть DataDrame 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
1 голос
/ 16 марта 2015

Я добавляю аналогичную проблему, используя пакеты tm и ngram. После отладки 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
    })

Тогда моя функция токенизации выглядит так:

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))
0 голосов
/ 30 июня 2017

Попробуйте этот код.

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

Надеюсь, это поможет. Это целый код, который вы можете использовать.

...