如何用tm、SnowballC等R包在TermDocumentMatrix中统计非重复单词语句频次
我来帮你搞定这个问题!要在同一个统计结果里同时包含单个单词和短语的频次,还得避免重复统计(也就是单个单词已经统计过的话,不会在短语里再重复计算它的次数),咱们一步步来实现:
步骤1:加载依赖包并预处理文本
先把你写的代码补全,完成文本的基础清洗,这是后续统计的关键:
# 加载需要的包 library(tm) library(SnowballC) library(RColorBrewer) library(wordcloud) library(NLP) library(tau) # 用来生成短语(n-gram)的工具包 # 读取本地文本文件 text <- readLines(file.choose()) docs <- Corpus(VectorSource(text)) # 文本预处理:去除特殊符号、转小写、去标点数字、去停用词等 toSpace <- content_transformer(function(x, pattern) gsub(pattern, " ", x)) docs <- tm_map(docs, toSpace, "/|@|\\|") docs <- tm_map(docs, content_transformer(tolower)) docs <- tm_map(docs, removePunctuation) docs <- tm_map(docs, removeNumbers) docs <- tm_map(docs, removeWords, stopwords("english")) # 如果是中文文本,替换成中文停用词表 docs <- tm_map(docs, stripWhitespace) # 可选:词干化(比如把"running"变成"run"),不需要的话可以注释掉 docs <- tm_map(docs, stemDocument)
步骤2:统计单字词和短语的频次并去重
这里核心是生成包含单字词和短语的频次数据,然后处理你要求的“无重复统计”——也就是单个单词的频次只算它单独出现的次数,排除它在短语里的出现次数:
# 将清洗后的语料库合并成一段纯文本 text_clean <- sapply(docs, as.character) text_clean <- paste(text_clean, collapse = " ") # 生成1-gram(单字词)和2-gram(双字词短语)的频次,你可以把`n=1:2`改成`n=1:3`来包含三字短语 ngram_freq <- textcnt(text_clean, n = 1:2, method = "string", split = "[[:space:]]+") # 转换成数据框方便处理 d <- as.data.frame(ngram_freq, stringsAsFactors = FALSE) colnames(d) <- "frequency" d$term <- rownames(d) rownames(d) <- NULL d <- d[, c("term", "frequency")] # 分离单字词和短语(通过是否包含空格判断) unigrams <- d[!grepl(" ", d$term), ] phrases <- d[grepl(" ", d$term), ] # 计算单字词的独立出现次数:总次数减去所有包含该词的短语的出现次数 for (i in 1:nrow(unigrams)) { target_word <- unigrams$term[i] # 找到所有包含该词的短语 matching_phrases <- phrases[grepl(paste0("\\b", target_word, "\\b"), phrases$term), ] # 减去短语里该词的出现次数 unigrams$frequency[i] <- unigrams$frequency[i] - sum(matching_phrases$frequency) # 避免出现负频次(比如单字词几乎都在短语里的情况) if (unigrams$frequency[i] < 0) unigrams$frequency[i] <- 0 } # 合并处理后的单字词和短语,过滤掉频次为0的无效条目 d_final <- rbind(unigrams[unigrams$frequency > 0, ], phrases) # 按频次从高到低排序 d_final <- d_final[order(-d_final$frequency), ]
现在d_final就是你要的变量d啦——里面既有单个单词,也有短语,而且单个单词的频次是它独立出现的次数,不会和短语里的重复统计。
步骤3:构建包含单字词和短语的TermDocumentMatrix(可选)
如果你需要生成对应的TermDocumentMatrix(而不是仅仅统计频次),可以用自定义的分词器来实现:
# 自定义分词器,同时生成1-gram和2-gram ngram_tokenizer <- function(x) { unlist(lapply(ngrams(words(x), 1:2), paste, collapse = " "), use.names = FALSE) } # 构建TermDocumentMatrix tdm <- TermDocumentMatrix(docs, control = list(tokenize = ngram_tokenizer)) # 转换为矩阵并统计总频次 tdm_matrix <- as.matrix(tdm) term_freq <- rowSums(tdm_matrix) d_tdm <- data.frame(term = names(term_freq), frequency = term_freq, stringsAsFactors = FALSE) # 同样做去重处理(和步骤2逻辑一致) unigrams_tdm <- d_tdm[!grepl(" ", d_tdm$term), ] phrases_tdm <- d_tdm[grepl(" ", d_tdm$term), ] for (i in 1:nrow(unigrams_tdm)) { target_word <- unigrams_tdm$term[i] matching_phrases <- phrases_tdm[grepl(paste0("\\b", target_word, "\\b"), phrases_tdm$term), ] unigrams_tdm$frequency[i] <- unigrams_tdm$frequency[i] - sum(matching_phrases$frequency) if (unigrams_tdm$frequency[i] < 0) unigrams_tdm$frequency[i] <- 0 } d_final_tdm <- rbind(unigrams_tdm[unigrams_tdm$frequency > 0, ], phrases_tdm) d_final_tdm <- d_final_tdm[order(-d_final_tdm$frequency), ]
步骤4:生成包含单字词和短语的词云(可选)
如果要可视化结果,用wordcloud包生成词云即可:
# 过滤掉频次过低的条目(这里阈值设为5,你可以根据需求调整) d_plot <- d_final[d_final$frequency >= 5, ] # 生成词云 wordcloud(words = d_plot$term, freq = d_plot$frequency, min.freq = 1, max.words = 200, random.order = FALSE, rot.per = 0.35, colors = brewer.pal(8, "Dark2"))
内容的提问来源于stack exchange,提问作者Shane Low
相关产品推荐
相关产品推荐

