如何对时间戳列表应用函数生成Pandas Series?解决属性错误
解决DataFrame.apply批量应用自定义时间函数时的AttributeError问题
错误原因分析
你遇到的AttributeError: 'Series' object has no attribute 'year'核心问题很明确:
当你执行GC_1M.reset_index().apply(as_timedelta,axis=1)时,apply(axis=1)会把整行数据打包成一个Series对象传入as_timedelta函数,但你的函数原本是设计用来接收单个pd.Timestamp对象的。所以当函数尝试访问ref_ts.year时,自然会报错——Series没有year这个属性。
两种解决方案
方案1:直接对时间戳列应用函数(推荐)
既然我们只需要时间戳列的数据,没必要让apply处理整行。重置索引后,直接提取Timestamp列单独应用函数即可:
# 重置索引后,仅对Timestamp列调用apply timedelta_values = GC_1M.reset_index()['Timestamp'].apply(as_timedelta).values
这种方式和你单独测试函数的场景完全一致,每个传入as_timedelta的都是单个pd.Timestamp对象,能完美兼容原函数逻辑,而且执行效率更高。
方案2:修改函数兼容Series输入
如果你需要保留整行apply的场景(比如后续函数需要用到整行其他数据),可以修改函数,先从传入的Series中提取时间戳:
import pandas as pd def as_timedelta(input_data): """ Return the duration of a time period. For a month, obtaining its duration requires a reference timestamp to identify how many days have to be accounted for in the month. """ # 处理输入为Series的情况(整行apply时) if isinstance(input_data, pd.Series): ref_ts = input_data['Timestamp'] else: ref_ts = input_data # 兼容单个Timestamp的输入 # 原函数逻辑保持不变 current_month = pd.Timestamp(year=ref_ts.year, month=ref_ts.month, day=1) next_month = current_month + pd.DateOffset(months=1) nex_next_month = current_month + pd.DateOffset(months=2) dist_to_next = next_month - ref_ts dist_to_prev = ref_ts - current_month td_13 = pd.Timedelta(13, 'h') if dist_to_next < td_13: return nex_next_month - next_month elif dist_to_prev < td_13: return next_month - current_month
之后再执行整行apply就不会报错了:
timedelta_values = GC_1M.reset_index().apply(as_timedelta, axis=1).values
验证结果
用你的示例数据测试,两种方案都会返回正确的月度时间差:
- 2019-02-01对应的时间差是
28 days 00:00:00 - 2019-03-01对应的时间差是
31 days 00:00:00 - 2019-04-01对应的时间差是
30 days 00:00:00
内容的提问来源于stack exchange,提问作者pierre_j
相关产品推荐
相关产品推荐

