Pandas宽表转长表保留指定列并合并p_前缀列的实现问题
原有写法的问题
- 没有预先将原始行索引转为可用于分组的标识列,
i=['index']指定的列在原DataFrame中不存在,无法作为行的唯一分组键 j参数使用错误:该参数用于指定存储p_后缀(a/b/c)的新列名,应传入字符串,而非你填写的['result1', 'result2']列表,这两个字段是你要保留的固定维度,不属于后缀存储列- 未做结果过滤:
wide_to_long转换后会保留所有p_值为0的行,不符合仅保留取值为1的行的需求
正确实现
推荐用melt方法实现,逻辑更直观:
首先预处理数据,保留原始行索引作为old_id:
import pandas as pd import io raw = ''' date speechnumber result1 result2 p_a p_b p_c 0 2009-11-10 2 0 0 1 0 1 1 2009-11-10 2 0 0 0 0 0 2 2009-11-10 2 0 0 0 1 0 3 2009-11-10 2 0 0 0 1 0 4 2009-11-10 2 1 1 0 0 1 5 2009-11-10 2 0 0 0 0 0 6 2009-11-10 2 0 0 1 0 1 7 2009-11-10 2 0 0 1 0 0 8 2009-11-10 2 1 1 1 0 1 9 2009-11-10 4 0 0 1 1 0 ''' # 读取数据并将原始索引转为old_id列 df = pd.read_table(io.StringIO(raw), delim_whitespace=True).rename_axis('old_id').reset_index()
然后进行宽表转长表操作:
# 宽转长 res = df.melt( id_vars=['old_id', 'date', 'speechnumber', 'result1', 'result2'], value_vars=[col for col in df.columns if col.startswith('p_')], var_name='p', value_name='flag' ) # 过滤取值为1的行,去掉p列的前缀 res = res.query('flag == 1').assign(p = lambda x: x['p'].str.slice(2)) # 清理冗余列,按old_id排序 res = res.drop(columns='flag').sort_values('old_id').reset_index(drop=True)
输出结果与你给出的预期完全一致。如果一定要用wide_to_long实现,写法如下:
res = pd.wide_to_long( df, stubnames='p', i=['old_id', 'date', 'speechnumber', 'result1', 'result2'], j='p', sep='_' ).query('p == 1').reset_index().drop(columns='p') res = res.sort_values('old_id').reset_index(drop=True)
内容的提问来源于stack exchange,提问作者Ivo
相关产品推荐
相关产品推荐

