【问题标题】:Pandas: reading multi-index JSON as pandas data frame熊猫:将多索引 JSON 读取为熊猫数据框
【发布时间】:2021-11-11 17:54:59
【问题描述】:

我有一个 JSON 文件如下:

{
    "ALPHA": [
        {
            "date": "2021-06-22",
            "constituents": {
                "BBB": 0,
                "EEE": 1,
                "BTB": 1,
                "YUY": 1
            }
        },
        {
            "date": "2021-09-07",
            "constituents": {
                "BBB": 0,
                "EEE": 0,
                "BTB": 0,
                "YUY": 0
            }
        }
    ],
    "BETA": [
        {
            "date": "2021-06-22",
            "constituents": {
                "BBB": 1,
                "EEE": 1,
                "BTB": 1,
                "YUY": 1
            }
        },
        {
            "date": "2021-09-07",
            "constituents": {
                "BBB": 1,
                "EEE": 1,
                "BTB": 1,
                "YUY": 1
            }
        }
    ],

    "THETA": [
        {
            "date": "2021-06-22",
            "constituents": {
                "BBB": 0,
                "EEE": 1,
                "BTB": 1,
                "YUY": 0
            }
        },
        {
            "date": "2021-08-20",
            "constituents": {
                "BBB": 0,
                "EEE": 1,
                "BTB": 1,
                "YUY": 0
            }
        },
        {
            "date": "2021-09-07",
            "constituents": {
                "BBB": 0,
                "EEE": 1,
                "BTB": 1,
                "YUY": 0
            }
        }
    ]
}

我想将上面的内容读入一个熊猫数据框,其中第一个索引是日期,第二个索引是第一个键(即“ALPHA”、“BETA”、“THETA”),列是内部键(即“BBB”、“EEE”、“BTB”、“YUY”),单元格值就是这些内键的值。

如何从 JSON 文件将其读入 pandas?

【问题讨论】:

    标签: python json pandas


    【解决方案1】:

    您可以使用pd.Series 将JSON 导入到以ALPHABETA 作为索引和元素作为列表的Pandas 系列。然后通过.explode() 将 JSON 列表扩展为单个 JSON。通过.apply() + pd.Series 将内部 JSON 扩展为数据框。

    date 附加为.set_index()append=True 的索引;通过.swaplevel()date从第二个索引交换到第一个索引。

    最后,取constituents列,将内部JSON进一步扩展为.apply()+pd.Series的dataframe,如下:

    (假设您已经将 JSON 文件加载到 j

    df = (pd.Series(j)
            .explode()
            .apply(pd.Series)
            .set_index('date', append=True)
            .swaplevel()['constituents']
            .apply(pd.Series)
         )
    

    数据输入:

    j = {'ALPHA': [{'date': '2021-06-22',
       'constituents': {'BBB': 0, 'EEE': 1, 'BTB': 1, 'YUY': 1}},
      {'date': '2021-09-07',
       'constituents': {'BBB': 0, 'EEE': 0, 'BTB': 0, 'YUY': 0}}],
     'BETA': [{'date': '2021-06-22',
       'constituents': {'BBB': 1, 'EEE': 1, 'BTB': 1, 'YUY': 1}},
      {'date': '2021-09-07',
       'constituents': {'BBB': 1, 'EEE': 1, 'BTB': 1, 'YUY': 1}}],
     'THETA': [{'date': '2021-06-22',
       'constituents': {'BBB': 0, 'EEE': 1, 'BTB': 1, 'YUY': 0}},
      {'date': '2021-08-20',
       'constituents': {'BBB': 0, 'EEE': 1, 'BTB': 1, 'YUY': 0}},
      {'date': '2021-09-07',
       'constituents': {'BBB': 0, 'EEE': 1, 'BTB': 1, 'YUY': 0}}]}
    

    输出

    print(df)
    
    
                      BBB  EEE  BTB  YUY
    date                                
    2021-06-22 ALPHA    0    1    1    1
    2021-09-07 ALPHA    0    0    0    0
    2021-06-22 BETA     1    1    1    1
    2021-09-07 BETA     1    1    1    1
    2021-06-22 THETA    0    1    1    0
    2021-08-20 THETA    0    1    1    0
    2021-09-07 THETA    0    1    1    0
    

    【讨论】:

    • 这简直太完美了
    • 完美答案,非常有用的提示,谢谢!
    • @Muhammadhassan 谢谢!
    • @AliCrash 谢谢!
    【解决方案2】:

    如果您在将最终形式拉入 Pandas 之前处理 Pandas 之外的 Python 原生数据结构,我觉得您可以获得更好的性能,并且可能更容易操作:

    让我们使用 Python 的工具将嵌套字典展平为单个字典:

    container = []
    for key, value in j.items(): # j is the main dictionary
        for entry in value:
            content = {'date': entry['date'], 
                       'key': key, 
                       # expand the nested constituent data
                       # this gets us a single dictionary 
                       **entry['constituents']}
            container.append(content)
    
    print(container)
    [{'date': '2021-06-22',
      'key': 'ALPHA',
      'BBB': 0,
      'EEE': 1,
      'BTB': 1,
      'YUY': 1},
     {'date': '2021-09-07',
      'key': 'ALPHA',
      'BBB': 0,
      'EEE': 0,
      'BTB': 0,
      'YUY': 0},
     {'date': '2021-06-22', 'key': 'BETA', 'BBB': 1, 'EEE': 1, 'BTB': 1, 'YUY': 1},
     {'date': '2021-09-07', 'key': 'BETA', 'BBB': 1, 'EEE': 1, 'BTB': 1, 'YUY': 1},
     {'date': '2021-06-22',
      'key': 'THETA',
      'BBB': 0,
      'EEE': 1,
      'BTB': 1,
      'YUY': 0},
     {'date': '2021-08-20',
      'key': 'THETA',
      'BBB': 0,
      'EEE': 1,
      'BTB': 1,
      'YUY': 0},
     {'date': '2021-09-07',
      'key': 'THETA',
      'BBB': 0,
      'EEE': 1,
      'BTB': 1,
      'YUY': 0}]
    

    现在,构建数据框,并将所需的列设置为索引:

    pd.DataFrame(container).set_index(['date', 'key'])
    
                      BBB  EEE  BTB  YUY
    date       key
    2021-06-22 ALPHA    0    1    1    1
    2021-09-07 ALPHA    0    0    0    0
    2021-06-22 BETA     1    1    1    1
    2021-09-07 BETA     1    1    1    1
    2021-06-22 THETA    0    1    1    0
    2021-08-20 THETA    0    1    1    0
    2021-09-07 THETA    0    1    1    0
    

    【讨论】:

    • 也许可以添加时间?我认为这非常快,我喜欢这个解决方案。
    • 是的,它更快;虽然数据很小,所以不确定速度测试是否合理。而且我不知道如何生成匹配 OP 形式的嵌套字典
    • 是的,也许数据样本中的输出也很有趣(但必要的状态也是必要的,也需要对 OP 进行实际测试)
    猜你喜欢
    • 1970-01-01
    • 2018-07-14
    • 1970-01-01
    • 2022-07-10
    • 2019-06-30
    • 2017-02-22
    • 2019-05-21
    • 2019-03-18
    • 2018-01-08
    相关资源
    最近更新 更多