我具有以下数据框,我希望从字典中映射该列。
data = [
('web', '0'),
('web', '1'),
('web', '2'),
('twitter', '0'),
('twitter', '1'),
('facebook', '0'),
('facebook', '1'),
('facebook','2')
]
data = (spark.createDataFrame(data, ['channel','type']))
我有下面的字典,我想根据“通道”列的值映射字典中的值
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))
)
最终结果应该是,如果“通道”列具有web,那么列“类型具有0”,那么通道类型应该是“网站”
答案 0 :(得分:1)
一种方法是通过联接数据框,但我不建议这样做,因为仅联接到地图将是一项繁重的操作
其他方法是使用UDF,这也是最不推荐使用的UDF,因为UDF是黑匣子,无法通过催化剂优化程序进行优化,但是解决方案仍然如此
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|
+--------+----+-----------+
答案 1 :(得分:0)
是否可以以稍微不同的方式重构字典,必须使用简单的python代码才能实现。然后,您可以从中创建一个数据框并加入。否则,将需要昂贵的udf。由于此表很小,因此您也可以进行广播联接。(此处未显示)
data = [
('web', '0'),
('web', '1'),
('twitter', '0'),
('twitter', '1')
]
data_df = (sqlContext.createDataFrame(data, ['channel','type']))
# Changed dictionary structure
conf = [{"channel": 'web', 'type': 0, 'result': 'webbsite'},
{"channel": 'web', 'type': 1, 'result': 'news'},
{"channel": 'twitter', 'type': 0, 'result': 'tweet'},
{"channel": 'twitter', 'type': 1, 'result': 'retweet'}]
conf_df = sqlContext.createDataFrame(data_sub)
data_res = data_df.join(conf_df,on=['channel','type'],how='left')
结果:
data_res.show()
+-------+----+--------+
|channel|type| result|
+-------+----+--------+
| web| 1| news|
|twitter| 0| tweet|
| web| 0|webbsite|
|twitter| 1| retweet|
+-------+----+--------+