如何按条件展开DataFrame并添加指定值的Val与Category列?
问题:DataFrame按指定列非零值展开并赋值
原始数据
import pandas as pd import numpy as np df = pd.DataFrame({ 'Name': ['x', 'y', 'z'], 'A': [1.1, 0, 0.5], 'B': [0, 0.1, 0.1], 'C': [0.2, 0, 0.3], 'Val': [np.nan, np.nan, np.nan], 'Category': [np.nan, np.nan, np.nan] })
期望结果
# 输出格式: # Name A B C Val Category # 0 x 1.1 0.0 0.2 1.1 first # 1 x 1.1 0.0 0.2 0.2 third # 2 y 0.0 0.1 0.0 0.1 second # 3 z 0.5 0.1 0.3 0.5 first # 4 z 0.5 0.1 0.3 0.1 second # 5 z 0.5 0.1 0.3 0.3 third
错误尝试分析
你的代码存在以下问题:
- 循环索引逻辑错误:
range(1, len(df_repeat)-3,3)起始值为1,会跳过第一组重复行,终止条件也不合理,导致大量行未被处理 - 链式索引赋值无效:
df_repeat.iloc[i][['Target','Category']]属于链式索引,pandas无法确保修改会作用到原DataFrame,大概率出现修改无效的情况 - 函数返回值与赋值逻辑不匹配:
targeta返回整行数据和分类值,但你试图将其赋值给不存在的Target列(应该是Val列),逻辑完全错误 - 未过滤0值:代码没有处理0值的情况,会生成不必要的行
可行解决方案
方法1:使用melt+过滤+合并(推荐,高效简洁)
利用pandas的melt函数将A/B/C列转成键值对,过滤0值后与原表合并:
# 定义列名与Category的映射关系 col_cat_map = {'A': 'first', 'B': 'second', 'C': 'third'} # 将A/B/C列转成键值对格式 melted_df = df.melt( id_vars=['Name'], value_vars=['A', 'B', 'C'], var_name='SourceCol', value_name='Val' ) # 过滤0值并添加Category列 filtered_df = melted_df[melted_df['Val'] != 0].assign( Category=melted_df['SourceCol'].map(col_cat_map) ) # 合并原表的A/B/C列,调整最终列顺序 result = pd.merge(filtered_df, df[['Name', 'A', 'B', 'C']], on='Name') result = result[['Name', 'A', 'B', 'C', 'Val', 'Category']].reset_index(drop=True) print(result)
方法2:使用apply生成多行(逻辑直观)
对每一行生成符合条件的多行数据,再拼接结果:
def expand_single_row(row): output_rows = [] # 遍历目标列和对应的分类 for col, category in zip(['A', 'B', 'C'], ['first', 'second', 'third']): val = row[col] if val != 0: new_row = row.copy() new_row['Val'] = val new_row['Category'] = category output_rows.append(new_row) return pd.DataFrame(output_rows) # 对每行应用函数并拼接结果 result = pd.concat( [expand_single_row(row) for _, row in df.iterrows()], ignore_index=True ) print(result)
两种方法均可得到预期结果,方法1更适合大数据量场景,执行效率更高;方法2逻辑清晰,易于理解和调试。
内容的提问来源于stack exchange,提问作者Bell
相关产品推荐
相关产品推荐

