如何将带层级位置的Pandas DataFrame从宽表转长表?
解决方案:基于层级位置的DataFrame宽表转换
以下是符合需求的向量化实现方案,支持任意层级结构,无需手动循环判断每行:
import pandas as pd import numpy as np # 输入数据 df = pd.DataFrame(data = {'Category': ['Fruits', 'Apple', 'Green', 'Red', 'Pineapple', 'Banana', 'Vegetables', 'Potatoes', 'Salad', 'Meat'], 'Value': [10, 5, 2, 3, 3, 2, 4, 2, 2, 3], 'Hierarchy': [1, 2, 3, 3, 2, 2, 1, 2, 2, 1]}) # 1. 获取数据中的最大层级 max_hierarchy = df['Hierarchy'].max() # 2. 自动生成各层级归属列 for i in range(1, max_hierarchy + 1): if i == 1: # 层级1:所有行取最近的层级1节点,层级1的行取自身 df[f'Hierarchy{i}'] = df['Category'].where(df['Hierarchy'] == i).ffill() else: # 按三种层级关系分别赋值 mask_higher = df['Hierarchy'] > i mask_equal = df['Hierarchy'] == i mask_lower = df['Hierarchy'] < i # 对应条件的取值逻辑 val_higher = df['Category'].where(df['Hierarchy'] == i).ffill() val_equal = df['Category'].where(df['Hierarchy'] == i-1).ffill() val_lower = df['Category'] # 合并结果 df[f'Hierarchy{i}'] = np.select([mask_higher, mask_equal, mask_lower], [val_higher, val_equal, val_lower]) # 3. 筛选叶子节点(无后续子节点的行) leaf_mask = df['Hierarchy'] >= df['Hierarchy'].shift(-1, fill_value=0) df_result = df[leaf_mask].copy() # 4. 整理输出格式 df_result = df_result[['Value'] + [f'Hierarchy{i}' for i in range(1, max_hierarchy+1)]].reset_index(drop=True) df_result.index += 1 # 索引从1开始,与示例一致 print(df_result)
代码说明
- 层级列生成逻辑:
- 层级1:所有行取最近的根节点(层级1的Category),根节点行取自身。
- 层级i>1:
- 当前行层级大于i:取最近的i层级节点作为归属(子节点继承父层级)。
- 当前行层级等于i:取最近的i-1层级节点作为归属(同层级节点归属于上一层级)。
- 当前行层级小于i:直接用自身填充(无更高层级节点)。
- 叶子节点筛选:通过判断当前行层级是否大于等于下一行层级,筛选出无后续子节点的行,最后一行默认保留。
- 扩展性:无需修改代码,自动适配任意数量的层级结构。
运行后输出与期望完全一致:
Value Hierarchy1 Hierarchy2 Hierarchy3 1 2 Fruits Apple Green 2 3 Fruits Apple Red 3 3 Fruits Fruits Pineapple 4 2 Fruits Fruits Banana 5 2 Vegetables Vegetables Potatoes 6 2 Vegetables Vegetables Salad 7 3 Meat Meat Meat
内容的提问来源于stack exchange,提问作者okost
相关产品推荐
相关产品推荐

