我有一个包含两列的数据框,其中每一行都有一个稀疏向量。我试图找到一种正确的方法来计算每行中两个向量的余弦相似度(或只是点积)。
但是,我找不到用于稀疏向量的任何库或教程。
我发现的唯一方法是:
创建一个k X n矩阵,其中n个项被描述为k维向量。要将每个项目表示为k维向量,可以使用ALS来表示潜在因子空间中的每个实体。您可以选择该空间的尺寸(k)。这个k X n矩阵可以表示为RDD [Vector]。
将此k X n矩阵转换为RowMatrix。
使用columnSimilarities()函数获得n个项目之间相似度的n X n矩阵。
我觉得为每对计算所有余弦相似度是过大的,而我仅需要(相当大的)数据框中的特定对来计算。
答案 0 :(得分:1)
@Sergey-Zakharov +1 上面的好答案。 一些附加组件:
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)。