
本文详解如何在pandas中根据多个条件(如市场类型为eex/ice且目标列为空)自动填充“月末最后一天”到指定列,并提供可直接运行的函数式与向量化方案。
在实际数据分析项目中,常需基于复合逻辑动态填充DataFrame中的缺失值。本例需求明确:对ValuedteTo列进行条件填充——仅当该列当前为空(NaN)且Market列为'EEX'或'ICE'时,将其设为Value Dte所在月份的最后一天;其余情况(如已有值或市场为'OTC')则保留原值。
首先需确保日期列已正确解析为datetime64类型,否则后续日期运算将失败:
import pandas as pd from datetime import timedelta # 假设 df 已加载 df['Value Dte'] = pd.to_datetime(df['Value Dte']) df['ValuedteTo'] = pd.to_datetime(df['ValuedteTo'], errors='coerce') # 空字符串转为 NaT
关键在于准确计算月末日期。原代码中last_day_of_month函数存在两个问题:
- 输入参数误用(应传入row['Value Dte']而非df['valueDate_From_']);
- 返回值未统一为date类型,导致与ValuedteTo列(datetime64)类型不兼容。
修正后的稳健实现如下:
def last_day_of_month(any_day):
"""输入任意日期,返回其所在月份最后一天(date对象)"""
if pd.isna(any_day):
return pd.NaT
next_month = any_day.replace(day=28) + timedelta(days=4)
return (next_month - timedelta(days=next_month.day)).date()
def fill_valuedteto(row):
"""按规则填充 ValuedteTo 列"""
if pd.isna(row['ValuedteTo']) and row['Market'] in ['EEX', 'ICE']:
return last_day_of_month(row['Value Dte'])
else:
return row['ValuedteTo']
df['ValuedteTo'] = df.apply(fill_valuedteto, axis=1)✅ 注意事项: pd.isna() 同时兼容 None、np.nan 和 pd.NaT,比 x is None 或 pd.isnull() 更鲁棒; 使用 row['Market'] in ['EEX', 'ICE'] 比多次 == 判断更简洁可扩展; 若需保持ValuedteTo列始终为datetime64类型(便于后续时间运算),可将last_day_of_month返回值改为pd.Timestamp(...),或在赋值后统一转换:df['ValuedteTo'] = pd.to_datetime(df['ValuedteTo'])。
进阶建议:避免apply以提升性能
对于大数据集,推荐使用向量化操作替代apply:
mask = df['ValuedteTo'].isna() & df['Market'].isin(['EEX', 'ICE'])
df.loc[mask, 'ValuedteTo'] = (
df.loc[mask, 'Value Dte'] + pd.offsets.MonthEnd(0)
).dt.date # .dt.date 转为 date 类型;若需 datetime,省略 .date此方案利用pd.offsets.MonthEnd(0)直接获取月末,无需自定义函数,执行效率显著更高,且代码更简洁专业。
最终结果中,EEX/ICE行的空ValuedteTo将被精确填充为对应Value Dte的月末日期(如2024-03-01 → 2024-03-31),而OTC行及已有值保持不变——完全满足业务逻辑要求。










