Pandas:如何规范化具有多个 JSON 嵌套列表的 JSON 文件?

Posted

技术标签:

【中文标题】Pandas:如何规范化具有多个 JSON 嵌套列表的 JSON 文件?【英文标题】:Pandas: How do I normalize a JSON file with multiple nested lists of JSON? 【发布时间】:2021-11-22 14:40:15 【问题描述】:

我从 API 请求数据,然后尝试规范化这个 JSON 文件,它有这个结构

['la_id': '33',
  'store': '1405fdsa6001209',
  'sell': '110aa346',
  'products': ['codigo': '176690', 'lacre': '15980fd2293', 'valor': '49.90',
   'codigo': 'sd4907', 'lacre': '1598a12385', 'valor': '19.90',
   'codigo': 'aa4907', 'lacre': '1598a2384', 'valor': '19.90',
   'codigo': '1fd307', 'lacre': '1598a20401', 'valor': '169.90'],
  'payment': 'paymentid': '10a836',
   'value': '259.6000',
   'number': '4',
   'finalid': '4',
   'finalname': 'Cartao de credito',
   'docs': '849763',
   'flag': None
   'pagamentos': ['pagamento_id': '107795',
   'valor': '854.9900',
   'numero_parcelas': '10',
   'finalizador_id': '4',
   'finalizador_nome': 'Cartao de credito',
   'documento': '500003',
   'bandeira': 'MASTERCARD']

当我应用 JsonNormalize 以将其转换为数据框时,我得到了这个:

id store sell products pagamentos
33 1405fdsa6001209 110aa346 ['codigo': '176690', 'lacre': '15980fd2293', 'valor': '49.90', 'codigo': 'sd4907', 'lacre': '1598a12385', 'valor': '19.90', 'codigo': 'aa4907', 'lacre': '1598a2384', 'valor': '19.90', 'codigo': '1fd307', 'lacre': '1598a20401', 'valor': '169.90'] ['pagamento_id': '10aa95','valor': '84.9900','numero_parcelas': '10','finalizador_id': '4','finalizador_nome': 'Cartao de credito','docs': '500003','bandeira': 'MASTERCARD']

如您所见,最后两列没有正确获取值,它们在列表中有字典。我该如何解决这个问题?

【问题讨论】:

1) 发布一个有效的 JSON 结构。 2)规范化JSONmanualy并分享结果 @Leonardo 请添加“|”表格第二行中用于格式化表格的符号 更新了我的解决方案以获得额外的pagamentos。请看一看。 【参考方案1】:

试试:

lst = [
    
        "la_id": "33",
        "store": "1405fdsa6001209",
        "sell": "110aa346",
        "products": [
            "codigo": "176690", "lacre": "15980fd2293", "valor": "49.90",
            "codigo": "sd4907", "lacre": "1598a12385", "valor": "19.90",
            "codigo": "aa4907", "lacre": "1598a2384", "valor": "19.90",
            "codigo": "1fd307", "lacre": "1598a20401", "valor": "169.90",
        ],
        "payment": 
            "paymentid": "10a836",
            "value": "259.6000",
            "number": "4",
            "finalid": "4",
            "finalname": "Cartao de credito",
            "docs": "849763",
            "flag": None,
        ,
    
]

df = pd.json_normalize(lst).explode("products")
df = pd.concat([df, df.pop("products").apply(pd.Series)], axis=1)
print(df)

打印:

  la_id            store      sell payment.paymentid payment.value payment.number payment.finalid  payment.finalname payment.docs payment.flag  codigo        lacre   valor
0    33  1405fdsa6001209  110aa346            10a836      259.6000              4               4  Cartao de credito       849763         None  176690  15980fd2293   49.90
0    33  1405fdsa6001209  110aa346            10a836      259.6000              4               4  Cartao de credito       849763         None  sd4907   1598a12385   19.90
0    33  1405fdsa6001209  110aa346            10a836      259.6000              4               4  Cartao de credito       849763         None  aa4907    1598a2384   19.90
0    33  1405fdsa6001209  110aa346            10a836      259.6000              4               4  Cartao de credito       849763         None  1fd307   1598a20401  169.90

编辑:更新输入:

df = pd.concat([df, df.pop("payments").apply(pd.Series)], axis=1)
df = df.explode("product")
df = pd.concat([df, df.pop("product").apply(pd.Series)], axis=1)
print(df)

打印:

   id            store      sell payment_id    valor number finalid   finalizador_nome    docs        flag  codigo        lacre   valor
