Apache spark 如何通过自定义行分组来简化PySpark中的EbyKey?
我有一个如下所示的数据框:Apache spark 如何通过自定义行分组来简化PySpark中的EbyKey?,apache-spark,pyspark,apache-spark-sql,rdd,Apache Spark,Pyspark,Apache Spark Sql,Rdd,我有一个如下所示的数据框: items_df ====================================================== | customer item_type brand price quantity | |====================================================| | 1 bread reems 20 10 | |
items_df
======================================================
| customer item_type brand price quantity |
|====================================================|
| 1 bread reems 20 10 |
| 2 butter spencers 10 21 |
| 3 jam niles 10 22 |
| 1 bread marks 16 18 |
| 1 butter jims 19 12 |
| 1 jam jills 16 6 |
| 2 bread marks 16 18 |
======================================================
我创建了一个rdd,将上述内容转换为dict:
rdd = items_df.rdd.map(lambda row: row.asDict())
结果如下:
[
{客户:1,商品类型:面包,品牌:reems,价格:20,数量:10},
{客户:2,商品类型:黄油,品牌:斯宾塞,价格:10,数量:21},
{客户:3,商品类型:果酱,品牌:尼尔斯,价格:10,数量:22},
{客户:1,商品类型:面包,品牌:商标,价格:16,数量:18},
{客户:1,商品类型:黄油,品牌:吉姆斯,价格:19,数量:12},
{客户:1,商品类型:果酱,品牌:吉尔,价格:16,数量:6},
{客户:2,商品类型:面包,品牌:商标,价格:16,数量:18}
]
我想先按客户对上述行进行分组。然后,我想介绍定制的新钥匙面包、黄油、果酱,并为该客户分组所有这些行。因此,我的rdd从7行减少到3行
输出如下所示:
items_df
======================================================
| customer item_type brand price quantity |
|====================================================|
| 1 bread reems 20 10 |
| 2 butter spencers 10 21 |
| 3 jam niles 10 22 |
| 1 bread marks 16 18 |
| 1 butter jims 19 12 |
| 1 jam jills 16 6 |
| 2 bread marks 16 18 |
======================================================
[
{
顾客:1,,
面包:[
{项目类型:面包,品牌:reems,价格:20,数量:10},
{项目类型:面包,品牌:标记,价格:16,数量:18},
],
黄油:[
{项目类型:黄油,品牌:吉姆斯,价格:19,数量:12}
],
堵塞:[
{项目类型:果酱,品牌:吉尔,价格:16,数量:6}
]
},
{
顾客:2,,
面包:[
{项目类型:面包,品牌:标记,价格:16,数量:18}
],
黄油:[
{项目类型:黄油,品牌:斯宾塞,价格:10,数量:21}
],
堵塞:[]
},
{
顾客:3,,
面包:[],
巴特斯:[],
堵塞:[
{项目类型:果酱,品牌:尼尔斯,价格:10,数量:22}
]
}
]
有人知道如何使用PySpark实现上述功能吗?我想知道是否有使用reduceByKey或类似的解决方案。如果可能的话,我希望避免使用groupByKey。首先向pivot dataframe添加一个列项类型
items_df=items_df.带有列'item_types',F.concatF.列'item_types',F.lit's'
展品
+----+-----+----+---+----+-----+
|客户|项目|类型|品牌|价格|数量|项目|类型|
+----+-----+----+---+----+-----+
|1 |面包|里姆斯| 20 | 10 |面包|
|2 |黄油|斯宾塞| 10 | 21 |黄油|
|3 |果酱|尼尔斯| 10 | 22 |果酱|
|1 |面包|标记| 16 | 18 |面包|
|1 |黄油|吉姆| 19 | 12 |黄油|
|1 |果酱|吉尔| 16 | 6 |果酱|
|2 |面包|标记| 16 | 18 |面包|
+----+-----+----+---+----+-----+
然后,您可以使用customer group透视表,并使用F.collect_list同时聚合其他列
items_df=items_df.groupby['customer'].pivotitem_types.agg
F.collect\u listF.structF.colitem\u type、F.colbrand、F.colprice、F.colquantity
.将“客户”分类
展品
+----+----------+----------+----------+
|顾客|面包|黄油|果酱|
+----+----------+----------+----------+
|面包,里姆斯,黄油,吉姆斯,果酱,吉尔斯,16|
|面包,马克,黄油,斯宾塞|
|果酱,尼尔斯,10|
+----+----------+----------+----------+
最后,需要设置recursive=True以将嵌套行转换为dict
rdd=items\u df.rdd.maplambda行:行。asDictrecursive=True
printrdd.take10
[{'客户]:1,
“面包”:[{'item_type':u'bread','brand':u'reems','price':20','quantity':10},
{'item_type':u'bread','brand':u'marks','price':16,'quantity':18}],
“黄油”:[{'item_type':u'butter','brand':u'jims','price':19,'quantity':12}],
“果酱”:[{'item_type':u'jam','brand':u'jills','price':16','quantity':6}]},
{'customer':2,
“面包”:[{'item_type':u'bread','brand':u'marks','price':16','quantity':18}],
“黄油”:[{'item_type':u'butter','brand':u'spencers','price':10,'quantity':21}],
“堵塞”:[]},
{'customer':3,
“面包”:[],
“黄油”:[],
“果酱”:[{'item_type':u'jam','brand':u'niles','price':10','quantity':22}]]
我还使用了另一种方法在rdd中使用reduceByKey。给定dataframe项_df,首先将其转换为rdd:
rdd = items_df.rdd.map(lambda row: row.asDict())
将每一行转换为tuple customer,[row_obj]其中row_obj位于列表中:
rdd = rdd.map(lambda row: ( row["customer"], [row] ) )
使用reduceByKey按客户分组,其中列表为给定客户连接:
rdd = rdd.reduceByKey(lambda x,y: x+y)
将元组转换回dict,其中键是customer,值是所有关联行的列表:
rdd = rdd.map(lambda tup: { tup[0]: tup[1] } )
由于每个客户数据现在都是一行,我们可以使用自定义函数将数据分离为面包、黄油、果酱:
def在客户视图中组织项目:
cust_id=listrow.keys[0]
项目=行[客户id]
new_cust_obj={客户:客户id,面包:[],黄油:[],果酱:[]
}
复数={面包:面包,黄油:黄油,果酱:果酱}
对于项目中的项目:
项目类型=项目[项目类型]
键=复数[项目类型]
新建客户对象[key]。追加项
返回新的客户对象
调用上述函数转换rdd:
rdd = rdd.map(organize_items_in_customer)
非常感谢@giser_yugang!这是一个很好的解释