在R语言中为corpus用RegEx指定character n-grams时遇到问题
嘿,我来帮你搞定语料库预处理里的正则和定制n-grams问题!结合你提到的TermDocumentMatrix场景,我默认你是用R的tm包来处理的,这是这类任务最常用的工具,下面分步骤给你解决:
解决语料库预处理的两个核心需求
一、提取单词去掉最后一个字符(比如"the"→"th","host"→"hos")
你之前用的正则(\b([a-z]*)\B)匹配逻辑不太对,没法精准实现“去掉单词最后一个字符”的效果。我们换个思路,用正则替换来完成这个预处理:
自定义转换函数实现
在语料库的预处理流程里,添加一个自定义函数,专门把每个单词的最后一个字符剔除:
library(tm) # 自定义转换函数:移除每个单词的最后一个字符 remove_last_char <- function(x) { gsub("\\b(\\w+)(.)\\b", "\\1", x) } # 把这个函数应用到你的语料库上 corpus <- tm_map(corpus, content_transformer(remove_last_char))
这个正则\b(\w+)(.)\b的逻辑是:匹配完整单词(\b是单词边界),把单词拆成「前面所有字符」和「最后一个字符」两部分,然后只保留前面的部分,刚好实现你要的效果。
二、生成定制的character n-grams(n=1:3,取单词开头且不含最后一个字符)
你的需求是对每个单词,提取从开头出发、长度为1/2/3的子串,但不能包含单词的最后一个字符(比如"the"取"t""th","host"取"h""ho""hos")。默认的NGramTokenizer做不到这点,我们得自定义一个tokenizer:
定制n-gram分词函数
# 自定义符合需求的n-gram分词器 custom_ngram_tokenizer <- function(x) { # 先把文本拆成单个单词,转小写并过滤空字符串 words <- strsplit(tolower(x), "\\W+")[[1]] words <- words[words != ""] # 对每个单词生成指定的n-grams lapply(words, function(word) { max_valid_len <- nchar(word) - 1 # 不能包含最后一个字符,最大有效长度是单词长度-1 if (max_valid_len < 1) return(NULL) # 跳过长度为1的单词(去掉最后一个字符就没内容了) # 生成n从1到min(3, max_valid_len)的子串 target_n <- 1:min(3, max_valid_len) sapply(target_n, function(n) substr(word, 1, n)) }) %>% unlist() } # 生成TermDocumentMatrix时使用这个分词器 tdm <- TermDocumentMatrix(corpus, control = list(tokenize = custom_ngram_tokenizer))
效果验证
如果输入文本是"the host",经过这个分词器处理后,会得到你想要的结果:"t" "th" "h" "ho" "hos"。
小补充
- 如果你的语料里有大写字母,建议提前用
tm_map(corpus, content_transformer(tolower))统一转成小写,避免重复统计 - 要是想保留长度为1的单词(比如"a"),可以去掉
if (max_valid_len < 1) return(NULL)这行,不过这类单词处理后会变成空字符串,可能需要额外过滤
内容的提问来源于stack exchange,提问作者J.B.
相关产品推荐
相关产品推荐

