Pandas 使用pyspark将用户项目评级列表转换为用户项目矩阵

Pandas 使用pyspark将用户项目评级列表转换为用户项目矩阵,pandas,apache-spark,pyspark,apache-spark-sql,pyspark-sql,Pandas,Apache Spark,Pyspark,Apache Spark Sql,Pyspark Sql,这就是用户项目分级列表作为数据框的外观 item_id rating user_id 0 aaaaaaa 5 X 1 bbbbbbb 2 Y 2 ccccccc 5 Z 3 ddddddd 1 T from pyspark.sql.functions import first df.groupby('user_id') \ .pivot('item_id') \ .agg(

这就是用户项目分级列表作为数据框的外观

   item_id  rating user_id
0  aaaaaaa       5       X
1  bbbbbbb       2       Y
2  ccccccc       5       Z
3  ddddddd       1       T
from pyspark.sql.functions import first

df.groupby('user_id') \
  .pivot('item_id') \
  .agg(first('rating'))
这就是我在pandas中创建用户项矩阵的方法,使用真实数据集(大约500k行)只需几秒钟:

我正在尝试这种方法来实现与pyspark dataframe相同的结果

   item_id  rating user_id
0  aaaaaaa       5       X
1  bbbbbbb       2       Y
2  ccccccc       5       Z
3  ddddddd       1       T
from pyspark.sql.functions import first

df.groupby('user_id') \
  .pivot('item_id') \
  .agg(first('rating'))

但要用真实的数据完成这项工作需要很多时间。有没有更聪明/更快的方法来实现这一点?基本上,我正在尝试从用户项目评级列表构建用户项目矩阵。

这是一种基于RDD的替代方法

rating_list = [['aaa',5.0,'T'],['bbb',5.0,'U'],['ccc',5.0,'V'],['ddd',5.0,'W'],['eee',5.0,'X']]
df = sc.parallelize(rating_list).toDF(['item_id','rating','user_id'])
df.show()

+-------+------+-------+
|item_id|rating|user_id|
+-------+------+-------+
|    aaa|   5.0|      T|
|    bbb|   5.0|      U|
|    ccc|   5.0|      V|
|    ddd|   5.0|      W|
|    eee|   5.0|      X|
+-------+------+-------+


items = df.select('item_id').rdd.map(lambda data:data.item_id).collect()
item_len = len(items)

def transformRating(item_id,rating,user_id):
    rating_list = [rating if ele == item_id else None for ele in items]
    return ([user_id]+rating_list)

df1 = (df.rdd.map(lambda data:(data.item_id,data.rating,data.user_id))
             .map(lambda (item,rat,uid):transformRating(item,rat,uid))
             .toDF(['uid']+items))

df1.show()

+---+----+----+----+----+----+
|uid| aaa| bbb| ccc| ddd| eee|
+---+----+----+----+----+----+
|  T| 5.0|null|null|null|null|
|  U|null| 5.0|null|null|null|
|  V|null|null| 5.0|null|null|
|  W|null|null|null| 5.0|null|
|  X|null|null|null|null| 5.0|
+---+----+----+----+----+----+

现在我假设一个用户可能会对多个项目进行评分。在这种情况下,您可能需要根据用户id减少RDD并合并评级。它只是在.toDF之前的一个reduceByKey语句,您应该得到这样一个df。

这是一种基于RDD的替代方法

rating_list = [['aaa',5.0,'T'],['bbb',5.0,'U'],['ccc',5.0,'V'],['ddd',5.0,'W'],['eee',5.0,'X']]
df = sc.parallelize(rating_list).toDF(['item_id','rating','user_id'])
df.show()

+-------+------+-------+
|item_id|rating|user_id|
+-------+------+-------+
|    aaa|   5.0|      T|
|    bbb|   5.0|      U|
|    ccc|   5.0|      V|
|    ddd|   5.0|      W|
|    eee|   5.0|      X|
+-------+------+-------+


items = df.select('item_id').rdd.map(lambda data:data.item_id).collect()
item_len = len(items)

def transformRating(item_id,rating,user_id):
    rating_list = [rating if ele == item_id else None for ele in items]
    return ([user_id]+rating_list)

df1 = (df.rdd.map(lambda data:(data.item_id,data.rating,data.user_id))
             .map(lambda (item,rat,uid):transformRating(item,rat,uid))
             .toDF(['uid']+items))

df1.show()

+---+----+----+----+----+----+
|uid| aaa| bbb| ccc| ddd| eee|
+---+----+----+----+----+----+
|  T| 5.0|null|null|null|null|
|  U|null| 5.0|null|null|null|
|  V|null|null| 5.0|null|null|
|  W|null|null|null| 5.0|null|
|  X|null|null|null|null| 5.0|
+---+----+----+----+----+----+

现在我假设一个用户可能会对多个项目进行评分。在这种情况下,您可能需要根据用户id减少RDD并合并评级。这只是前面的一个reduceByKey语句。toDF,你应该得到这样一个df。

我希望它能起作用:(我希望它能起作用:(必须有一种更简洁的方法来做到这一点。特别是推荐系统和矩阵分解方法需要实现这一效果。我可以想象一种更精简的方法确实存在。而且,这会引发一个错误;python或至少google colab,看不到
lamba(item,rat,uid)
可以接受。@mjake取决于python版本。在撰写本文时,它使用的是python 2.7或python 3.1或其他不记得的工具。您可以轻松地将其更改为(lambda数据:数据[0]、数据[1]、数据[2])而且应该可以很好地工作!@mjake这个问题是2年前提出来的。从那时起,pyspark已经发展起来,你有了诸如explode和其他功能……你可以对此进行探索。现在肯定有一种简单的方法可以用数据帧来做这件事。必须有一种更简洁的方法来做这件事。推荐系统和矩阵分解方法,特别是,n我想一个更精简的方法确实存在。而且,这会抛出一个错误;python或者至少google colab,没有看到
lamba(item,rat,uid)
可以接受。@mjake取决于python版本。在撰写本文时,它使用的是python 2.7或python 3.1或其他不记得的工具。您可以轻松地将其更改为(lambda数据:数据[0]、数据[1]、数据[2])而且应该可以很好地工作!@mjake这个问题是2年前提出的。从那时起,pyspark已经发展起来,您可以使用explode和其他功能……您可以对此进行探索。现在肯定有一种简单的方法可以使用数据帧来实现这一点。