我正在尝试实现基于项目的过滤,具有代表购买(1)或未购买(0)特定产品的消费者的大特征空间。
我有一个长尾分布,所以矩阵非常稀疏。R 处理得不好。我可以做些什么来简化余弦相似度的测量?
我正在尝试实现基于项目的过滤,具有代表购买(1)或未购买(0)特定产品的消费者的大特征空间。
我有一个长尾分布,所以矩阵非常稀疏。R 处理得不好。我可以做些什么来简化余弦相似度的测量?
使用Matrix包存储矩阵,使用skmeans_xdist函数计算余弦距离。
/edit: 看来这个skmeans_xdist
功能效率不是很高。这是一个简单的示例,说明如何计算 R 中 netflix 大小的矩阵的余弦相似度。
首先,构建矩阵:
library(Matrix)
set.seed(42)
non_zero <- 99000000
i <- sample(1:17770, non_zero, replace=TRUE)
j <- sample(1:480189, non_zero, replace=TRUE)
x <- sample(1:5, non_zero, replace=TRUE)
m <- sparseMatrix(i=i,j=j,x=x) #Rows are movies, columns are users
m <- drop0(m)
接下来对每一行进行归一化,使其矢量距离为 1。这在我的机器上需要 85 秒。
row_norms <- sqrt(rowSums(m^2))
row_norms <- t(crossprod(sign(m), Diagonal(x=row_norms)))
row_norms@x <- 1/row_norms@x
m_norm <- m * row_norms
最后,我们可以找到余弦相似度,这需要我 155 秒
system.time(sim <- tcrossprod(m_norm))
另外,请注意余弦相似度矩阵非常稀疏,因为许多电影不共享任何共同的用户。您可以使用 转换为余弦距离1-sim
,但这可能需要一段时间(我没有计时)。
/edit 几年后:这是一个更快的行规范化函数:
row_normalize <- function(m){
row_norms <- sqrt(rowSums(m^2))
row_norms <- t(crossprod(sign(m), Diagonal(x=row_norms)))
row_norms@x <- 1/row_norms@x
m_norm <- m * row_norms
return(m_norm)
}
fast_row_normalize <- function(m){
d <- Diagonal(x=1/sqrt(rowSums(m^2)))
return(t(crossprod(m, d)))
}
library(microbenchmark)
microbenchmark(
a = row_normalize(m),
b = fast_row_normalize(m),
times=1
)
新功能只需要 25 秒(而另一个需要 89 秒——我猜我的电脑变慢了 =/):
Unit: seconds
expr min lq mean median uq max neval
a 89.68086 89.68086 89.68086 89.68086 89.68086 89.68086 1
b 24.09879 24.09879 24.09879 24.09879 24.09879 24.09879 1
R 通常不能很好地扩展到大数据。您可能需要转向更高效的实施。周围有很多选择。但是,当然,可能还有各种 R 包可以帮助您更进一步。
此外,停止思考矩阵也是值得的。您正在使用的是一个图表。1 是边,0 不是。在这里加速计算相似性的一种简单方法是巧妙地利用相似性。这个顺便说一句。例如,通过在 Hadoop 中以“列形式”处理数据所获得的好处几乎是一样的。
当你意识到余弦相似度由三个分量组成:A 和 B 的乘积、A 的长度和 B 的长度时,你会注意到两部分独立于另一个向量,而第三部分具有平方稀疏性,这将大大减少余弦相似度“矩阵”所需的计算(再次,不要将其视为矩阵)
那么精简是:
或者:
并且一定要考虑如何在内存中存储和组织数据。在这里,快速数据访问和操作是成本的 90%,实际计算是微不足道的。不要让 R 自动执行它,因为这可能意味着它做错了……
mcl 软件 ( http://micans.org/mcl ) 的一部分是 mcxarray 程序,专门用于快速进行所有与所有比较,包括余弦相似度。它利用稀疏表示,并且可以在不同的 CPU(带有线程)和不同的机器(带有作业)上并行化,并且可以轻松地重新集成计算部分。免责声明 - 它是我写的。
我正在使用gensim,它非常适用于通常是高维和稀疏的文本数据