R语言使用stringdist::qgrams实现命名矩阵相乘计算n-gram概率
R语言实现命名矩阵按列名匹配计算n-gram字符串概率
问题核心原因
- 矩阵维度不匹配:
bigram_model的列是参考语料库中出现过的二元组,bigram_string的列是待计算字符串的二元组,二者列的数量、排序完全不一致,直接执行矩阵乘法必然报维度不兼容错误。 - 索引逻辑错误:你之前写的
bigram_model["V1",][bigram_string]是把bigram_string中的计数数值(全部为1)当成位置索引取值,所以每次都取到第一个元素Th对应的概率,输出自然全是相同值。
解决方法
我们可以把两个矩阵转为按二元组命名的向量,通过名字匹配对应取值,同时需要处理**未登录二元组(OOV,即待计算字符串中出现但参考语料库中不存在的二元组)**的概率赋值问题,以下是可直接运行的实现代码:
第一步:转为命名向量
# 把预训练的二元组模型转成命名向量,名字为二元组,值为对应对数概率 model_vec <- setNames(as.numeric(bigram_model), colnames(bigram_model)) # 把待计算字符串的二元组计数转成命名向量 string_vec <- setNames(as.numeric(bigram_string), colnames(bigram_string))
第二步:匹配概率并处理未登录二元组
这里示例给未登录二元组赋值对数概率为-10,你可以根据自己的平滑策略调整取值,比如使用加一平滑可以提前消除未登录问题:
# 按二元组名字匹配预训练概率 matched_prob <- model_vec[names(string_vec)] # 未匹配到的未登录二元组赋值默认对数概率 matched_prob[is.na(matched_prob)] <- -10
第三步:计算总对数概率
total_log_prob <- sum(string_vec * matched_prob) # 输出结果就是该字符串在你的二元组模型下的总对数概率 total_log_prob
附加:加一平滑预训练模型方案
如果要提前消除未登录二元组的问题,可以在训练模型时就做加一平滑:
# 合并参考语料和待预测字符串的所有二元组作为全集(批量预测时可以合并所有待预测样本的二元组) all_bigram <- unique(c(colnames(bigram_ref), colnames(bigram_string))) # 初始计数全部设为1实现加一平滑 smooth_count <- setNames(rep(1, length(all_bigram)), all_bigram) # 累加参考语料的实际计数 smooth_count[colnames(bigram_ref)] <- smooth_count[colnames(bigram_ref)] + as.numeric(bigram_ref) # 计算平滑后的对数概率模型 smooth_model <- log(smooth_count / sum(smooth_count)) # 直接匹配计算即可,不会出现NA total_log_prob_smooth <- sum(string_vec * smooth_model[names(string_vec)])
内容的提问来源于stack exchange,提问作者iNyar
相关产品推荐
相关产品推荐

