用嵌套列表和嵌套字典列表展平一个非常大的 Json

Posted

技术标签:

【中文标题】用嵌套列表和嵌套字典列表展平一个非常大的 Json【英文标题】:Flattening a very large Json with nested lists and nested dict list 【发布时间】:2021-11-05 08:39:25 【问题描述】:

我需要扁平化/规范化非常大的分层 JSON 记录。 我已经用json_normalize 尝试了这些示例,但我不知道我必须在record_path 参数中传递的列的确切名称,而不是meta 的其他列。

这是 JSON 记录可能有多复杂的示例:

d2 = 'key2':None, 
'a':1 , 'b':'v':[1,2,3], 
'c': 'c1':'c1', 'c2':'c2', 
'd': 'd1': 1, 'd2':'d3': 'd3', 'd4': 'd4', 'd5':[3,3,3,4], 
'key':
'seqOf': ['seqOf': 
'dedicatedAccountID': '191', 'campaignIdentifier': None, 'transactionAmount': b'106.670000',
 'adjustmentAmount': None, 'accountBalance': b'122.000000', 'accountExpiryDateBefore': None, 
'accountExpiryDateAfter': None, 'accountStartDateBefore': None, 'accountStartDateAfter': None,
 'mainDedicatedAccountID': None, 'offerIdentifier': None, 'dedicatedAccountUnit': '1', 
'transactionUnits': None, 'adjustmentUnits': None, 'unitBalance': None, 'realMoneyFlag': None
]

我也尝试为every key and then join the columns 做,但正如我所说,文件真的很复杂。 性能不是问题,我是离线运行的,我只需要将其中一些 JSON 记录展平为 CSV。

有没有自动工具可以做到这一点?

【问题讨论】:

你的预期输出是什么? @galaxyan 没有任何嵌套列表或字典的平面 CSV 文件。这是数据团队的要求。我相信他们可以使用 Azure 数据工厂,但还没有决定。 例如,'b':'v':[1,2,3] 应该如何展平? @galaxyan 纯列表可能会爆炸。但是如果一个列表有嵌套的字典,我们也需要将它展平, 【参考方案1】:

当有一个列表作为键的值时,json_normalize 方法将不会再进一步​​,因为它可能会破坏数据。列表可以是多行,也可以是数据框的扩展。这是您的示例的扩展解决方案:

df = pd.json_normalize(d2)

df_extension = pd.json_normalize(df['key.seqOf'].str[0].to_list())
df = pd.concat([df,df_extension], axis=1).drop('key.seqOf', axis=1)

输出:

key2 a b.v c.c1 c.c2 d.d1 d.d2.d3 d.d2.d4 d.d2.d5 seqOf.dedicatedAccountID seqOf.campaignIdentifier seqOf.transactionAmount seqOf.adjustmentAmount seqOf.accountBalance seqOf.accountExpiryDateBefore seqOf.accountExpiryDateAfter seqOf.accountStartDateBefore seqOf.accountStartDateAfter seqOf.mainDedicatedAccountID seqOf.offerIdentifier seqOf.dedicatedAccountUnit seqOf.transactionUnits seqOf.adjustmentUnits seqOf.unitBalance seqOf.realMoneyFlag
0 1 [1, 2, 3] c1 c2 1 d3 d4 [3, 3, 3, 4] 191 106.67 122 1

或者如果列表通过分解d.d2.d5 列被计为行:

df = df.explode('d.d2.d5')

结果:

key2 a b.v c.c1 c.c2 d.d1 d.d2.d3 d.d2.d4 d.d2.d5 seqOf.dedicatedAccountID seqOf.campaignIdentifier seqOf.transactionAmount seqOf.adjustmentAmount seqOf.accountBalance seqOf.accountExpiryDateBefore seqOf.accountExpiryDateAfter seqOf.accountStartDateBefore seqOf.accountStartDateAfter seqOf.mainDedicatedAccountID seqOf.offerIdentifier seqOf.dedicatedAccountUnit seqOf.transactionUnits seqOf.adjustmentUnits seqOf.unitBalance seqOf.realMoneyFlag
0 1 [1, 2, 3] c1 c2 1 d3 d4 3 191 106.67 122 1
0 1 [1, 2, 3] c1 c2 1 d3 d4 3 191 106.67 122 1
0 1 [1, 2, 3] c1 c2 1 d3 d4 3 191 106.67 122 1
0 1 [1, 2, 3] c1 c2 1 d3 d4 4 191 106.67 122 1

主要的一点是你想要你的数据如何?在像您这样的情况下,数据可能不是像通用 SQL 这样的关系数据库的形式,但它可能是像 MongoDB 实例这样的文档形式。您需要根据数据的进一步使用情况来决定如何清理数据。

【讨论】:

【参考方案2】:

一种方法是使用json.dumps 将字典序列化为字符串,然后将其反序列化回带有json.loads 的字典,并使用对象挂钩(参见下面的示例my_obj_hook)附加父级的非容器值和所有儿童词典FLAT_MAP

from json import dumps, loads


FLAT_MAP = dict()


def my_obj_hook(obj):
    """append k-v pairs to flat map"""
    for k,v in obj.items():
        if not isinstance(v, (dict, list)):
            FLAT_MAP[k] = v
    return obj


d2 = dumps(d2)
d2 = loads(d2, object_hook=my_obj_hook)

这是object_hook 参数的文档:

object_hook 是一个可选函数,将使用解码的任何对象字面量(一个字典)的结果调用。将使用 object_hook 的返回值而不是 dict。此功能可用于实现自定义解码器(例如 JSON-RPC 类提示)。

【讨论】:

以上是关于用嵌套列表和嵌套字典列表展平一个非常大的 Json的主要内容,如果未能解决你的问题,请参考以下文章

将嵌套命名元组的列表展平为字典列表

以独特的方式展平包含嵌套字典的列表的数据框列

Python:展平多个嵌套的字典并追加

如何展平多级/嵌套 JSON?

以更快的方式展平和扩展 json

Pandas DataFrame 中的嵌套字典列表