我想在没有循环的情况下(滞后或偏移)时间序列(日、周、月或年)
I want to (Lag or shift) a time series by a (day, week, month or year) without loops
我基本上是在尝试为我的时间序列创建新的专栏,并且我希望根据需要延迟几天、几周、几个月或几年。
我做了一个解决这个问题的函数,但是效率很低。
def lag_N_period ( df, y , days_ago=0 , weeks_ago=0 , months_ago=0 , years_ago=0 ):
skip = days_ago + weeks_ago*7 + months_ago*31 + years_ago*366
## FEATURE NAME ##
feature_name = ''
if days_ago > 0 :
feature_name = feature_name + str(days_ago) + 'days_'
if weeks_ago > 0 :
feature_name = feature_name + str(weeks_ago) + 'weeks_'
if months_ago > 0 :
feature_name = feature_name + str(months_ago) + 'months_'
if years_ago > 0 :
feature_name = feature_name + str(years_ago) + 'years_'
feature_name = feature_name + 'ago'
df[feature_name] = [np.nan for i in range(len(df[objetivo])) ] #Creates NaN column named 'feature_name'
for i in df.index[skip:]:
j = i - dateutil.relativedelta.relativedelta(days=days_ago , weeks=weeks_ago , months=months_ago , years=years_ago)
df[feature_name][i] = df[y][j]
return df
skip 只是一个 int,因为如果在循环中你在数据帧中调用一个索引但它不存在,你会得到一个错误,但是其他任何东西。
df 是我的数据框,日期作为索引,'y',objective 变量
objective
date
2018-01-01 3420
2018-01-02 100580
2018-01-03 78500
2018-01-04 72640
2018-01-05 64980
... ...
2021-01-27 76820
2021-01-28 90520
2021-01-29 81920
2021-01-30 20080
2021-01-31 0
我已经尝试将 .shift() 函数用作 .shift(1, period='M') 但这不是您想要的输出。
唯一有效的情况是当我只想要 5 天或几天前的滞后时,.shift(5)
我们可以使用relativedelta
, pandas.to_datetime
and pandas.DataFrame.apply
.
from dateutil.relativedelta import relativedelta
import pandas as pd
# Sample dataframe
>>> a = pd.DataFrame([('2021-01-01'), ('2021-01-02'), ('2022-01-01')], columns=['Date'])
# Contents of a
>>> a
Date
0 2021-01-01
1 2021-01-02
2 2022-01-01
# Ensuring Date is a datetime column
>>> a['Date'] = pd.to_datetime(a['Date'])
# Adding a month to all of the dates
>>> a.Date.apply(lambda x: x + relativedelta(months=1))
0 2021-02-01
1 2021-02-02
2 2022-02-01
Name: Date, dtype: datetime64[ns]
给定一个 DatetimeIndex
的数据框,它没有像这样的任何缺失天数
df = pd.DataFrame(
{"A": range(500)}, index=pd.date_range("2022-03-01", periods=500, freq="1D")
)
A
2022-03-01 0
2022-03-02 1
... ...
2023-07-12 498
2023-07-13 499
您可以执行以下操作
from dateutil.relativedelta import relativedelta
delta = relativedelta(months=1)
df["B"] = None # None instead of other NaNs - can be changed
idx = df.loc[df.index[0] + delta:].index
df.loc[idx, "B"] = df.loc[[day - delta for day in idx], "A"].values
并获得
A B
2022-03-01 0 None
2022-03-02 1 None
... ... ...
2023-07-12 498 468
2023-07-13 499 469
idx
是为了确保实际的移动不会失败。这是您要通过 skip
解决的部分。 (您的 skip
实际上有点不精确,因为您普遍使用 31/366 天 month/year 长度。)
但是当您使用月 and/or 年时,请准备好 运行 进入奇怪的现象。例如
from datetime import date
delta = relativedelta(months=1)
date(2022, 3, 30) + delta == date(2022, 3, 31) + delta
是True
。
我基本上是在尝试为我的时间序列创建新的专栏,并且我希望根据需要延迟几天、几周、几个月或几年。 我做了一个解决这个问题的函数,但是效率很低。
def lag_N_period ( df, y , days_ago=0 , weeks_ago=0 , months_ago=0 , years_ago=0 ):
skip = days_ago + weeks_ago*7 + months_ago*31 + years_ago*366
## FEATURE NAME ##
feature_name = ''
if days_ago > 0 :
feature_name = feature_name + str(days_ago) + 'days_'
if weeks_ago > 0 :
feature_name = feature_name + str(weeks_ago) + 'weeks_'
if months_ago > 0 :
feature_name = feature_name + str(months_ago) + 'months_'
if years_ago > 0 :
feature_name = feature_name + str(years_ago) + 'years_'
feature_name = feature_name + 'ago'
df[feature_name] = [np.nan for i in range(len(df[objetivo])) ] #Creates NaN column named 'feature_name'
for i in df.index[skip:]:
j = i - dateutil.relativedelta.relativedelta(days=days_ago , weeks=weeks_ago , months=months_ago , years=years_ago)
df[feature_name][i] = df[y][j]
return df
skip 只是一个 int,因为如果在循环中你在数据帧中调用一个索引但它不存在,你会得到一个错误,但是其他任何东西。
df 是我的数据框,日期作为索引,'y',objective 变量
objective
date
2018-01-01 3420
2018-01-02 100580
2018-01-03 78500
2018-01-04 72640
2018-01-05 64980
... ...
2021-01-27 76820
2021-01-28 90520
2021-01-29 81920
2021-01-30 20080
2021-01-31 0
我已经尝试将 .shift() 函数用作 .shift(1, period='M') 但这不是您想要的输出。 唯一有效的情况是当我只想要 5 天或几天前的滞后时,.shift(5)
我们可以使用relativedelta
, pandas.to_datetime
and pandas.DataFrame.apply
.
from dateutil.relativedelta import relativedelta
import pandas as pd
# Sample dataframe
>>> a = pd.DataFrame([('2021-01-01'), ('2021-01-02'), ('2022-01-01')], columns=['Date'])
# Contents of a
>>> a
Date
0 2021-01-01
1 2021-01-02
2 2022-01-01
# Ensuring Date is a datetime column
>>> a['Date'] = pd.to_datetime(a['Date'])
# Adding a month to all of the dates
>>> a.Date.apply(lambda x: x + relativedelta(months=1))
0 2021-02-01
1 2021-02-02
2 2022-02-01
Name: Date, dtype: datetime64[ns]
给定一个 DatetimeIndex
的数据框,它没有像这样的任何缺失天数
df = pd.DataFrame(
{"A": range(500)}, index=pd.date_range("2022-03-01", periods=500, freq="1D")
)
A
2022-03-01 0
2022-03-02 1
... ...
2023-07-12 498
2023-07-13 499
您可以执行以下操作
from dateutil.relativedelta import relativedelta
delta = relativedelta(months=1)
df["B"] = None # None instead of other NaNs - can be changed
idx = df.loc[df.index[0] + delta:].index
df.loc[idx, "B"] = df.loc[[day - delta for day in idx], "A"].values
并获得
A B
2022-03-01 0 None
2022-03-02 1 None
... ... ...
2023-07-12 498 468
2023-07-13 499 469
idx
是为了确保实际的移动不会失败。这是您要通过 skip
解决的部分。 (您的 skip
实际上有点不精确,因为您普遍使用 31/366 天 month/year 长度。)
但是当您使用月 and/or 年时,请准备好 运行 进入奇怪的现象。例如
from datetime import date
delta = relativedelta(months=1)
date(2022, 3, 30) + delta == date(2022, 3, 31) + delta
是True
。