用嵌套列表和嵌套字典列表展平一个非常大的 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的主要内容,如果未能解决你的问题,请参考以下文章