我有两个数据帧,即
df1 = sc.parallelize([
['u1', 'type1', ['a', 'b']],
['u2', 'type1', ['a', 'c', 'd']],
['u1', 'type2', ['d']]
]).toDF(('person', 'type', 'keywords'))
df2 = sc.parallelize([
['a', 2],
['b', 1],
['c', 0],
['d', 1],
['e', 3],
]).toDF(('keyword', 'score'))
我需要为每个person
和每type
计算其score
的平均keywords
。因此,person
'type1'上type
'u1'的平均值为1.5,因为它有关键字'a'和'b',贡献为2 + 1/2 = 1.5
我尝试了一种包含联接的方法:
df = df1.join(df2) \
.select('person', 'type', 'keywords', 'keyword', 'score') \
.groupBy('person', 'type') \
.agg(avg('score'))
但问题是,它是计算每个可能关键字的平均值,而不仅仅是那些表示用户和类型的关键字,因此我到处获得1.4,这是所有关键字的所有分数之和除以它们的数量。
我需要在每个用户的列表keywords
中仅对这些关键字的分数进行总结并输入。
答案 0 :(得分:2)
您必须首先explode
keywords
:
from pyspark.sql.functions import explode, avg, col
(df1.select("person", "type", explode("keywords").alias("keyword"))
.join(df2, "keyword")
.groupBy("person", "type")
.agg(avg("score")))
虽然可以做这样的事情
from pyspark.sql.functions import expr
(df1.join(df2, expr("array_contains(keywords, keyword)"))
.groupBy("person", "type")
.agg(avg("score")))
为了达到相同的效果,您希望在实践中避免使用它来避免扩展为笛卡尔积。