0  33  1405fdsa6001209  110aa346     10aa95  84.9900     10       4  Cartao de credito  500003  MASTERCARD  176690  15980fd2293   49.90
0  33  1405fdsa6001209  110aa346     10aa95  84.9900     10       4  Cartao de credito  500003  MASTERCARD  sd4907   1598a12385   19.90
0  33  1405fdsa6001209  110aa346     10aa95  84.9900     10       4  Cartao de credito  500003  MASTERCARD  aa4907    1598a2384   19.90
0  33  1405fdsa6001209  110aa346     10aa95  84.9900     10       4  Cartao de credito  500003  MASTERCARD  1fd307   1598a20401  169.90

【讨论】:

哦!凉爽的!在我的情况下,我还有另一个具有相同问题的列(我没有在示例中放入的付款列)如何“爆炸”两个列的值?我在这里尝试将两者都放入公式中,但没有奏效 @LeonardoAmador 您能否编辑您的问题并更新示例输入? 是的,当然,我刚刚这样做了 好像新添加的标签是pagamentos :-) 非常感谢!【参考方案2】:

您可以为每个使用pd.json_normalize()

    提取主要字段(包括键la_id

    提取products详细信息+密钥la_id

    提取pagamentos详细信息+密钥la_id

然后,使用.merge(),使用公共键la_id合并3个结果数据帧,如下:

j_lst = ['la_id': '33',
          'store': '1405fdsa6001209',
          'sell': '110aa346',
          'products': ['codigo': '176690', 'lacre': '15980fd2293', 'valor': '49.90',
                       'codigo': 'sd4907', 'lacre': '1598a12385', 'valor': '19.90',
                       'codigo': 'aa4907', 'lacre': '1598a2384', 'valor': '19.90',
                       'codigo': '1fd307', 'lacre': '1598a20401', 'valor': '169.90'],
          'payment': 'paymentid': '10a836',
                      'value': '259.6000',
                      'number': '4',
                      'finalid': '4',
                      'finalname': 'Cartao de credito',
                      'docs': '849763',
                      'flag': None,
          'pagamentos': ['pagamento_id': '107795',
                          'valor': '854.9900',
                          'numero_parcelas': '10',
                          'finalizador_id': '4',
                          'finalizador_nome': 'Cartao de credito',
                          'documento': '500003',
                          'bandeira': 'MASTERCARD']]


df_main = pd.json_normalize(j_lst)

df_products = pd.json_normalize(j_lst, record_path=['products'], record_prefix='products.', meta=['la_id'])

df_pagamentos = pd.json_normalize(j_lst, record_path=['pagamentos'], record_prefix='pagamentos.', meta=['la_id'])

df_out = (df_main.merge(df_products, on='la_id')
                 .merge(df_pagamentos, on='la_id')
                 .drop(['products', 'pagamentos'], axis=1)
         )

结果:

print(df_out)

  la_id            store      sell payment.paymentid payment.value payment.number payment.finalid  payment.finalname payment.docs payment.flag products.codigo products.lacre products.valor pagamentos.pagamento_id pagamentos.valor pagamentos.numero_parcelas pagamentos.finalizador_id pagamentos.finalizador_nome pagamentos.documento pagamentos.bandeira
0    33  1405fdsa6001209  110aa346            10a836      259.6000              4               4  Cartao de credito       849763         None          176690    15980fd2293          49.90                  107795         854.9900                         10                         4           Cartao de credito               500003          MASTERCARD
1    33  1405fdsa6001209  110aa346            10a836      259.6000              4               4  Cartao de credito       849763         None          sd4907     1598a12385          19.90                  107795         854.9900                         10                         4           Cartao de credito               500003          MASTERCARD
2    33  1405fdsa6001209  110aa346            10a836      259.6000              4               4  Cartao de credito       849763         None          aa4907      1598a2384          19.90                  107795         854.9900                         10                         4           Cartao de credito               500003          MASTERCARD
3    33  1405fdsa6001209  110aa346            10a836      259.6000              4               4  Cartao de credito       849763         None          1fd307     1598a20401         169.90                  107795         854.9900                         10                         4           Cartao de credito               500003          MASTERCARD

【讨论】:

以上是关于Pandas:如何规范化具有多个 JSON 嵌套列表的 JSON 文件?的主要内容,如果未能解决你的问题,请参考以下文章

在 Pandas 数据框中使用 JSON 数据规范化列

如何通过 Python Pandas 正确规范化 json

如何将嵌套的 JSON 键规范化为 pandas 数据帧

使用 JSON 对象展开 Pandas DataFrame 列

pandas DataFrame:规范化一个 JSON 列并与其他列合并

如何使用 json_normalize 规范化嵌套的 json