公众号:尤而小屋
编辑:Peter
作者:Peter
大家好,我是Peter~
Pandas 是一个强大的 Python 数据分析库,它提供了非常灵活和高效的方式来处理时间序列数据。
时间序列数据是指按照时间顺序排列的数据点集合,通常用于分析随时间变化的趋势、周期性或其他统计特性。
Pandas提供了很多的函数来处理时间序列相关的数据,比如:
- 使用 Timestamp 和 DatetimeIndex:Timestamp 表示单个时间点,而 DatetimeIndex 是由多个 Timestamp 组成的索引
- 使用 pd.date_range():快速生成时间序列的日期范围
- 使用 .resample() 方法可以对时间序列数据进行重新采样,例如从日数据转换为月数据
- 使用 DateOffset 或 Timedelta 对时间序列进行时间偏移
- 使用 .rolling() 或 .expanding() 方法进行滑动窗口或扩展窗口的计算,如计算移动平均等。
本文介绍基于pandas处理时间序列数据的基础知识:
- 时间戳对象TimeStamp
- 时间范围的生成
- 时间序列数据的生成与选择
导入库
import numpy as np
import pandas as pd
import os
import datetime
import time
np.random.seed(42)
import plotly_express as px
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set_theme(style="darkgrid")
# 设置支持中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
# 设置图像标题字体
plt.rcParams['axes.unicode_minus'] = False
import warnings
warnings.filterwarnings('ignore')
时间戳Timestamp
在pandas中,时间戳(Timestamp,通常指的是自1970年1月1日(UTC)以来的秒数)是用于表示特定时间点的数据类型。它是pandas库中用于时间序列分析的一个重要组成部分,基于Python的datetime模块但提供了更丰富的功能。时间戳不仅包含日期(年、月、日),还包含时间(时、分、秒,以及可选的毫秒、微秒和纳秒)。
首先,如何获取当前时间的时间戳(秒)?
import time
time.time()
1725526309.6035366
创建时间戳对象
1、直接使用字符串创建时间戳
ts = pd.Timestamp("2024-09-03 08:30:00")
ts # 时间戳对象
Timestamp(‘2024-09-03 08:30:00’)
2、使用datetime对象创建:将Python的datetime对象传递给Timestamp构造函数
from datetime import datetime
dt_obj = datetime(2024, 9,3,8,30)
dt_obj
datetime.datetime(2024, 9, 3, 8, 30)
ts1 = pd.Timestamp(dt_obj)
ts1
Timestamp(‘2024-09-03 08:30:00’)
可以看到生成的效果和上面是一样的。
也可以通过timestamp属性直接获取其时间戳(秒):
dt_obj.timestamp() # 具体的秒数
1725323400.0
3、使用pandas的to_datetime
函数,它可以灵活地处理列表、数组、Series等数据结构中的日期字符串数据,并将它们转成时间戳对象。
ts2 = pd.to_datetime(["2024-09-03 08:30:00","2024-09-03 10:30:00","2024-09-03 12:30:00"])
ts2
DatetimeIndex(['2024-09-03 08:30:00', '2024-09-03 10:30:00','2024-09-03 12:30:00'],dtype='datetime64[ns]', freq=None)
ts2中的每个元素都是时间戳对象:
ts2[0]
Timestamp(‘2024-09-03 08:30:00’)
时间戳的属性
以ts1对象为例
ts1
Timestamp(‘2024-09-03 08:30:00’)
单独获取年、月、日、时分秒等
ts1.year # 年
2024
ts1.month # 月
9
ts1.day # 日
3
ts1.hour,ts1.minute,ts1.second # 时分秒
(8, 30, 0)
ts1.daysinmonth # 一月中的哪天
30
时间戳的方法
返回datetime.dateimte
对象:
ts1.date() # 获取完整的年月日
datetime.date(2024, 9, 3)
ts1.day_of_week # 星期几(数字)
1
ts1.day_name() # 星期几(英文)
‘Tuesday’
ts1.day_of_year # 一年当中的第几天
247
ts1.time() # 获取月日
datetime.time(8, 30)
ts1.days_in_month # 该月中的第几天
30
时间范围data_range
pandas.date_range(
start=None,
end=None,
periods=None,
freq=None,
tz=None,
normalize=False,
name=None,
inclusive='both', # start和end是否全部包含:both-left-right
unit=None)
官网地址:
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.date_range.html
生成的是DatatimeIndex形式的数据
指定开始和截止时间
dr1 = pd.date_range(start="2024-01-01",end="2024-08-01")
dr1
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04',
'2024-01-05', '2024-01-06', '2024-01-07', '2024-01-08',
'2024-01-09', '2024-01-10',
...
'2024-07-23', '2024-07-24', '2024-07-25', '2024-07-26',
'2024-07-27', '2024-07-28', '2024-07-29', '2024-07-30',
'2024-07-31', '2024-08-01'],
dtype='datetime64[ns]', length=214, freq='D')
指定周期数periods
dr2 = pd.date_range(start="2024-01-01",periods=20)
dr2
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04',
'2024-01-05', '2024-01-06', '2024-01-07', '2024-01-08',
'2024-01-09', '2024-01-10', '2024-01-11', '2024-01-12',
'2024-01-13', '2024-01-14', '2024-01-15', '2024-01-16',
'2024-01-17', '2024-01-18', '2024-01-19', '2024-01-20'],
dtype='datetime64[ns]', freq='D')
指定频率freq
默认是以天为频率:
dr3 = pd.date_range(start="2024-01-01",periods=6, freq="D") # 年
dr3
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04', '2024-01-05', '2024-01-06'],dtype='datetime64[ns]', freq='D')
以月为频率,生成6个周期数的数据
dr3 = pd.date_range(start="2024-01-01",periods=6, freq="M") # 月
dr3
DatetimeIndex(['2024-01-31', '2024-02-29', '2024-03-31', '2024-04-30','2024-05-31', '2024-06-30'],dtype='datetime64[ns]', freq='ME')
以年为频率:
dr3 = pd.date_range(start="2024-01-01",periods=6, freq="Y") # 年
dr3
DatetimeIndex(['2024-12-31', '2025-12-31', '2026-12-31', '2027-12-31','2028-12-31', '2029-12-31'],dtype='datetime64[ns]', freq='YE-DEC')
dr3 = pd.date_range(start="2024-01-01",periods=6, freq="2Y") # 2年
dr3
DatetimeIndex(['2024-12-31', '2026-12-31', '2028-12-31', '2030-12-31','2032-12-31', '2034-12-31'],dtype='datetime64[ns]', freq='2YE-DEC')
以星期为频率:
dr3 = pd.date_range(start="2024-01-01",periods=6, freq="W") # 星期
dr3
DatetimeIndex(['2024-01-07', '2024-01-14', '2024-01-21', '2024-01-28',
'2024-02-04', '2024-02-11'],
dtype='datetime64[ns]', freq='W-SUN')
dr3 = pd.date_range(start="2024-01-01",periods=6, freq="2W") # 2星期
dr3
DatetimeIndex(['2024-01-07', '2024-01-21', '2024-02-04', '2024-02-18',
'2024-03-03', '2024-03-17'],
dtype='datetime64[ns]', freq='2W-SUN')
freq参数不同取值的别名:
- D:Day;每日历日
- B:BussinessDay;每工作日
- H:Hour;小时
- T/min:Minute;分
- S:Second;秒
- L/ms:Milli;毫秒(秒的千分之一)
- U:Micro;微秒(秒的百分分之一)
- M:MonthEnd;每月最后一个日历日
- BM:BusinessMonthEnd;每月最后一个工作日
- MS:MonthBegin;每月第一个日历日
- BMS:BusinessMonthBegin;每月第一个工作日
- W-MON、W-TUE:Week;从指定的星期几(MON、TUE、WED等)开始算起
- WOM-1MON、WOM-2MON: WeekOfMonth;产生每月第一、第二、第三或第四周的星期几;比如,WOM-3FRI表示每月的第3个星期五
- Q-JAN、Q-FEB:QuarterEnd;对于以指定月份(JAN、FEB、MAR等)结束的年度,每季度最后一月的最后一个日历日
- BQ-JAN、BQ-FEB:BuinessQuarterEnd;对于以指定月份结束的年度,每季度最后一个月的最后一个工作日
时间标准化
有时候生成的数据是包含具体时间信息的开始或结束日期新鲜,可以通过normalize=True参数将其转化成零点的整数据:
# 默认非标准化数据
dr4 = pd.date_range(start="2024-01-01 01:25:38",periods=6, normalize=False)
dr4
DatetimeIndex(['2024-01-01 01:25:38', '2024-01-02 01:25:38',
'2024-01-03 01:25:38', '2024-01-04 01:25:38',
'2024-01-05 01:25:38', '2024-01-06 01:25:38'],
dtype='datetime64[ns]', freq='D')
# 标准化数据
dr5 = pd.date_range(start="2024-01-01 01:25:38",periods=6, normalize=True)
dr5
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04','2024-01-05', '2024-01-06'],dtype='datetime64[ns]', freq='D')
还可以指定时区tz:
dr6 = pd.date_range(start="2024-01-01",periods=6,freq="M",tz="Asia/ShangHai") # 月
dr6
DatetimeIndex(['2024-01-31 00:00:00+08:00', '2024-02-29 00:00:00+08:00',
'2024-03-31 00:00:00+08:00', '2024-04-30 00:00:00+08:00',
'2024-05-31 00:00:00+08:00', '2024-06-30 00:00:00+08:00'],
dtype='datetime64[ns, Asia/Shanghai]', freq='ME')
dr6 = pd.date_range(start="2024-01-01",periods=6,freq="2M",tz="Asia/ShangHai") # 2月
dr6
DatetimeIndex(['2024-01-31 00:00:00+08:00', '2024-03-31 00:00:00+08:00',
'2024-05-31 00:00:00+08:00', '2024-07-31 00:00:00+08:00',
'2024-09-30 00:00:00+08:00', '2024-11-30 00:00:00+08:00'],
dtype='datetime64[ns, Asia/Shanghai]', freq='2ME')
时间范围period_range
pandas.period_range(
start=None, # 开始和结束时间
end=None,
periods=None, # 周期数、频率
freq=None,
name=None)
注意:start、end和periods选择其中两个参数
官方地址:https://pandas.pydata.org/docs/reference/api/pandas.period_range.html
最终生成的是PeriodIndex类型的数据。
指定开始和截止时间
pr1 = pd.period_range(start="2024-01-01",end="2024-09-01")
pr1 # PeriodIndex对象
PeriodIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04',
'2024-01-05', '2024-01-06', '2024-01-07', '2024-01-08',
'2024-01-09', '2024-01-10',
...
'2024-08-23', '2024-08-24', '2024-08-25', '2024-08-26',
'2024-08-27', '2024-08-28', '2024-08-29', '2024-08-30',
'2024-08-31', '2024-09-01'],
dtype='period[D]', length=245)
指定周期数periods
pr2 = pd.period_range(start="2024/01/01",periods=30) # 开始时间+周期数
pr2 # PeriodIndex对象
PeriodIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04',
'2024-01-05', '2024-01-06', '2024-01-07', '2024-01-08',
'2024-01-09', '2024-01-10', '2024-01-11', '2024-01-12',
'2024-01-13', '2024-01-14', '2024-01-15', '2024-01-16',
'2024-01-17', '2024-01-18', '2024-01-19', '2024-01-20',
'2024-01-21', '2024-01-22', '2024-01-23', '2024-01-24',
'2024-01-25', '2024-01-26', '2024-01-27', '2024-01-28',
'2024-01-29', '2024-01-30'],
dtype='period[D]')
pr3 = pd.period_range(end="2024-01-01",periods=30) # 截止时间+周期数
pr3 # PeriodIndex对象
PeriodIndex(['2023-12-03', '2023-12-04', '2023-12-05', '2023-12-06',
'2023-12-07', '2023-12-08', '2023-12-09', '2023-12-10',
'2023-12-11', '2023-12-12', '2023-12-13', '2023-12-14',
'2023-12-15', '2023-12-16', '2023-12-17', '2023-12-18',
'2023-12-19', '2023-12-20', '2023-12-21', '2023-12-22',
'2023-12-23', '2023-12-24', '2023-12-25', '2023-12-26',
'2023-12-27', '2023-12-28', '2023-12-29', '2023-12-30',
'2023-12-31', '2024-01-01'],
dtype='period[D]')
指定频率freq
# 按月生成数据
pr4 = pd.period_range(start="2020-01-01",end="2024-01-01",freq="M")
pr4 # PeriodIndex对象
PeriodIndex(['2020-01', '2020-02', '2020-03', '2020-04', '2020-05', '2020-06',
'2020-07', '2020-08', '2020-09', '2020-10', '2020-11', '2020-12',
'2021-01', '2021-02', '2021-03', '2021-04', '2021-05', '2021-06',
'2021-07', '2021-08', '2021-09', '2021-10', '2021-11', '2021-12',
'2022-01', '2022-02', '2022-03', '2022-04', '2022-05', '2022-06',
'2022-07', '2022-08', '2022-09', '2022-10', '2022-11', '2022-12',
'2023-01', '2023-02', '2023-03', '2023-04', '2023-05', '2023-06',
'2023-07', '2023-08', '2023-09', '2023-10', '2023-11', '2023-12',
'2024-01'],
dtype='period[M]')
# W-SAT表示周期的频率为每周六(SAT),即每个周期间隔一周,且周期开始于周六
pr5 = pd.period_range(start="2020-01-01",freq="W-SAT",periods=10)
pr5
PeriodIndex(['2019-12-29/2020-01-04', '2020-01-05/2020-01-11',
'2020-01-12/2020-01-18', '2020-01-19/2020-01-25',
'2020-01-26/2020-02-01', '2020-02-02/2020-02-08',
'2020-02-09/2020-02-15', '2020-02-16/2020-02-22',
'2020-02-23/2020-02-29', '2020-03-01/2020-03-07'],
dtype='period[W-SAT]')
时间序列
基于时间序列索引生成时间序列的Series或者DataFrame数据:
简单的线性时间序列数据
s1 = pd.Series(data=np.arange(1000),index=pd.date_range(start="2022-08-01", periods=1000))
s1
2022-08-01 0
2022-08-02 1
2022-08-03 2
2022-08-04 3
2022-08-05 4
...
2025-04-22 995
2025-04-23 996
2025-04-24 997
2025-04-25 998
2025-04-26 999
Freq: D, Length: 1000, dtype: int32
查看索引信息:
s1.index
DatetimeIndex(['2022-08-01', '2022-08-02', '2022-08-03', '2022-08-04',
'2022-08-05', '2022-08-06', '2022-08-07', '2022-08-08',
'2022-08-09', '2022-08-10',
...
'2025-04-17', '2025-04-18', '2025-04-19', '2025-04-20',
'2025-04-21', '2025-04-22', '2025-04-23', '2025-04-24',
'2025-04-25', '2025-04-26'],
dtype='datetime64[ns]', length=1000, freq='D')
也可以用于生成DataFrame的数据:
df1 = pd.DataFrame({"col1": np.arange(5000),"col2": np.arange(5000,10000)},
index=pd.date_range(start="2020-01-01",periods=5000)
)
df1.head()
df1.index[:5]
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04','2020-01-05'],dtype='datetime64[ns]', freq='D')
# 基于plotly的可视化
# fig = px.scatter(df1,y=["col1","col2"])
# fig.show()
df1.plot()
plt.show()
具有随机噪声的时间序列数据
# 索引
index = pd.date_range("2023-01-01",periods=100)
# 基础线性数据
base = np.linspace(0,100,100)
# 添加随机噪声
np.random.seed()
noise = np.random.normal(0,10,100) # 均值为0-标准差为10的正态分布噪声数据
# 时间序列数据
df2 = pd.DataFrame({"col": base + noise}, index=index)
df2
# fig = px.scatter(df2,y="col")
# fig.show()
df2.plot()
plt.show()
生成周期性时间序列数据
365*4
1460
# 设置时间范围
index = pd.date_range('2023-01-01', periods=1460)
# 生成基础数据
base = np.sin(np.linspace(0, 2 * np.pi, 1460)) # 生成一年的正弦波
# 添加随机噪声
np.random.seed(0)
noise = np.random.normal(0, 0.1, 1460)
# 生成时间序列数据
df3 = pd.DataFrame({"col": base + noise}, index=index)
df3
# fig = px.scatter(df3,y="col")
# fig.show()
基于pandas内置的可视化功能:
df3.plot()
plt.show()
选择时间序列数据
从时间序列数据中选择指定条件下的数据
s1
2022-08-01 0
2022-08-02 1
2022-08-03 2
2022-08-04 3
2022-08-05 4
...
2025-04-22 995
2025-04-23 996
2025-04-24 997
2025-04-25 998
2025-04-26 999
Freq: D, Length: 1000, dtype: int32
s1[2] # 索引为2的数据
2
s1["2022-08-05"] # 选择2022年8月5号的数据
4
s1["2022"] # 选择2022年全部数据
2022-08-01 0
2022-08-02 1
2022-08-03 2
2022-08-04 3
2022-08-05 4
...
2022-12-27 148
2022-12-28 149
2022-12-29 150
2022-12-30 151
2022-12-31 152
Freq: D, Length: 153, dtype: int32
s1["2022-08"] # 选择2022年8月份的全部数据
# s1.loc["2022-08"] # 等效功能
2022-08-01 0
2022-08-02 1
2022-08-03 2
2022-08-04 3
2022-08-05 4
2022-08-06 5
2022-08-07 6
2022-08-08 7
2022-08-09 8
2022-08-10 9
2022-08-11 10
2022-08-12 11
2022-08-13 12
2022-08-14 13
2022-08-15 14
2022-08-16 15
2022-08-17 16
2022-08-18 17
2022-08-19 18
2022-08-20 19
2022-08-21 20
2022-08-22 21
2022-08-23 22
2022-08-24 23
2022-08-25 24
2022-08-26 25
2022-08-27 26
2022-08-28 27
2022-08-29 28
2022-08-30 29
2022-08-31 30
Freq: D, dtype: int32
s1[datetime(2024,1,1):] # 选2024-1-1之后的全部数据
2024-01-01 518
2024-01-02 519
2024-01-03 520
2024-01-04 521
2024-01-05 522
...
2025-04-22 995
2025-04-23 996
2025-04-24 997
2025-04-25 998
2025-04-26 999
Freq: D, Length: 482, dtype: int32
s1["2022-08-01":"2022-08-08"] # 选择指定时间段内的数据
2022-08-01 0
2022-08-02 1
2022-08-03 2
2022-08-04 3
2022-08-05 4
2022-08-06 5
2022-08-07 6
2022-08-08 7
Freq: D, dtype: int32
s1.truncate(after="2023-04") # 选择截止到2023-04-01的数据
2022-08-01 0
2022-08-02 1
2022-08-03 2
2022-08-04 3
2022-08-05 4
...
2023-03-28 239
2023-03-29 240
2023-03-30 241
2023-03-31 242
2023-04-01 243
Freq: D, Length: 244, dtype: int32