我有一个pyspark数据框,看起来像这样:
data = [{'event_id':0, 'bid_0_a':1, 'bid_0_b':2, 'bid_1_a':1, 'bid_1_b':2},
{'event_id':1, 'bid_0_a':1, 'bid_0_b':2, 'bid_1_a':1, 'bid_1_b':2}]
schema = T.StructType([T.StructField(nm, T.IntegerType(), True)
for nm in ['event_id', 'bid_0_a', 'bid_0_b', 'bid_1_a', 'bid_1_b']])
df3 = spark.createDataFrame(data,
schema=schema)
即
+--------+-------+-------+-------+-------+
|event_id|bid_0_a|bid_0_b|bid_1_a|bid_1_b|
+--------+-------+-------+-------+-------+
| 0| 1| 2| 1| 2|
| 1| 1| 2| 1| 2|
+--------+-------+-------+-------+-------+
真实桌面每个活动有很多出价,还有更多的出价字段(超过a和b)。最后,我想对出价进行分类,并在每个类别中进行一些汇总。我想我首先需要爆炸这些列,这就产生了一个像:
这样的表+--------+---+--+--+
|event_id|bid| a| b|
+--------+---+--+--+
| 0 | 0 | 1| 2|
| 0 | 1 | 1| 2|
| 1 | 0 | 1| 2|
| 1 | 1 | 1| 2|
+--------+---+--+--+
我可以想象这样做,但我想知道是否有更快的pyspark SQL方法来做到这一点?也许如果我将_ * _列的出价收集到地图或数组中,我可以使用explode
?
答案 0 :(得分:0)
这是使用create_map()
,explode()
和pivot()
的有点hacky解决方案。我说有点hacky,因为我依靠max()
函数来聚合,当你的列名称是唯一的时,它应该工作,但我觉得应该有更好的方法。
首先从列中创建一个地图字段。您必须有一个bid_ids
列表。
import pyspark.sql.functions as f
from operator import add
bid_ids = ['0', '1']
df4 = df3.withColumn(
'map',
f.create_map(
*(reduce(
add,
[[f.lit(b),
f.create_map(f.lit('a'),
f.col('bid_%s_a'%b),
f.lit('b'),
f.col('bid_%s_b'%b))
] for b in bid_ids
]
))
)
)
df4.select('event_id', 'map').show(truncate=False)
#+--------+-------------------------------------------------------+
#|event_id|map |
#+--------+-------------------------------------------------------+
#|0 |Map(0 -> Map(a -> 1, b -> 2), 1 -> Map(a -> 1, b -> 2))|
#|1 |Map(0 -> Map(a -> 1, b -> 2), 1 -> Map(a -> 1, b -> 2))|
#+--------+-------------------------------------------------------+
现在调用explode()
两次(因为地图是嵌套的)。如果不清楚,可以打印出中间步骤(这里省略)。
df4 = df4.select('event_id', f.explode('map'))\
.select('event_id', f.col('key').alias('bid'), f.explode('value'))
df4.show(truncate=False)
#+--------+---+---+-----+
#|event_id|bid|key|value|
#+--------+---+---+-----+
#|0 |0 |a |1 |
#|0 |0 |b |2 |
#|0 |1 |a |1 |
#|0 |1 |b |2 |
#|1 |0 |a |1 |
#|1 |0 |b |2 |
#|1 |1 |a |1 |
#|1 |1 |b |2 |
#+--------+---+---+-----+
数据采用此格式后,您可以拨打groupBy()
和pivot()
。您需要汇总作为分组,因此我选择max()
- 它不应该重要,因为每个(event_id, bid, key)
组应该只有一个值。
df4.groupBy('event_id', 'bid').pivot('key').max('value').show()
#+--------+---+---+---+
#|event_id|bid| a| b|
#+--------+---+---+---+
#| 1| 0| 1| 2|
#| 0| 1| 1| 2|
#| 0| 0| 1| 2|
#| 1| 1| 1| 2|
#+--------+---+---+---+