如何在Pandas时间序列中迭代执行自定义季节性函数并新增列?
解决Pandas中自定义季节性函数应用于Datetime序列的问题
先帮你拆解下两个报错的原因,再给出更简便的实现方案:
报错原因分析
iterrows()的TypeError:
你用pd.date_range生成的Date列是Pandas的Timestamp类型,不是Python原生的datetime.date。当你在函数里用dt.date(year,1,1)(原生date对象)和Timestamp做减法时,类型不匹配就会抛出这个错误——原生datetime的__sub__方法只接受同类型的对象。apply()的AttributeError:
看起来你应该是直接调用了df.apply(date_season),而不是针对Date列调用df['Date'].apply(date_season)。前者会把整个行的Series传入函数,而Series没有year属性,自然会报错。如果是针对列调用apply,其实只要函数兼容Timestamp类型就可以正常运行。
修正方案:兼容Timestamp的函数+正确apply用法
先修改你的函数,让它能同时处理datetime.date和pd.Timestamp类型:
import datetime as dt import pandas as pd import numpy as np def date_season(date): # 把Timestamp转成原生date对象(如果是Timestamp的话) if isinstance(date, pd.Timestamp): date = date.date() year = date.year min_season = dt.date(year,1,1) max_season = dt.date(year,6,30) dif = abs(max_season - date) dif_days = dif.days total_half_year_days = (max_season - min_season).days x = (total_half_year_days - dif_days * 2) / total_half_year_days seasonality = np.sin(x * np.pi / 2) return seasonality # 生成数据 start = dt.date(2017,1,1) end = dt.date(2019,12,31) df = pd.DataFrame({'Date': pd.date_range(start, end, freq="D")}) # 正确应用函数到Date列 df['Seasonality'] = df['Date'].apply(date_season)
更高效的向量化方案(推荐)
上面的apply是逐元素处理,对于大数据集效率不高。我们可以用Pandas的dt属性做完全向量化的计算,速度会快很多:
# 提取日期的年、日序数、是否闰年 df['dayofyear'] = df['Date'].dt.dayofyear df['is_leap'] = df['Date'].dt.is_leap_year # 计算每年6月30日的日序数(平年181,闰年182) df['june30_day'] = np.where(df['is_leap'], 182, 181) # 计算距离6月30日的天数 df['dif_days'] = abs(df['june30_day'] - df['dayofyear']) # 上半年总天数 df['half_year_days'] = df['june30_day'] # 计算x和季节性值 df['x'] = (df['half_year_days'] - df['dif_days'] * 2) / df['half_year_days'] df['Seasonality_vectorized'] = np.sin(df['x'] * np.pi / 2)
这个方案不需要循环或apply,完全利用Pandas和NumPy的向量化运算,性能提升明显,尤其是当你的数据集很大时。
内容的提问来源于stack exchange,提问作者Gambit1337
相关产品推荐
相关产品推荐

