pandas处理时间序列数据:基础知识点

情感   2024-09-05 18:30   湖北  

公众号:尤而小屋
编辑: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(20249,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(02 * np.pi, 1460))  # 生成一年的正弦波  
# 添加随机噪声  
np.random.seed(0)  
noise = np.random.normal(00.11460)  
  
# 生成时间序列数据   
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


尤而小屋
尤而小屋,一个温馨且有爱的小屋🏡 小屋主人,一手代码谋求生存,一手掌勺享受生活,欢迎你的光临~
 最新文章