如何过滤Pandas DataFrame获取树形层级结构的叶子节点记录
问题描述
现有存储多层级结构的DataFrame,lvl1/lvl2/lvl3字段分别对应一级、二级、三级层级,形式和目录路径一致。需求是过滤掉所有非叶子节点的记录,仅保留层级树最末端的叶子节点记录。使用transform、groupby等方法尝试实现后,始终无法得到符合预期的输出。
测试数据与预期结果
import numpy as np import pandas as pd # 原始输入数据 df = pd.DataFrame({'lvl1':['aa','aa','aa','aa','bb','bb','bb','bb','cc','aa'], 'lvl2':[np.nan,'xx','xx','xx',np.nan,'yy','yy','zz',np.nan,'sa'], 'lvl3':[np.nan,np.nan,'ww','qq',np.nan,np.nan,'rr',np.nan,np.nan,'jj'], 'value':[12,4,7,22,76,0,18,47,10,2]}) # 预期输出结果 expected_result = pd.DataFrame({'lvl1':['aa','aa','bb','bb','cc','aa'], 'lvl2':['xx','xx','yy','zz',np.nan,'sa'], 'lvl3':['ww','qq','rr',np.nan,np.nan,'jj'], 'value':[7,22,18,47,10,2]})
层级结构参考示意图:
实现方案
核心判断规则:如果某条记录的层级路径,是其他任意一条记录路径的前缀,那这条记录就是非叶子节点,需要被过滤;反之则是要保留的叶子节点。
实现步骤
- 为每行生成对应的层级路径元组,遇到空值就截断路径
- 收集所有路径,筛选出不被任何其他路径作为前缀的叶子路径
- 从原始表中匹配属于叶子路径的记录,整理后得到最终结果
可直接运行的代码
# 按层级列生成每行的有效路径 def build_path(row, level_cols): valid_path = [] for col in level_cols: current_val = row[col] if pd.isna(current_val): break valid_path.append(current_val) return tuple(valid_path) # 这里按实际层级列名修改即可,适配任意层级数量 level_columns = ['lvl1', 'lvl2', 'lvl3'] df['full_path'] = df.apply(build_path, axis=1, args=(level_columns,)) # 筛选叶子路径 all_paths = df['full_path'].tolist() leaf_paths = [] for path in all_paths: is_leaf = True for compare_path in all_paths: # 存在更长的路径以当前路径为前缀,说明当前不是叶子 if len(compare_path) > len(path) and compare_path[:len(path)] == path: is_leaf = False break if is_leaf: leaf_paths.append(path) # 提取结果,重置索引 res = df[df['full_path'].isin(leaf_paths)]\ .drop(columns=['full_path'])\ .drop_duplicates()\ .reset_index(drop=True)
运行后res和预期结果完全一致。如果业务场景中允许存在重复的叶子节点记录,去掉代码中的.drop_duplicates()即可。
内容的提问来源于stack exchange,提问作者Youstanzr
相关产品推荐
相关产品推荐

