R语言如何避免for循环计算数据框相邻行向量的余弦值
报错核心原因
之前的rowwise写法报错来自三个逻辑问题:
select_all不是dplyr行操作上下文里合法的取整行数据的语法rowwise模式是按列逐值计算,lead()在该模式下无法直接提取完整的下一行向量- 逐行调用
lsa::cosine本身属于性能浪费,该函数原生支持矩阵级批量计算,大表场景下运算效率远高于逐行迭代、for循环。
无循环最优实现(大表友好)
直接利用lsa::cosine的矩阵计算特性,一次完成所有相邻行余弦值计算,无需逐行遍历:
library(tidyverse) library(lsa) dat <- mydat %>% mutate( cosineraw = cosine( x = t(as.matrix(.)), y = t(as.matrix(lead(.))) ) |> diag() )
逻辑说明:
lsa::cosine接收两个矩阵作为输入时,会计算x矩阵每一列和y矩阵每一列的余弦相似度,返回列数乘积维度的相似度矩阵- 原数据框转矩阵后转置,每一列对应原数据的一行15维向量;经
lead()偏移1位的数据集转置后,每一列对应原数据下一行的向量 - 最终取结果矩阵的对角线值,刚好对应「原第i行向量」和「原第i+1行向量」的余弦值,最后一行因偏移后无有效数据自动返回NA,无需额外处理边界。如果需要丢弃最后一行的空值,直接在代码末尾加
%>% slice(-n())即可。
逐行写法修正(仅作参考,大表不推荐)
如果需要用行操作逻辑实现,修正后的写法如下,但数据量较大时运算速度会明显低于上述向量化方案:
dat <- mydat %>% mutate(next_row = lead(cur_data(), 1)) %>% rowwise() %>% mutate( cosineraw = cosine( as.numeric(c_across(1:15)), as.numeric(next_row) ) ) %>% ungroup() %>% select(-next_row)
可以先用小数据集验证,上述两种方案输出的第一行余弦值,和手动运行lsa::cosine(as.vector(t(dat[2,])), as.vector(t(dat[1,])))得到的结果完全一致。
内容的提问来源于stack exchange,提问作者Jamie
相关产品推荐
相关产品推荐

