如何对Pandas DataFrame按3列及以上分组,生成嵌套字典格式的子码列表?
嘿,我完全get到你的需求了——就是要把DataFrame里的层级关系(Region→Country→AREA_CODE)对应到子码列的嵌套字典对吧?先帮你把之前踩的groupby解包坑填上,再一步步实现你想要的嵌套结构~
先解决你之前的报错问题
你之前写的代码报错too many values to unpack (expected 2),原因很简单:当你用['Region', 'Country', 'AREA_CODE']这3列分组时,每个分组的键是一个包含3个元素的元组(比如('AMER', 'US', 'A1')),但你却用(k1, k2)来解包,自然会因为元素数量不匹配报错。正确的解包应该是(k1, k2, k3),对应3个分组列的键值。
分步实现你要的嵌套结构
首先咱们先把示例DataFrame构造出来,方便后续演示:
import pandas as pd data = { 'Region': ['AMER', 'AMER', 'AMER', 'AMER'], 'Country': ['US', 'CANADA', 'US', 'US'], 'AREA_CODE': ['A1', 'A1', 'B1', 'A1'], 'AREA_SUB_CODE_1': ['A1_US_1', 'A1_CA_1', 'B1_US_1', 'A1_US_1'], 'AREA_SUB_CODE_2': ['A1_US_2', 'A1_CA_2', 'B1_US_2', 'A1_US_2'] } df = pd.DataFrame(data)
1. 生成AREA_SUB_CODE_1的嵌套字典
按照你要的结构,我们需要按Region→Country→AREA_CODE层级分组,提取每个层级下AREA_SUB_CODE_1的唯一值列表:
result = {'AREA_SUB_CODE_1': {}} # 按3列分组,解包时对应3个键值 for (region, country, area_code), sub_codes in df.groupby(['Region', 'Country', 'AREA_CODE'])['AREA_SUB_CODE_1']: # 逐层创建嵌套字典,确保每个层级的键存在 if region not in result['AREA_SUB_CODE_1']: result['AREA_SUB_CODE_1'][region] = {} if country not in result['AREA_SUB_CODE_1'][region]: result['AREA_SUB_CODE_1'][region][country] = {} # 存入去重后的子码列表 result['AREA_SUB_CODE_1'][region][country][area_code] = sub_codes.unique().tolist()
运行后result['AREA_SUB_CODE_1']的结构就完全符合你的要求:
{ "AMER": { "US": { "A1": ["A1_US_1"], "B1": ["B1_US_1"] }, "CANADA": { "A1": ["A1_CA_1"] } } }
2. 生成AREA_SUB_CODE_2的嵌套字典
你对AREA_SUB_CODE_2的要求多了一层:在AREA_CODE下面还要关联AREA_SUB_CODE_1,所以需要按Region→Country→AREA_CODE→AREA_SUB_CODE_1这4列分组:
result['AREA_SUB_CODE_2'] = {} # 按4列分组,解包对应4个键值 for (region, country, area_code, sub1_code), sub2_codes in df.groupby(['Region', 'Country', 'AREA_CODE', 'AREA_SUB_CODE_1'])['AREA_SUB_CODE_2']: # 逐层构建嵌套 if region not in result['AREA_SUB_CODE_2']: result['AREA_SUB_CODE_2'][region] = {} if country not in result['AREA_SUB_CODE_2'][region]: result['AREA_SUB_CODE_2'][region][country] = {} if area_code not in result['AREA_SUB_CODE_2'][region][country]: result['AREA_SUB_CODE_2'][region][country][area_code] = {} # 存入去重后的AREA_SUB_CODE_2列表 result['AREA_SUB_CODE_2'][region][country][area_code][sub1_code] = sub2_codes.unique().tolist()
这部分运行后就会得到你想要的多层嵌套结构,比如US的A1下面会有"A1_US_1": ["A1_US_2"]这样的对应关系。
用通用函数优化代码(可选)
如果以后还要处理更多类似的子码列,写一个通用函数会更高效,不管是3列还是5列分组都能搞定:
def build_nested_dict(df, target_col, group_cols): """ 通用嵌套字典构建函数 :param df: 输入的Pandas DataFrame :param target_col: 要提取列表的目标列名 :param group_cols: 分组列列表,按从外到内的层级顺序排列 :return: 嵌套字典 """ nested_dict = {} for keys, values in df.groupby(group_cols)[target_col]: current_level = nested_dict # 遍历除最后一个外的所有分组键,创建层级 for key in keys[:-1]: if key not in current_level: current_level[key] = {} current_level = current_level[key] # 最后一个分组键对应目标列的唯一值列表 current_level[keys[-1]] = values.unique().tolist() return nested_dict # 调用函数快速生成结果 result = { 'AREA_SUB_CODE_1': build_nested_dict(df, 'AREA_SUB_CODE_1', ['Region', 'Country', 'AREA_CODE']), 'AREA_SUB_CODE_2': build_nested_dict(df, 'AREA_SUB_CODE_2', ['Region', 'Country', 'AREA_CODE', 'AREA_SUB_CODE_1']) }
这样不管以后要加多少层分组,只要调整group_cols的列表就行,非常灵活~
备注:内容来源于stack exchange,提问作者SM079

