【问题标题】:Python pandas, how to unpack pandas column with json to new dataframe in most efficient way?Python pandas,如何以最有效的方式将带有json的pandas列解压缩到新的数据框?
【发布时间】:2020-01-16 14:22:42
【问题描述】:

我有一个清单:

data_list= [
        {
           'fields': {
               'standard': ['ADSL1'],
               'serviceCode': ['BNG_DSL'],
               'deltaUpload': [0]
                    }
        },
        {
            'fields': {
                'standard': ['ADSL1'],
                'serviceCode': ['BNG_DSL'],
                'deltaUpload': [545618]
                }
        },
        {
            'fields': {
                'standard': ['ADSL1'],
                'serviceCode': ['BNG_DSL'],
                'deltaUpload': [597561]
                }
        },
        {
            'fields': {
                'standard': ['ADSL1'],
                'serviceCode': ['BNG_DSL'],
                'deltaUpload': [323771]
                }
        },    
        {
           'fields': {
               'standard': ['ADSL1'],
               'serviceCode': ['BNG_DSL'],
               'deltaUpload': [1088]
                }
        }
    ]

从这个列表中我创建了一个数据框:

从 df.fields 系列我想创建一个新的数据框。 我试过:

一切正常,但我不希望每个单元格都在列表中。 我试过了:

...由于数以千万计的数据行,它可以工作,但速度很慢。 是否有矢量化的方法可以从 data_list 中创建没有单元格列表的字段数据框?

【问题讨论】:

    标签: json python-3.x pandas


    【解决方案1】:

    你可以使用:

    df = pd.DataFrame(data_list)
    out = pd.DataFrame(df['fields'].tolist()).stack().str[0].unstack()
    

      standard serviceCode deltaUpload
    0    ADSL1     BNG_DSL           0
    1    ADSL1     BNG_DSL      545618
    2    ADSL1     BNG_DSL      597561
    3    ADSL1     BNG_DSL      323771
    4    ADSL1     BNG_DSL        1088
    

    我们也可以尝试使用infer_objects推断正确的dtypes

    out1 = (pd.DataFrame(df['fields'].tolist()).stack().str[0]
                      .astype(object).unstack().infer_objects())
    

    我们也可以直接pd.io.json.json_normalize

    df = pd.io.json.json_normalize(data_list).rename(columns=lambda x: x.split('.')[1])
    df.stack().str[0].astype(object).unstack().infer_objects()
    

    print(out.dtypes)
    #standard       object
    #serviceCode    object
    #deltaUpload    object
    #dtype: object
    
    print(out1.dtypes)
    #standard       object
    #serviceCode    object
    #deltaUpload     int64
    dtype: object
    

    【讨论】:

    • 它有效,但我想避免使用 tolist()、stack()、str[0] 和 unstack()。字段 json 比我在这里介绍的要大得多,所以我必须非常小心系统的性能。
    • @user3225309 嗯,这应该比你当前的代码更快,你也可以试试pd.DataFrame(df['fields'].tolist()).applymap(lambda x: x[0])
    【解决方案2】:

    pandas 中的 json_normalize 函数并不是特别快。我建议您将初始数据减少到列表或字典,然后创建您的数据框:

    d = [(i['fields']['standard'][0],
          i['fields']['serviceCode'][0],
          i['fields']['deltaUpload'][0]) 
         if i['fields']['standard'] else '' 
         if i['fields']['serviceCode'] else '' 
         if i['fields']['deltaUpload'] else ''
         for i in data_list ]
    
    d
    
    [('ADSL1', 'BNG_DSL', 0),
     ('ADSL1', 'BNG_DSL', 1088),
     ('ADSL1', 'BNG_DSL', 323771),
     ('ADSL1', 'BNG_DSL', 545618),
     ('ADSL1', 'BNG_DSL', 597561)]
    
    df = pd.DataFrame(d)
    
    df.columns = ['standard','serviceCode','deltaUpload']
    
    
       standard  serviceCode    deltaUpload
    0   ADSL1     BNG_DSL        545618
    1   ADSL1     BNG_DSL        1088
    2   ADSL1     BNG_DSL        323771
    3   ADSL1     BNG_DSL        597561
    4   ADSL1     BNG_DSL         0
    

    在我的 PC 上运行的时间:每个循环 596 µs ± 14.7 µs(平均值 ± 标准偏差,7 次运行,每次 1000 个循环)。

    时间流逝,我们学到了更多:更短的代码,更简洁:

    from collections import defaultdict
    d = defaultdict(list)
    for entry in data_list:
        for k,v in entry['fields'].items():
                d[k].append(v[0])
    
    pd.DataFrame(d)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-10
      • 2013-06-13
      • 2013-05-02
      • 1970-01-01
      • 2017-05-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多