两个 pyspark 数据帧的余弦相似度

Posted

技术标签:

【中文标题】两个 pyspark 数据帧的余弦相似度【英文标题】:Cosine Similarity for two pyspark dataframes 【发布时间】:2018-09-27 18:13:58 【问题描述】:

我有一个 PySpark 数据帧 df1,它看起来像:

CustomerID  CustomerValue CustomerValue2 
12          .17           .08

我有第二个 PySpark DataFrame,df2

 CustomerID  CustomerValue CustomerValue
 15          .17           .14
 16          .40           .43
 18          .86           .09

我想取两个数据帧的余弦相似度。并且有类似的东西

 CustomerID  CustomerID   CosineCustVal CosineCustVal
 15          12           1            .90
 16          12           .45          .67
 18          12           .8           .04

【问题讨论】:

你有没有尝试过? datascience.stackexchange.com/questions/13347/… 很遗憾,但它无法正常工作。我认为的另一个解决方案是转换列表中的第一个 df 并采用余弦相似度,但我想避免这种方式 您的第一个数据框只有一行?此外,这是您决定加入两者的共同列,因为CustomerID 没有任何共同值。 是的,它只有一行。问题是我不想加入这两个 dfs,因为他们确实没有相同的 CustomerID @mayankagrawal 如果只有一行,最好把它收集成列表或类似的结构,然后计算。无需为单行创建 spark 数据框。 【参考方案1】:

您只能计算两个向量的余弦相似度,而不是两个数字。也就是说,如果名为 CustomerValue 的列是代表您希望获得两个客户之间相似性的特征的向量的不同组件,您可以通过转置数据框然后在 CuatomerValues 上进行连接来实现。

转置可以通过爆炸来完成(有关转置数据框here的更多详细信息):

from pyspark.sql import functions as F

kvs = F.explode(F.array([
        F.struct(F.lit(c).alias('key'), F.columm(c).alias('value')) for c in ['CustomerValue1', 'CustomerValue2']
      ])).alias('kvs')

dft1 = (df1.select(['CustomerID', kvs])
        .select('CustomerID', F.column('kvs.name').alias('column_name'), F.column('kvs.value').alias('column_value'))
        )
dft2 = (df2.select(['CustomerID', kvs])
        .select('CustomerID', F.column('kvs.name').alias('column_name'), F.column('kvs.value').alias('column_value'))
        )

其中dft1dft2 表示转置后的数据帧。转置后,您可以在列名上加入它们:

dft2 = (dft2.withColumnRenamed('CustomerID', 'CustomerID2')
        .withColumnRenamed('column_value', 'column_value2')
       )
cosine = (dft1.join(dft2, dft1.column_name = dft2.column_name)
          .groupBy('CustomerID' , 'CustomerID2')
          .agg(F.sum(F.column('column_value')*F.column('column_value2')).alias('cosine_similarity'))
         )

现在在cosine 中,您有三列:来自第一个和第二个数据帧的 CustomerID 和余弦相似度(前提是首先对值进行标准化)。这样做的好处是您只有具有非零相似性的 CustomerID 对的行(如果某些 CustomerID 的值为零)。以您为例:

df1:

CustomerID CustomerValue CustomerValue2
12         .17           .08

df2:

CustomerID CustomerValue CustomerValue
15         .17           .14
16         .40           .43
18         .86           .09

余弦:

CustomID CustomID2 cosine_similarity
12       15        .0401
12       16        .1024
12       18        .1534

当然,这些还不是真正的余弦相似度,您需要先对值进行归一化。您可以通过以下方式与组一起执行此操作:

(df.groupBy('CustomerID')
 .agg(F.sqrt(F.sum(F.column('column_value')*F.column('column_value'))).alias('norm'))
 .select('CustomerID', F.column('column_name'), (F.column('column_value')/F.column('norm')).alias('column_value_norm'))
)

对列进行标准化后,您的余弦相似度如下:

CustomID CustomID2 cosine_similarity
12       15        .970
12       16        .928
12       18        .945

大的相似性值是由于低维(只有两个组件)。

【讨论】:

以上是关于两个 pyspark 数据帧的余弦相似度的主要内容,如果未能解决你的问题,请参考以下文章

PySpark中如何计算两个向量的余弦相似度?

PYSPARK:如何在 pyspark 数据框中找到两列的余弦相似度?

Spark笔记(1) :余弦相似度计算

余弦相似度的应用

余弦计算相似度理解以及计算

余弦相似度计算