在R中计算仅统计共享列的二进制数据相似度矩阵
高效计算二进制数据行间相似度(排除0值贡献)
核心需求
计算data.frame中每行(代表单个项目)的相似度,仅基于**同时为1的列(组)**统计,0值(非组内成员)不参与相似度计算——即只考虑两行都属于的组,忽略双方都不属于的组。
高效实现方案
方案1:纯矩阵运算(无依赖)
利用二进制矩阵的交叉乘积快速计算两两交集,再结合行和计算并集,最终得到符合需求的Jaccard相似度(交集/并集):
# 将data.frame转为矩阵 mat <- as.matrix(your_dataframe) # 计算两两行的交集(同时为1的列数) intersection <- mat %*% t(mat) # 计算每行的1的数量(项目所属组的总数) row_counts <- rowSums(mat) # 计算两两行的并集(至少一方为1的列数) union <- outer(row_counts, row_counts, "+") - intersection # 生成相似度矩阵,对角线设为1(自身相似度) similarity_mat <- intersection / union diag(similarity_mat) <- 1
矩阵运算基于R基础包实现,底层是优化过的线性代数逻辑,处理大数据集时比循环实现快数个数量级。
方案2:用proxy包快速实现
proxy包专门优化了距离/相似度计算,内置Jaccard方法,代码更简洁:
library(proxy) # 转矩阵(data.frame也可直接传入) mat <- as.matrix(your_dataframe) # 将Jaccard距离转为相似度(1-距离) similarity_mat <- 1 - dist(mat, method = "Jaccard") similarity_mat <- as.matrix(similarity_mat)
底层实现经过性能优化,适合快速开发场景。
示例验证
假设输入数据:
df <- data.frame( GroupA = c(1,1,0,0), GroupB = c(1,0,1,0), GroupC = c(0,1,1,1), GroupD = c(0,0,0,1) )
运行上述代码后得到的相似度矩阵:
[,1] [,2] [,3] [,4] [1,] 1.0000000 0.3333333 0.2500000 0.0000000 [2,] 0.3333333 1.0000000 0.5000000 0.2500000 [3,] 0.2500000 0.5000000 1.0000000 0.3333333 [4,] 0.0000000 0.2500000 0.3333333 1.0000000
完全符合基于共享组的相似度需求。
额外说明
- 如果数据不是严格二进制(存在大于1的值),先转二进制:
mat <- (mat > 0) * 1 - 若仅需要共享组的数量作为相似度,直接使用
intersection矩阵即可,无需计算并集。
内容的提问来源于stack exchange,提问作者mikeblazanin
相关产品推荐
相关产品推荐

