文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

计算时间序列周期的三种方法

2024-11-30 18:11

关注

我们使用City of Ottawa 数据集,主要关注的是每天的服务呼叫数量。所以不需要对病房名称进行初始数据处理。Ottawa 数据集在渥太华市提供的数据门户网站上免费提供。

让我们加载2019-2022年的这些数据,并将它们连接起来得到一个df。

from google.colab import drive
drive.mount('/content/gdrive')
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

file_path = '/content/gdrive/My Drive/Colab Notebooks/Data/SR-2019.xlsx'
records2019 = pd.read_excel(file_path)#,encoding='utf16')

file_path = '/content/gdrive/My Drive/Colab Notebooks/Data/SR-2020.xlsx'
records2020 = pd.read_excel(file_path)#,encoding='utf16')

file_path = '/content/gdrive/My Drive/Colab Notebooks/Data/2021_Monthly_Service_Requests_EN.xlsx'
records2021 = pd.read_excel(file_path)#,encoding='utf16')

file_path = '/content/gdrive/My Drive/Colab Notebooks/Data/2022_Monthly_Service_Requests.csv'
records2022 =pd.read_csv(file_path)

records=pd.concat([records2019,records2020,records2021,records2022],axis=0)

让我们根据服务调用日期聚合这些数据,并得到一个简单的图。

records["DATE_RAISED"]=pd.to_datetime(records.DATE_RAISED)
record_by_date=records.groupby("DATE_RAISED")["TYPE"].count().sort_index()
record_by_date.plot(figsize = (25, 10))
plt.ylabel('Number of requests')
plt.grid(visible=True,which='both')
plt.figure()

record_by_date.iloc[100:130].plot(figsize = (25, 10))
plt.ylabel('Number of requests')
plt.grid(visible=True,which='both')

填充缺失

让我们检查一下我们的数据是否包含了所有的日期。

start_date = record_by_date.index.min()
end_date = record_by_date.index.max()

# create a complete date range for the period of interest
date_range = pd.date_range(start=start_date, end=end_date, freq='D')

# compare the date range to the index of the time series
missing_dates = date_range[~date_range.isin(record_by_date.index)]

if len(missing_dates) > 0:
print("Missing dates:", missing_dates)
else:
print("No missing dates")

正如所预期的那样,数据缺少一些日期的值。让我们用相邻日期的平均值填充这些值。

# Reindex to fill missing dates
idx = pd.date_range(start=record_by_date.index.min(), end=record_by_date.index.max(), freq='D')
record_by_date = record_by_date.reindex(idx, fill_value=0)

# Add missing dates with average of surrounding values
for date in missing_dates:
prev_date = date - pd.DateOffset(days=1)
next_date = date + pd.DateOffset(days=1)
prev_val = record_by_date.loc[prev_date] if prev_date in record_by_date.index else np.nan
next_val = record_by_date.loc[next_date] if next_date in record_by_date.index else np.nan
avg_val = np.nanmean([prev_val, next_val])
record_by_date.loc[date] = avg_val

这就是我们要做的所有预处理了,在所有这些步骤之后,我们尝试检测这个时间序列的周期。一般来说,基于假日模式和一般的人类习惯,我们希望在数据中看到七天的周期,我们来看看是不是有这样的结果。

1、目测

最简单的方法就是目测。这是一种主观的方法,而不是一种正式的或统计的方法,所以我把它作为我们列表中的原始方法。

如果我们看一下这张图的放大部分,我们可以看到7天的周期。最低值出现在5月14日、21日和28日。但最高点似乎不遵循这个模式。但在更大的范围内,我们仍然可以说这个数据集的周期是7天。

下面我们来正式的进行分析:

2、自相关分析

我们将绘制时间序列的自相关值。查看acf图中各种滞后值的峰值。与第一个显著峰值对应的滞后可以给出周期的估计。

对于这种情况,我们看看50个滞后值,并使用statmodels包中的方法绘制acf。

from statsmodels.graphics.tsaplots import plot_acf

fig, ax = plt.subplots(figsize=(14,7))
plot_acf(record_by_date.values.squeeze(), lags=50,ax=ax,title='Autocorrelation', use_vlines=True);
lags = list(range(51))
ax.set_xticks(lags);
ax.set_xticklabels(lags);

从上图可以看出,在7、1、21等处有峰值。这证实了我们的时间序列有7天的周期。

3、快速傅里叶变换

对时间序列进行傅里叶变换,寻找主频分量。主频率的倒数可以作为周期的估计值。

傅里叶变换是一种数学运算,它把一个复杂的信号分解成一组更简单的正弦和余弦波。傅里叶变换广泛应用于信号处理、通信、图像处理以及其他许多科学和工程领域。它允许我们在频域中分析和操作信号,这通常是一种比在时域中更自然和直观的理解和处理信号的方法。

from scipy.fft import fft

# Calculate the Fourier transform
yf = np.fft.fft(record_by_date)
xf = np.linspace(0.0, 1.0/(2.0), len(record_by_date)//2)

# Find the dominant frequency
# We have to drop the first element of the fft as it corresponds to the
# DC component or the average value of the signal
idx = np.argmax(np.abs(yf[1:len(record_by_date)//2]))
freq = xf[idx]

period =(1/freq)
print(f"The period of the time series is {period}")

输出为:The period of the time series is 7.030927835051545。这与我们使用acf和目视检查发现的每周周期相似。

4、周期图

周期图 Periodogram 是一个信号或序列的功率谱密度(PSD)图。换句话说它是一个显示信号中每个频率包含多少总功率的图表。周期图是通过计算信号的傅里叶变换的幅值平方得到的,常用于信号处理和频谱分析。在某种意义上,只是前面给出的基于fft的方法的扩展。

from scipy.signal import periodogram

freq, power = periodogram(record_by_date)
period = 1/freq[np.argmax(power)]
print(f"The period of the time series is {period}")

plt.plot(freq, power)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Power spectral density')
plt.show()

周期图可以清楚地看出,信号的最高功率在0.14,对应于7天的周期。

总结

本文,我们介绍了寻找时间序列周期的三种不同方法,通过使用这三种方法,我们能够识别信号的周期性,并使用常识进行确认。

来源:DeepHub IMBA内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