Scala Spark中两个稀疏向量的余弦相似度

时间:2018-12-15 18:07:42

标签: scala apache-spark cosine-similarity

我有一个包含两列的数据框,其中每一行都有一个稀疏向量。我试图找到一种正确的方法来计算每行中两个向量的余弦相似度(或只是点积)。

但是,我找不到用于稀疏向量的任何库或教程。

我发现的唯一方法是:

  1. 创建一个k X n矩阵,其中n个项被描述为k维向量。要将每个项目表示为k维向量,可以使用ALS来表示潜在因子空间中的每个实体。您可以选择该空间的尺寸(k)。这个k X n矩阵可以表示为RDD [Vector]。

  2. 将此k X n矩阵转换为RowMatrix。

  3. 使用columnSimilarities()函数获得n个项目之间相似度的n X n矩阵。

我觉得为每对计算所有余弦相似度是过大的,而我仅需要(相当大的)数据框中的特定对来计算。

3 个答案:

答案 0 :(得分:1)

@Sergey-Zakharov +1 上面的好答案。 一些附加组件:

  1. reduce doesn't 处理空序列。
  2. 确保计算 L2 规范化。
val normalizer = new Normalizer()
  .setInputCol("features")
  .setOutputCol("normFeatures")
  .setP(2.0)

val l2NormData = normalizer.transform(df_features)

val dotProduct = udf {(v1: SparseVector, v2: SparseVector) =>
    v1.indices.intersect(v2.indices).map(x => v1(x) * v2(x)).reduceOption(_ + _).getOrElse(0.0)
}

然后

val df = dfA.crossJoin(broadcast(dfB))
    .withColumn("dot", dotProduct(col("featuresA"), col("featuresB")))

答案 1 :(得分:0)

如果要用于计算点积的向量数量较少,请缓存RDD [Vector]表。创建一个新表[cosine_vectors],该表是原始表上的过滤器,仅选择想要余弦相似度的向量。广播将两者结合在一起进行计算。

答案 2 :(得分:0)

Spark 3中,现在有一个dot对象的方法SparseVector,它使用另一个向量作为其参数。

如果要在早期版本中执行此操作,可以创建一个遵循此算法的用户定义函数:

  • 采用向量索引的交集。
  • 根据相交处的索引获取向量值的两个子数组。
  • 对这两个子数组的元素进行成对乘法。
  • 将这些成对乘法所得的值相加。

这是我的认识:

import org.apache.spark.ml.linalg.SparseVector

def dotProduct(vec: SparseVector, vecOther: SparseVector) = {
    val commonIndices = vec.indices intersect vecOther.indices
    commonIndices.map(x => vec(x) * vecOther(x)).reduce(_+_)
}

我想您知道如何从此处将其转换为Spark UDF并将其应用于数据框的列。

如果在计算点积之前用org.apache.spark.ml.feature.Normalizer来对稀疏向量进行归一化,最终将得到余弦相似度(通过definition)。