Skip to main content
 首页 » 编程设计

python之在 spark 数据框中为用户的每个项目创建每一行

2024年10月17日27dyllove98

我有一个如下所示的 spark 数据框:

  User  Item    Purchased 
1   A   1 
1   B   2 
2   A   3 
2   C   4 
3   A   3 
3   B   2 
3   D   6 
 
only showing top 5 rows 

每个用户都有一行表示他们购买的商品。假设 Purhcased 是多少数量。购买(计数)。

但是,有些商品用户可能没有购买,因此对于该商品,特定用户没有一行。我们只有用户购买的商品的行。因此,如果用户 1 购买了商品 A、B,则用户 1 有 2 行对应于这两个商品。但是,如果用户 2 购买了 A、C,则用户 2 拥有商品 A 和 C 的行,但没有商品 B。我希望最后每个用户都应该拥有表中所有商品的所有行以及每个商品的相应计数。

我想将这个数据框转换成上面的数据框,但也有用户没有看到的项目行,并将相应的计数设为零。

如下所示:

User    Item    Purchased 
1   A   1 
1   B   2 
1   C   0 
1   D   0 
2   A   3 
2   C   4 
2   B   0 
2   D   0 
3   A   3 
3   B   2 
3   D   6 
3   C   0 
only showing top 5 rows 

我想到的一种方法是,如果我在第一个数据帧上使用 sqlContext 的 cross_tab 方法,那么我可以将每一行转换为具有相应值的列。对于用户没有的项目,它将为相同的项目创建一个列并将零放在那里。

但是如何将这些列转换回行呢?这也可能是一种迂回的方式。

谢谢

请您参考如下方法:

我们也可以通过仅使用 df 函数来实现这一点。

orders = [(1,"A",1),(1,"B",2),(2,"A",3),(2,"C",4),(3,"A",3),(3,"B",2),(3,"D",6)] 
df = sqlContext.createDataFrame(orders, ["user","item","purchased"]) 
df_items = df.select("item").distinct().repartition(5).withColumnRenamed("item", "item_1") 
df_users = df.select("user").distinct().repartition(5).withColumnRenamed("user", "user_1") 
df_cartesian = df_users.join(df_items) 
//above expression returns cartesian product of users and items dfs 
joined_df = df_cartesian.join(df, [df_cartesian.user_1==df.user, df_cartesian.item_1==df.item], "left_outer").drop("user").drop("item") 
result_df = joined_df.fillna(0,["purchased"]).withColumnRenamed("item_1", "item").withColumnRenamed("user_1", "user") 

最后,result_df.show() 产生如下所示的期望输出:

+----+----+---------+ 
|user|item|purchased| 
+----+----+---------+ 
|   2|   A|        3| 
|   2|   B|        0| 
|   2|   C|        4| 
|   2|   D|        0| 
|   3|   A|        3| 
|   3|   B|        2| 
|   3|   C|        0| 
|   3|   D|        6| 
|   1|   A|        1| 
|   1|   B|        2| 
|   1|   C|        0| 
|   1|   D|        0| 
+----+----+---------+