You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:28:12