Pandas中使用.apply后列消失问题求助(附代码与预期结果)
Pandas合并后使用apply丢失原有列的问题分析与解决
原始数据
DataFrame 1: nopat
nopat 0 2021-12-31 3.580000e+09 1 2020-12-31 6.250000e+08 2 2019-12-31 -1.367000e+09 3 2018-12-31 2.028000e+09
DataFrame 2: capital_employed
capital_employed 0 2021-12-31 5.924000e+10 1 2020-12-31 6.062400e+10 2 2019-12-31 5.203500e+10 3 2018-12-31 5.441200e+10
你的代码
roce_by_year = pd.merge(nopat, capital_employed) \ .rename(columns={"" : "date"}) \ .sort_values(by='date') \ .apply(lambda row: compute_roce(row['nopat'], row['capital_employed']), axis=1) \ .reset_index(name='roce')
当前结果
index roce 0 3 3.727119 1 2 -2.627078 2 1 1.030945 3 0 6.043214
期望结果
date roce 0 2018 3.727119 1 2019 -2.627078 2 2020 1.030945 3 2021 6.043214
问题原因
- apply的返回值特性:当
apply(axis=1)的lambda返回单个数值时,Pandas会返回一个Series而非保留原DataFrame结构,所有原有列会被直接丢弃,只剩下计算结果序列。 - 日期列处理错误:你试图用
rename(columns={"" : "date"})将空列名改为date,但实际上原始数据中的日期是索引而非列,这一步并没有把索引转为正经的date列,后续排序后仍保留原数字索引,导致reset_index只能拿到数字索引而非日期。
解决方法
步骤1:先将索引转为日期列
合并前把两个DataFrame的索引转为名为date的列:
nopat = nopat.reset_index().rename(columns={'index': 'date'}) capital_employed = capital_employed.reset_index().rename(columns={'index': 'date'})
步骤2:新增ROCE列而非替换整个DataFrame
不要用apply直接覆盖原DataFrame,而是新增列存储计算结果:
# 合并并排序 roce_by_year = pd.merge(nopat, capital_employed, on='date') \ .sort_values(by='date') # 新增roce计算列 roce_by_year['roce'] = roce_by_year.apply(lambda row: compute_roce(row['nopat'], row['capital_employed']), axis=1) # 格式化日期并保留需要的列 roce_by_year['date'] = roce_by_year['date'].dt.year roce_by_year = roce_by_year[['date', 'roce']].reset_index(drop=True)
更高效的替代方案(跳过apply)
apply是逐行操作效率较低,建议直接用列运算(需确保compute_roce支持接收Series参数):
# 先处理索引转列 nopat = nopat.reset_index().rename(columns={'index': 'date'}) capital_employed = capital_employed.reset_index().rename(columns={'index': 'date'}) # 合并、排序、计算 roce_by_year = pd.merge(nopat, capital_employed, on='date').sort_values('date') roce_by_year['roce'] = (roce_by_year['nopat'] / roce_by_year['capital_employed']) * 100 # 假设ROCE公式为(nopat/资本占用)*100 roce_by_year['date'] = roce_by_year['date'].dt.year roce_by_year = roce_by_year[['date', 'roce']].reset_index(drop=True)
内容的提问来源于stack exchange,提问作者Mattasse
相关产品推荐
相关产品推荐

