【问题标题】:Explode dict from Pandas column从 Pandas 列中分解 dict
【发布时间】:2020-04-30 07:14:04
【问题描述】:

我有以下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')

但没有人给出类似的东西。有没有一种简单的方法可以将字典分解成列?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    假设我已经正确解释了您要执行的操作,您可以按如下方式实现:

    从(我假设!!)开始是您的输入数据集:

        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 返回许多行,而不是 pandas 试图将我们返回的内容解释为单行。感觉有点像 hack,但是,嘿,它有效!

    现在您可以根据计数和评分来获取列表值:

    tabulated= parsed.pivot_table(
        index='movie_id',
        columns=['age'],
        values=['avg_rating','count'],
        aggfunc='mean'
    )
    

    我在这里使用均值,sum 也可以假设每部电影和年龄组只有一行数据

    > 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
    

    【讨论】:

      猜你喜欢
      • 2021-10-06
      • 2018-06-20
      • 2019-08-25
      • 2022-11-07
      • 2013-12-18
      • 1970-01-01
      • 1970-01-01
      • 2020-12-31
      • 2020-04-10
      相关资源
      最近更新 更多