如何用Pandas内置方法替代循环转换多层嵌套字典(含列表)为DataFrame?
三层嵌套字典转指定DataFrame的Pandas优化方案
针对你这种三层嵌套字典+列表的结构,确实有比手动嵌套循环更高效的Pandas内置方法或优化写法,下面两种方案都能替代原循环,且效率更高:
方案一:Pandas链式内置方法组合
利用pd.json_normalize、melt和explode三个方法配合,完全通过Pandas内置操作实现转换:
import pandas as pd data = { "etherA": { "vlanY": { "local": ['mac01', 'mac02'], "external": ['mac03', 'mac02'] } }, "etherB": { "vlanZ": { "local": ['mac06', 'mac09'], "external": ['mac01', 'mac02', 'mac03'] } } } # 先将顶层结构转换为json_normalize可处理的列表格式 flat_data = [ {"interface": iface, "vlan": vlan, **dyn_macs} for iface, vlans in data.items() for vlan, dyn_macs in vlans.items() ] # 链式操作完成转换 df = (pd.json_normalize(flat_data) .melt(id_vars=['interface', 'vlan'], var_name='dyn', value_name='mac-address') .explode('mac-address') .reset_index(drop=True)) print(df)
输出结果和你预期完全一致:
interface vlan dyn mac-address 0 etherA vlanY local mac01 1 etherA vlanY local mac02 2 etherA vlanY external mac03 3 etherA vlanY external mac02 4 etherB vlanZ local mac06 5 etherB vlanZ local mac09 6 etherB vlanZ external mac01 7 etherB vlanZ external mac02 8 etherB vlanZ external mac03
步骤说明:
- flat_data整理:把顶层的interface和vlan提取为键,将dyn类型的字典展开到同一层级,为
json_normalize做准备; - json_normalize:将嵌套字典转换为宽表结构,此时local和external是列,值为mac列表;
- melt:将宽表转为长表,把local/external列合并为
dyn列,对应的mac列表转为mac-address列; - explode:将
mac-address列的列表元素拆分为单独行,最后重置索引。
方案二:列表推导式+DataFrame批量生成
如果追求最高效率,先通过Python列表推导式扁平化所有数据,再一次性生成DataFrame,这种写法比嵌套循环逐个添加行快得多(避免了Pandas逐行修改的性能损耗):
import pandas as pd data = { "etherA": { "vlanY": { "local": ['mac01', 'mac02'], "external": ['mac03', 'mac02'] } }, "etherB": { "vlanZ": { "local": ['mac06', 'mac09'], "external": ['mac01', 'mac02', 'mac03'] } } } # 用列表推导式直接生成所有行的记录 flat_records = [ (iface, vlan, dyn_type, mac) for iface, vlans in data.items() for vlan, dyn_dict in vlans.items() for dyn_type, mac_list in dyn_dict.items() for mac in mac_list ] # 批量生成DataFrame df = pd.DataFrame(flat_records, columns=['interface', 'vlan', 'dyn', 'mac-address'])
这个方案的结果和方案一完全相同,但数据量越大,性能优势越明显——因为列表推导式是Python原生高效操作,且一次性创建DataFrame避免了多次修改的开销。
对比原循环的优势
你原来的df.loc[len(df)]逐行赋值的方式,每次都会触发DataFrame的内部结构调整,数据量较大时会非常缓慢。上面两种方案都是先将数据整理为扁平结构,再一次性生成DataFrame,效率至少提升一个数量级,且代码更简洁易维护。
内容的提问来源于stack exchange,提问作者FrozenCryptid
相关产品推荐
相关产品推荐

