如何用R tidytext、widyr实现相似文本聚类及tidy格式到聚类矩阵转换
从长表相似度结果转换聚类矩阵的实现方法
前置代码修正
示例代码缺少widyr包的加载步骤,会触发函数找不到的报错,先补全可运行的基础链路:
library(janeaustenr) library(dplyr) library(tidytext) library(widyr) # 必须加载的依赖包 austen_words <- austen_books() %>% unnest_tokens(word, text) # 输出的closest为三列长表结构:item1、item2、similarity,仅存储两两配对的相似度值,无对角线自匹配记录 closest <- austen_words %>% pairwise_similarity(book, word, n) %>% arrange(desc(similarity))
核心矩阵转换步骤
pairwise输出的非对称长表无法直接用于距离计算和聚类,需要先转换为对称矩阵,再匹配聚类算法的输入要求。具体转换流程如下:
- 提取所有参与配对的唯一对象(当前示例为书籍名),作为矩阵的行、列索引
- 将相似度值转换为聚类可用的距离值,转换规则为
距离 = 1 - 相似度(相似度越高,对象间距离越近) - 补全长表的缺失部分,包括反向配对的距离值、自匹配的对角线0值,让矩阵满足对称要求
- 转换为宽格式的数值矩阵
对应代码实现:
# 提取所有唯一的书籍名称 book_names <- unique(c(closest$item1, closest$item2)) # 整理距离值长表 dist_tbl <- closest %>% # 相似度转距离 mutate(dist_val = 1 - similarity) %>% # 补全反向配对的距离记录,让矩阵对称 bind_rows( closest %>% rename(item1 = item2, item2 = item1) %>% mutate(dist_val = 1 - similarity) ) %>% # 补全对角线元素:对象与自身的距离为0 bind_rows( tibble( item1 = book_names, item2 = book_names, dist_val = 0 ) ) # 转换为宽格式矩阵 m <- dist_tbl %>% tidyr::pivot_wider( names_from = item2, values_from = dist_val ) %>% select(-item1) %>% as.matrix() # 为矩阵补充行名,保证行列标签一致 rownames(m) <- colnames(m)
聚类流程的衔接与关键注意事项
转换完成的矩阵可直接对接聚类流程,但需要匹配不同算法的输入要求,避免出现逻辑错误:
- *kmeans函数的输入强制要求为「样本为行、特征为列」的原始数据矩阵,不支持直接传入计算好的距离值。如果坚持使用原生kmeans流程,无需从pairwise相似度结果转矩阵,可直接从分词结果生成文档-词项矩阵(行是待聚类对象、列是词项/TF-IDF值)作为输入m,此时
d <- dist(m)计算欧氏距离、传入kmeans的流程才是正确的。 - 如果要基于已经计算好的相似度距离做聚类,可替换为基于距离的medoid聚类算法(PAM),直接将转换好的距离矩阵转为
dist对象传入即可,和kmeans的聚类逻辑一致:library(cluster) # 将宽格式矩阵转为标准dist距离对象 d_obj <- as.dist(m) # 直接基于距离对象做聚类,指定聚类数为4 kfit <- pam(d_obj, k = 4) - 如果聚类目标为语义相似的词汇而非书籍,只要调整
pairwise_similarity的入参(将待聚类对象从book替换为word),上述矩阵转换流程完全通用。
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

