我有以下df:
movie_id rating_all
0 tt7653254 [{'age': 'all', 'avg_rating': 8.1, 'count': 109326}, {'age': '<18', 'avg_rating': 8.8, 'count': 318}, {'age': '18-29', 'avg_rating': 8.3, 'count': 29740}, {'age': '30-44', 'avg_rating': 8.0, 'count': 33012}, {'age': '45+', 'avg_rating': 7.7, 'count': 7875}]
1 tt8579674 [{'age': 'all', 'avg_rating': 8.6, 'count': 9420}, {'age': '<18', 'avg_rating': 9.1, 'count': 35}, {'age': '18-29', 'avg_rating': 8.7, 'count': 2437}, {'age': '30-44', 'avg_rating': 8.5, 'count': 2529}, {'age': '45+', 'avg_rating': 8.3, 'count': 960}]
2 tt7286456 [{'age': 'all', 'avg_rating': 8.6, 'count': 592441}, {'age': '<18', 'avg_rating': 9.1, 'count': 2244}, {'age': '18-29', 'avg_rating': 8.7, 'count': 160506}, {'age': '30-44', 'avg_rating': 8.5, 'count': 160158}, {'age': '45+', 'avg_rating': 8.3, 'count': 30451}]
3 tt1302006 [{'age': 'all', 'avg_rating': 8.1, 'count': 187675}, {'age': '<18', 'avg_rating': 8.7, 'count': 461}, {'age': '18-29', 'avg_rating': 8.3, 'count': 41951}, {'age': '30-44', 'avg_rating': 7.9, 'count': 59729}, {'age': '45+', 'avg_rating': 7.8, 'count': 18550}]
4 tt7131622 [{'age': 'all', 'avg_rating': 7.8, 'count': 323152}, {'age': '<18', 'avg_rating': 8.4, 'count': 955}, {'age': '18-29', 'avg_rating': 7.9, 'count': 82133}, {'age': '30-44', 'avg_rating': 7.6, 'count': 95878}, {'age': '45+', 'avg_rating': 7.5, 'count': 26383}]
5 tt8637428 [{'age': 'all', 'avg_rating': 7.7, 'count': 21362}, {'age': '<18', 'avg_rating': 8.0, 'count': 45}, {'age': '18-29', 'avg_rating': 7.9, 'count': 5901}, {'age': '30-44', 'avg_rating': 7.6, 'count': 6492}, {'age': '45+', 'avg_rating': 7.3, 'count': 2133}]
我想将其转换为:
movie_id all_avg all_count <18_avg <18_count 18-29_avg
0 tt7653254 8.1 109326 8.8 318 8.3
1 tt8579674 8.6 9420 9.1 35 8.7
2 tt7286456 8.6 592441 9.1 2244 8.7
3 tt1302006 8.1 187675 8.7 461 8.3
4 tt7131622 7.8 323152 8.4 955 7.9
5 tt8637428 7.7 21362 8 45 7.9
以此类推...
我尝试过
ratings.set_index('movie_id')['rating_all'].apply(pd.Series).reset_index()
并使用
json_normalize(data,
record_path=['rating_all'],
meta=['movie_id']).set_index('movie_id')
但没有人提供类似的东西。有没有简单的方法可以将字典分解为列?
答案 0 :(得分:2)
假设我已经正确解释了您要尝试执行的操作,则可以按以下步骤实现它:
从(我假设!! )开始是您的输入数据集:
movie_id ratings
0 tt7653254 [{'age': 'all', 'avg_rating': 8.1, 'count': 10...
1 tt8579674 [{'age': 'all', 'avg_rating': 8.6, 'count': 94...
2 tt7286456 [{'age': 'all', 'avg_rating': 8.6, 'count': 59...
3 tt1302006 [{'age': 'all', 'avg_rating': 8.1, 'count': 18...
4 tt7131622 [{'age': 'all', 'avg_rating': 7.8, 'count': 32...
5 tt8637428 [{'age': 'all', 'avg_rating': 7.7, 'count': 21...
其中收视率值是实际列表,而不是字符串(如果它们是字符串,请x['ratings'] = x.ratings.apply(eval)
将其变成对象)。
首先,您希望将列表中的每一行爆炸为一组行:
parsed = x.groupby('movie_id').ratings.apply(lambda x: pd.DataFrame(x.values[0])).reset_index()
哪个会给你:
> parsed.head(10)
movie_id level_1 age avg_rating count
0 tt1302006 0 all 8.1 187675
1 tt1302006 1 <18 8.7 461
2 tt1302006 2 18-29 8.3 41951
3 tt1302006 3 30-44 7.9 59729
4 tt1302006 4 45+ 7.8 18550
5 tt7131622 0 all 7.8 323152
6 tt7131622 1 <18 8.4 955
7 tt7131622 2 18-29 7.9 82133
8 tt7131622 3 30-44 7.6 95878
9 tt7131622 4 45+ 7.5 26383
...
等
这是关键步骤。这与您尝试过的apply(pd.Series)
步骤相似,但不同之处在于groupby
。这使我们可以为每个movie_id返回许多行,而不是熊猫试图将返回的内容解释为单行。感觉有点像骇客,但嘿,行得通!
现在,您可以根据计数和等级来获取列表值:
tabulated= parsed.pivot_table(
index='movie_id',
columns=['age'],
values=['avg_rating','count'],
aggfunc='mean'
)
我在这里使用的意思是,总和也可以工作假设每个电影和年龄段只有一行数据
> tabulated
avg_rating count
age 18-29 30-44 45+ <18 all 18-29 30-44 45+ <18 all
movie_id
tt1302006 8.3 7.9 7.8 8.7 8.1 41951 59729 18550 461 187675
tt7131622 7.9 7.6 7.5 8.4 7.8 82133 95878 26383 955 323152
tt7286456 8.7 8.5 8.3 9.1 8.6 160506 160158 30451 2244 592441
tt7653254 8.3 8.0 7.7 8.8 8.1 29740 33012 7875 318 109326
tt8579674 8.7 8.5 8.3 9.1 8.6 2437 2529 960 35 9420
tt8637428 7.9 7.6 7.3 8.0 7.7 5901 6492 2133 45 21362