基于条件映射pyspark数据帧列中字典中的值
我有下面的数据框,我想从字典映射列基于条件映射pyspark数据帧列中字典中的值,pyspark,Pyspark,我有下面的数据框,我想从字典映射列 data = [ ('web', '0'), ('web', '1'), ('web', '2'), ('twitter', '0'), ('twitter', '1'), ('facebook', '0'), ('facebook', '1'), ('facebook','2') ] data = (spark.createDataFrame(data, ['channel','type'])) 我有下
data = [
('web', '0'),
('web', '1'),
('web', '2'),
('twitter', '0'),
('twitter', '1'),
('facebook', '0'),
('facebook', '1'),
('facebook','2')
]
data = (spark.createDataFrame(data, ['channel','type']))
我有下面的字典,我希望字典中的值基于列“channel”的值进行映射
conf = {'channel_type':
{'web': {'0': 'website', '1': 'news', '2': 'blogs'},
'twitter': {'0': 'tweet', '1': 'retweet'},
'facebook': {'0': 'post',
'1': 'feed_post',
'2': 'comment',
'3': 'shared_post'},
'you_tube': {'0': 'comment'},
'instagram': {'0': 'video', '1': 'media', '2': 'comment'},
'reddit': {'0': 'reddit_post', '1': 'reddit_comment'},
'linkedin': {'0': 'linkedin_articles',
'1': 'linkedin_rich',
'2': 'linkedin_comments'}}
}
我已经尝试了下面的代码,但没有成功
mapping_expr_twitter = f.create_map([lit(x) for x in chain(*conf['channel_type']['twitter'].items())])
mapped_cols = (data.withColumn('channel_type', f.when(f.col('channel')=='twitter',
mapping_expr_twitter.getItem(f.col("type")))
.otherwsie(None))
)
最终结果应该是,如果列“channel”有web,那么列“type”有0,那么通道类型应该是“website”是否可以稍微改变字典的结构,必须使用简单的python代码才能实现。然后,您可以从中创建一个数据帧并进行连接。否则,将需要成本高昂的udf。由于这个表很小,您也可以进行广播连接。(此处未显示) 结果是:
data_res.show()
+-------+----+--------+
|channel|type| result|
+-------+----+--------+
| web| 1| news|
|twitter| 0| tweet|
| web| 0|webbsite|
|twitter| 1| retweet|
+-------+----+--------+
一种方法是加入dataframe,但我不建议这样做,因为仅仅加入map将是一项繁重的操作 另一种方法是使用UDF,这也是最不推荐的,因为UDF是blackbox,不能由catalyst optimizer优化,但解决方案仍然如下所示
map_func = f.udf(lambda channel,typ : conf['channel_type'].get(channel,channel).get(typ,typ))
data.withColumn('ChannelType',map_func(f.col('channel'),f.col('type'))).show()
+--------+----+-----------+
| channel|type|ChannelType|
+--------+----+-----------+
| web| 0| website|
| web| 1| news|
| web| 2| blogs|
| twitter| 0| tweet|
| twitter| 1| retweet|
|facebook| 0| post|
|facebook| 1| feed_post|
|facebook| 2| comment|
+--------+----+-----------+
另一种方法是使用create_map,这在本例中是最首选的
from itertools import chain
conf_mapper = f.create_map([f.lit(i) for i in chain(*{k+x:y for k,v in conf['channel_type'].items() for x,y in v.items()}.items())])
data.withColumn('ChannelType',conf_mapper[f.concat('channel','type')]).show()
+--------+----+-----------+
| channel|type|ChannelType|
+--------+----+-----------+
| web| 0| website|
| web| 1| news|
| web| 2| blogs|
| twitter| 0| tweet|
| twitter| 1| retweet|
|facebook| 0| post|
|facebook| 1| feed_post|
|facebook| 2| comment|
+--------+----+-----------+
from itertools import chain
conf_mapper = f.create_map([f.lit(i) for i in chain(*{k+x:y for k,v in conf['channel_type'].items() for x,y in v.items()}.items())])
data.withColumn('ChannelType',conf_mapper[f.concat('channel','type')]).show()
+--------+----+-----------+
| channel|type|ChannelType|
+--------+----+-----------+
| web| 0| website|
| web| 1| news|
| web| 2| blogs|
| twitter| 0| tweet|
| twitter| 1| retweet|
|facebook| 0| post|
|facebook| 1| feed_post|
|facebook| 2| comment|
+--------+----+-----------+