创建非标准Pandas频率(“十天”=每月3期)

h6my8fg2  于 2023-03-16  发布在  其他
关注(0)|答案(1)|浏览(150)

bounty将在4天后过期。回答此问题可获得+500声望奖励。user308827希望引起更多人关注此问题。

由于statsmodels.tseries模型需要具有给定频率的指数来进行预测,因此我需要数据具有非标准频率。
因此,我想创建一个新的频率来分配给pandas.DateTimeIndex。这是一个dekad频率,其中一年有36个时段。每个月三个时段。第一个时段总是在该月的第10天,第二个时段是该月的第20天,最后一个时段是该月的最后一天。
困难的是,每月的最后一天:
1.二月的不同取决于是否是闰年(28日或29日)
1.根据该月的天数而有所不同(28、29、30、31)
然而,最终,它是一个固定的频率(每月3次,每年36期)。
原因是statsmodels.tsa.holtwinters模型需要具有给定频率的索引来进行预测。当我尝试运行holtwinters预测时,收到以下警告消息:

/home/tommy/miniconda3/envs/ml/lib/python3.8/site-packages/statsmodels/tsa/base/tsa_model.py:216: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.

这是十分钟时间步长的样子:

from pandas.tseries.offsets import MonthEnd

dates = pd.date_range("2000-01-01", "2003-01-01")
_dekads = [d for d in dates if d.day in [10, 20]]
_month_ends = [d + MonthEnd(1) for d in dates if d.day == 10]
dekads = sorted(np.concatenate([_dekads, _month_ends]))

我希望能够为索引分配一个十周频率
一个二个一个一个
我希望能给物体分配一个“十年”频率。我怎样才能创建我自己的十年频率?

df.index.freq = "dekad"
Out[]:
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
pandas/_libs/tslibs/offsets.pyx in pandas._libs.tslibs.offsets._get_offset()

KeyError: 'DEKAD'

The above exception was the direct cause of the following exception:

ValueError                                Traceback (most recent call last)
pandas/_libs/tslibs/offsets.pyx in pandas._libs.tslibs.offsets.to_offset()

pandas/_libs/tslibs/offsets.pyx in pandas._libs.tslibs.offsets._get_offset()

ValueError: Invalid frequency: DEKAD

The above exception was the direct cause of the following exception:

ValueError                                Traceback (most recent call last)
<ipython-input-155-aa7b4737fd5a> in <module>
      7 
      8 df = pd.DataFrame({"y": np.random.random(len(dekads))}, index=dekads)
----> 9 df.index.freq = "dekad"

~/miniconda3/envs/ml/lib/python3.8/site-packages/pandas/core/indexes/extension.py in fset(self, value)
     62 
     63             def fset(self, value):
---> 64                 setattr(self._data, name, value)
     65 
     66             fget.__name__ = name

~/miniconda3/envs/ml/lib/python3.8/site-packages/pandas/core/arrays/datetimelike.py in freq(self, value)
   1090     def freq(self, value):
   1091         if value is not None:
-> 1092             value = to_offset(value)
   1093             self._validate_frequency(self, value)
   1094 

pandas/_libs/tslibs/offsets.pyx in pandas._libs.tslibs.offsets.to_offset()

pandas/_libs/tslibs/offsets.pyx in pandas._libs.tslibs.offsets.to_offset()

ValueError: Invalid frequency: dekad

如何在Pandas中创建新的freq对象

本练习的目的:

df = pd.read_csv(
    "https://gist.githubusercontent.com/tommylees112/2b1b2dda43d91ea9346a6edaa6788ec8/raw/644af74955ce078d1c4d55a2ffd6a55eeb59bad4/demo_data_SO_02092021.csv"
).astype({"time": "datetime64[ns]"}).set_index("time")

train, test = df.iloc[:-100], df.iloc[-100:]

f, ax = plt.subplots(figsize=(12, 4))
ax.plot(train, label="train")
ax.plot(test, label="test")
plt.xticks(rotation=70)
plt.legend()

from statsmodels.tsa.holtwinters import SimpleExpSmoothing, ExponentialSmoothing

# set seasonality parameters
m = 36
alpha = 1/(2*m)

model = ExponentialSmoothing(train["vci"],trend="mul").fit()

preds = model.forecast(len(test))
preds.index = test.index

f, ax = plt.subplots(figsize=(12, 4))
ax.plot(train.index, model.fittedvalues, label="Train Preditions")
ax.plot(test.index, preds, label="Test Preditions")
ax.plot(df.index, df["vci"], ls="--", color="k", alpha=0.6)
plt.xticks(rotation=70)
plt.legend()

这个预测显然很差,没有反映学到的季节性。我相信这是一个没有为日期时间索引分配频率的问题。
如果有其他方法可以实现这些目标,那么我会非常热衷于探索这些方法。我想创建一个新的频率来分配给pandas.DateTimeIndex。原因是statsmodels.tseries模型需要具有给定频率的指数来进行预测。

wbrvyc0a

wbrvyc0a1#

您可以编辑源代码并添加规则来定义频率,但您可能不想这样做。
一个简单的实现是使用现有的自定义工作日频率:

pd.offsets.CustomBusinessDay(
    holidays=my_holidays,
    weekmask=my_weekdays,
)

并将您的假日日历定义为除10、20和is_month_end偏移别名docs之外的每一天
我猜你希望你的工作日是周一到周日(确保你没有漏掉10号、20号或is_month_end

start_date = '1/1/2023'
end_date = '31/12/2023'
full_calendar = pd.date_range(start=start_date, end=end_date)[source](https://pandas.pydata.org/docs/reference/api/pandas.date_range.html)

my_holidays = full_calendar[full_calendar.day != 10] #not the 10th of the month
my_holidays = my_holidays[my_holidays.day != 20] #not the 20th of the month
my_holidays = my_holidays[~my_holidays.is_month_end] #not the last day of the month
my_weekdays = = "Sun Mon Tue Wed Thu Fri Sat"
dekad = pd.offsets.CustomBusinessDay(
    holidays=my_holidays,
    weekmask=my_weekdays,
)

现在,您可以将其用作freq

my_dekad_dates = pd.date_range("2000-01-01", "2003-01-01", freq=dekad)

相关问题