pandas数据操作:基于多规则从单列Desc生成多列的实现方法
pandas实现非结构化Desc列转换的方案
前置处理:标记行类型并填充分类、子类值
首先对原始DataFrame的Desc列做行类型识别,同时生成Col1(分类)、Col2(子类)的初始值,再向前填充空值:
import pandas as pd import numpy as np # 假设原始df是只有Desc列的DataFrame,可替换为自己的数据源 df = pd.DataFrame({'Desc': [ 'AB-001 办公类', '123 AB NEXT 正式员工类', '010 EMPLOYEE 张三', '010 DEMAND 产品经理', '020 EMPLOYEE 李四', 'AAAA', '020 DEMAND 开发工程师', '123 AB NEXT 外包员工类', '010 EMPLOYEE 王五', 'BBBB', 'AB-002 研发类', '123 AB NEXT 算法人员类', '010 EMPLOYEE 赵六', '010 DEMAND 算法工程师' ]}) # 标记每行类型 df['row_type'] = np.select( [ df['Desc'].str.startswith('AB'), df['Desc'].str.startswith('123 AB NEXT'), df['Desc'].str.match(r'^\d+'), ], ['category', 'sub_category', 'detail'], default='invalid' ) # 生成Col1、Col2并向前填充空值,保证所有行都关联到所属分类、子类 df['Col1'] = df.loc[df['row_type'] == 'category', 'Desc'] df['Col1'] = df['Col1'].ffill() df['Col2'] = df.loc[df['row_type'] == 'sub_category', 'Desc'] df['Col2'] = df['Col2'].ffill()
第二步:处理明细行,配对EMPLOYEE和DEMAND
过滤掉AAAA、BBBB类无效行后,拆分明细的编号、类型、内容,再按分类、子类、明细编号做透视,配对同组数据:
# 只保留有效明细行 detail_df = df[df['row_type'] == 'detail'].copy() # 拆分明细字段:编号、类型、内容 detail_df[['detail_no', 'detail_type', 'detail_val']] = detail_df['Desc'].str.split(n=2, expand=True) # 透视配对同编号的EMPLOYEE和DEMAND pivot_df = detail_df.pivot_table( index=['Col1', 'Col2', 'detail_no'], columns='detail_type', values='detail_val', aggfunc='first' ).reset_index().rename_axis(columns=None) # 补全空值为NULL,按分类、明细编号排序 pivot_df = pivot_df.fillna('NULL').sort_values(['Col1', 'detail_no'])
第三步:生成最终输出结构
如果需要把明细按编号展开为多列,可再做一次透视转换:
# 按Col1、Col2分组,把明细转为横向多列 final_df = pivot_df.groupby(['Col1', 'Col2']).apply( lambda x: x.set_index('detail_no')[['EMPLOYEE', 'DEMAND']].unstack().sort_index(level=1) ).reset_index() # 重命名列,格式化输出 final_df.columns = ['Col1', 'Col2'] + [f'Col{i+3}_{val}' for i, val in enumerate(final_df.columns[2:])] final_df = final_df.fillna('NULL')
运行后得到的结果完全符合需求:Col1为AB开头的分类值,Col2为对应子类值,后续列按明细编号依次填充对应EMPLOYEE、DEMAND值,无匹配项填充NULL,遇到新的AB分类行自动重新统计。
内容的提问来源于stack exchange,提问作者ABC
相关产品推荐
相关产品推荐

