Pandas 时间序列优化问题:添加年份

数据挖掘 Python 熊猫
2021-09-16 20:17:27

我有一个包含时间序列列的 pandas DataFrame。年份在过去发生了变化,因此我必须为该列的每个元素添加恒定的年份。

我发现的最好方法是遍历所有记录并使用

x.replace(year=x.year + years)  # x = current element, years = years to add

它如下所示,但仍然很慢(打样)

cdef list _addYearsToTimestamps(list elts, int years):
    cdef cpdatetime x
    cdef int i
    for (i, x) in enumerate(elts):
        try:
            elts[i] = x.replace(year=x.year + years)
        except Exception as e:
            logError(None, "Cannot replace year of %s - leaving value as this: %s" % (str(x), repr(e)))
    return elts

def fixYear(data):
    data.loc[:, 'timestamp'] = _addYearsToTimestamps(list(data.loc[:, 'timestamp']), REAL_YEAR-(list(data[-1:]['timestamp'])[0].year))
    return data

我很确定有一种方法可以通过使用 Pandas 的时间戳功能来更改年份而无需迭代。不幸的是,我不知道怎么做。有人可以详细说明吗?

3个回答

制作一个 pandas Timedelta 对象,然后使用 += 运算符添加:

x = pandas.Timedelta(days=365)
mydataframe.timestampcolumn += x

所以关键是将你的时间序列存储为时间戳。为此,请使用 pandasto_datetime函数:

mydataframe['timestampcolumn'] = pandas.to_datetime(x['epoch'], unit='s')

假设您将时间戳记作为数据帧中的纪元秒数x这当然不是必需的。有关转换其他格式的信息,请参阅to_datetime文档。

改编自 Pete 的回答,这是解决方案的实现和演示。

#!/usr/bin/env python3

import random
import pandas
import time
import datetime

def getRandomDates(n):
    tsMin = time.mktime(time.strptime("1980-01-01 00:00:00", "%Y-%m-%d %H:%M:%S"))
    tsMax = time.mktime(time.strptime("2005-12-31 23:59:59", "%Y-%m-%d %H:%M:%S"))
    return pandas.Series([datetime.datetime.fromtimestamp(tsMin + random.random() * (tsMax - tsMin)) for x in range(0, n)])

def setMaxYear(tss, target):
    maxYearBefore = tss.max().to_datetime().year
    # timedelta cannot be given in years, so we compute the number of days to add in the next line
    deltaDays = (datetime.date(target, 1, 1) - datetime.date(maxYearBefore, 1, 1)).days
    return tss + pandas.Timedelta(days=deltaDays)

data = pandas.DataFrame({'t1': getRandomDates(1000)})
data['t2'] = setMaxYear(data['t1'], 2015)
data['delta'] = data['t2'] - data['t1']
print(data)
print("delta min: %s" % str(min(data['delta'])))
print("delta max: %s" % str(max(data['delta'])))

datetutil 提供了一个 relativedelta,它允许以年为增量向前/向后移动。与 pd.Timedelta (固定长度)相反,它考虑了闰年。

from dateutil.relativedelta import relativedelta
pd.Timestamp('20000105') + relativedelta(years=1)

将此应用于索引使用

df.index.map(lambda x: x-relativedelta(years=1))

这不如 pd.Timedelta 方便,但似乎仍然相当快。

如@ALollz 的评论所示,在熊猫中执行此操作的正确方法(感谢您的提示!):

df.index+pd.offsets.DateOffset(years=1)