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

时间:2018-09-27 18:13:58

标签: python apache-spark pyspark apache-spark-sql

我有一个PySpark DataFrame 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

1 个答案:

答案 0 :(得分: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

相似度值较大是由于维数较低(仅两个分量)。