有没有更有效的方式在PySpark 1.6中实现余弦相似度?

问题描述

我试图计算用户表中给定的user_id与带有电影的另一个表之间的余弦相似度,以便挑选出最相似的电影来推荐。

余弦相似度:= dot(a,b) / (norm(a) * norm(b))dot(a,b)/sqrt((dot(a)*dot(b))

df = self.given_user.crossJoin(self.movies_df)
df = df.select('userId','movieId','user_features','movie_features')
df = df.rdd.map(lambda x: (x[0],x[1],x[2],x[3],float(np.dot(np.array(x[2]),np.array(x[3]))))).toDF(df.columns + ['dotxy'])
df = df.rdd.map(lambda x: (x[0],x[4],np.array(x[2]))))).toDF(df.columns + ['dotxx'])
df = df.rdd.map(lambda x: (x[0],x[5],float(np.dot(np.array(x[3]),np.array(x[3]))))).toDF(df.columns + ['dotyy'])
output = df.withColumn('cosine_sim',F.col("dotxy") / F.sqrt(F.col("dotxx") * F.col("dotyy")))

output.select('userId','dotxy','dotxx','dotyy','cosine_sim').orderBy('cosine_sim',ascending=False).show(5)

结果输出如下:

+------+-------+-----+-----+-----+----------+
|userId|movieId|dotxy|dotxx|dotyy|cosine_sim|
+------+-------+-----+-----+-----+----------+
|    18|   1430|  1.0|  0.5|  2.0|       1.0|
|    18|   2177|  1.0|  0.5|  2.0|       1.0|
|    18|   1565|  1.0|  0.5|  2.0|       1.0|
|    18|    415|  1.0|  0.5|  2.0|       1.0|
|    18|   1764|  1.0|  0.5|  2.0|       1.0|
+------+-------+-----+-----+-----+----------+

PySpark 1.6中是否存在更有效/更紧凑的余弦相似度函数实现方式?

解决方法

您可以使用更多numpy函数。

import numpy as np

df = spark.createDataFrame([(18,1,[1,1],1])]).toDF('userId','movieId','user_features','movie_features')

df.rdd.map(lambda x: (x[0],x[1],x[2],x[3],float(np.dot(np.array(x[2]),np.array(x[3])) / (np.linalg.norm(np.array(x[2])) * np.linalg.norm(np.array(x[3])))))).toDF(df.columns + ['cosine_sim']).show()

+------+-------+-------------+--------------+------------------+
|userId|movieId|user_features|movie_features|       cosine_sim |
+------+-------+-------------+--------------+------------------+
|    18|      1|    [1,1]|     [1,1]|0.8164965809277259|
+------+-------+-------------+--------------+------------------+