Pandas中時(shí)間序列分析的核心功能和實(shí)戰(zhàn)指南
本節(jié)學(xué)習(xí)目標(biāo)
- 掌握 Pandas 中日期時(shí)間類型的創(chuàng)建與操作
- 學(xué)會(huì)使用
date_range生成日期序列 - 掌握
resample重采樣方法 - 理解
rolling滑動(dòng)窗口計(jì)算 - 能夠處理時(shí)區(qū)和日期偏移
為什么學(xué)這個(gè)?
幾乎所有業(yè)務(wù)數(shù)據(jù)都和時(shí)間相關(guān):
- 銷售數(shù)據(jù)——按天、按周、按月匯總
- 股票數(shù)據(jù)——計(jì)算移動(dòng)平均線、波動(dòng)率
- 網(wǎng)站流量——分析用戶活躍時(shí)段
- 生產(chǎn)數(shù)據(jù)——監(jiān)測(cè)設(shè)備運(yùn)行趨勢(shì)
在 Pandas 出現(xiàn)之前,處理時(shí)間序列數(shù)據(jù)非常痛苦。你需要手動(dòng)解析日期字符串、處理閏年、計(jì)算工作日……現(xiàn)在,Pandas 提供了一整套時(shí)間序列工具,讓時(shí)間分析變得優(yōu)雅而強(qiáng)大。
Pandas 的時(shí)間序列優(yōu)勢(shì):
- 自動(dòng)處理日期格式解析
- 內(nèi)置豐富的日期范圍生成器
- 一行代碼完成"按周/月/季度重采樣"
- 滑動(dòng)窗口計(jì)算(移動(dòng)平均、累計(jì)求和等)
打個(gè)比方:如果說(shuō) DataFrame 是一個(gè)倉(cāng)庫(kù),那么時(shí)間序列工具就是倉(cāng)庫(kù)的"時(shí)間管理器"——它能告訴你"什么時(shí)候進(jìn)了多少貨"、“過(guò)去 7 天平均每天出多少貨”、“下個(gè)月的預(yù)期銷量”。
核心知識(shí)點(diǎn)講解
datetime 類型與日期解析
1. Python 的 datetime 模塊
from datetime import datetime, timedelta
# 創(chuàng)建日期時(shí)間對(duì)象
dt = datetime(2024, 3, 15, 14, 30, 0)
print(dt) # 2024-03-15 14:30:00
# 獲取當(dāng)前時(shí)間
now = datetime.now()
print(f"當(dāng)前時(shí)間:{now}")
# 日期運(yùn)算
tomorrow = dt + timedelta(days=1)
print(f"明天:{tomorrow}")
last_week = dt - timedelta(weeks=1)
print(f"上周:{last_week}")
# 提取各個(gè)部分
print(f"年:{dt.year}")
print(f"月:{dt.month}")
print(f"日:{dt.day}")
print(f"星期:{dt.weekday()}") # 0=周一,6=周日
print(f"時(shí)分秒:{dt.hour}:{dt.minute}:{dt.second}")
2. Pandas 的 Timestamp 類型
import pandas as pd
import numpy as np
# Pandas 的時(shí)間戳
ts = pd.Timestamp('2024-03-15 14:30:00')
print(ts)
# 從字符串自動(dòng)解析
ts = pd.Timestamp('2024/3/15')
print(ts)
ts = pd.Timestamp('15 March 2024')
print(ts)
# 獲取時(shí)間屬性
print(f"年:{ts.year}")
print(f"月:{ts.month}")
print(f"日:{ts.day}")
print(f"星期幾:{ts.day_name()}") # Friday
print(f"季度:{ts.quarter}") # 1
print(f"年初至今天數(shù):{ts.dayofyear}") # 75
print(f"本月天數(shù):{ts.days_in_month}") # 31
3. to_datetime:批量轉(zhuǎn)換日期列
# 這是處理時(shí)間序列數(shù)據(jù)的第一步:把字符串列轉(zhuǎn)為 datetime 類型
df = pd.DataFrame({
'日期': ['2024-01-01', '2024-02-15', '2024-03-20', '2024-04-10'],
'銷售額': [1000, 1500, 1200, 1800]
})
print("轉(zhuǎn)換前:")
print(df.dtypes)
# 日期 object(字符串)
# 轉(zhuǎn)換為 datetime
df['日期'] = pd.to_datetime(df['日期'])
print("\n轉(zhuǎn)換后:")
print(df.dtypes)
# 日期 datetime64[ns]
# ===== 處理不同格式的日期 =====
df2 = pd.DataFrame({
'日期': ['01/15/2024', '02/20/2024', '03/25/2024']
})
df2['日期'] = pd.to_datetime(df2['日期'], format='%m/%d/%Y')
print(df2)
# ===== 處理包含錯(cuò)誤的日期 =====
df3 = pd.DataFrame({
'日期': ['2024-01-01', 'invalid', '2024-03-01']
})
# errors='coerce' 將無(wú)法解析的值轉(zhuǎn)為 NaT(Not a Time)
df3['日期'] = pd.to_datetime(df3['日期'], errors='coerce')
print(df3)
date_range:生成日期序列
# ===== 基本用法 =====
# 生成從 2024-01-01 開(kāi)始的 10 天日期序列
dates = pd.date_range(start='2024-01-01', periods=10)
print("10天序列:")
print(dates)
# 生成到 2024-01-31 結(jié)束的所有日期
dates = pd.date_range(end='2024-01-31', periods=5)
print("\n5天序列:")
print(dates)
# 指定起止日期
dates = pd.date_range('2024-01-01', '2024-01-10')
print("\n指定起止:")
print(dates)
# ===== 不同頻率 =====
# freq 參數(shù)控制頻率
print("每日:", pd.date_range('2024-01-01', periods=5, freq='D'))
print("每周:", pd.date_range('2024-01-01', periods=5, freq='W'))
print("每月:", pd.date_range('2024-01-01', periods=5, freq='M'))
print("每季:", pd.date_range('2024-01-01', periods=5, freq='Q'))
print("每年:", pd.date_range('2024-01-01', periods=5, freq='Y'))
print("每小時(shí):", pd.date_range('2024-01-01', periods=5, freq='H'))
# ===== 常用頻率代碼 =====
# D —— 日歷日
# B —— 工作日(排除周末)
# W —— 每周
# M —— 月末
# MS —— 月初
# Q —— 季末
# QS —— 季初
# Y —— 年末
# YS —— 年初
# H —— 每小時(shí)
# T/min —— 每分鐘
# S —— 每秒
# ===== 工作日序列 =====
# 只生成工作日(排除周六日)
workdays = pd.date_range('2024-01-01', periods=10, freq='B')
print("\n工作日序列:")
print(workdays)
# 自定義(如每周三)
wednesdays = pd.date_range('2024-01-01', periods=10, freq='W-WED')
print("\n每周三:")
print(wednesdays)
創(chuàng)建帶日期索引的 DataFrame
# 最常用的做法:用 date_range 創(chuàng)建時(shí)間序列 DataFrame
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=30, freq='D')
df = pd.DataFrame({
'銷售額': np.random.randint(1000, 5000, 30),
'訪客數(shù)': np.random.randint(100, 500, 30),
'轉(zhuǎn)化率': np.random.uniform(0.02, 0.08, 30)
}, index=dates)
df.index.name = '日期'
print(df.head())
日期訪問(wèn)器(dt accessor)
轉(zhuǎn)換后的 datetime 列可以通過(guò) .dt 訪問(wèn)器提取各種時(shí)間屬性。
df = pd.DataFrame({
'日期': pd.date_range('2024-01-01', periods=10, freq='D'),
'銷售額': np.random.randint(1000, 5000, 10)
})
# ===== 提取時(shí)間屬性 =====
df['年'] = df['日期'].dt.year
df['月'] = df['日期'].dt.month
df['日'] = df['日期'].dt.day
df['季度'] = df['日期'].dt.quarter
df['星期'] = df['日期'].dt.day_name()
df['周幾'] = df['日期'].dt.dayofweek # 0=周一
df['一年中第幾天'] = df['日期'].dt.dayofyear
df['第幾周'] = df['日期'].dt.isocalendar().week
df['是否月初'] = df['日期'].dt.is_month_start
df['是否月末'] = df['日期'].dt.is_month_end
print(df)
resample 重采樣
resample 是時(shí)間序列分析中最核心的方法。它可以把數(shù)據(jù)從一個(gè)時(shí)間粒度轉(zhuǎn)換到另一個(gè)時(shí)間粒度。
類比:就像你把"按天"的數(shù)據(jù)"放大"為"按月"看,或"縮小"為"按小時(shí)"看。
# 創(chuàng)建日粒度數(shù)據(jù)
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=90, freq='D')
df = pd.DataFrame({
'日期': dates,
'銷售額': np.random.randint(1000, 5000, 90),
'訪客數(shù)': np.random.randint(100, 500, 90)
}).set_index('日期')
# ===== 降采樣(高頻 → 低頻)=====
# 按月匯總(求和)
monthly = df.resample('M')['銷售額'].sum()
print("月度銷售額:")
print(monthly)
# 按周求均值
weekly = df.resample('W')['銷售額'].mean()
print("\n周均銷售額:")
print(weekly)
# 按季度
quarterly = df.resample('Q').agg({
'銷售額': 'sum',
'訪客數(shù)': 'mean'
})
print("\n季度匯總:")
print(quarterly)
# ===== 升采樣(低頻 → 高頻)=====
# 創(chuàng)建月度數(shù)據(jù)
monthly_df = pd.DataFrame({
'月度目標(biāo)': [50000, 60000, 55000]
}, index=pd.date_range('2024-01-01', periods=3, freq='MS'))
# 升采樣到日粒度(用 NaN 填充)
daily = monthly_df.resample('D').asfreq()
print("\n升采樣到日粒度(前5行):")
print(daily.head())
# 用前向填充
daily_ffill = monthly_df.resample('D').ffill()
print("\n升采樣 + 前向填充(前5行):")
print(daily_ffill.head())
常用重采樣頻率
| 代碼 | 含義 | 代碼 | 含義 |
|---|---|---|---|
D | 天 | W | 周 |
M | 月末 | MS | 月初 |
Q | 季末 | QS | 季初 |
Y | 年末 | YS | 年初 |
H | 小時(shí) | T/min | 分鐘 |
S | 秒 | B | 工作日 |
自定義聚合
# 按周重采樣,同時(shí)做多種聚合
result = df.resample('W').agg({
'銷售額': ['sum', 'mean', 'max'],
'訪客數(shù)': ['sum', 'mean']
})
result.columns = ['周銷售額', '周均銷售額', '最高日銷售', '周訪客', '日均訪客']
print(result.head())
rolling 滑動(dòng)窗口
rolling 用于滑動(dòng)窗口計(jì)算,比如計(jì)算 7 天移動(dòng)平均線、30 天累計(jì)銷量等。
# 繼續(xù)使用上面的 df
# ===== 基本滑動(dòng)窗口 =====
# 7天移動(dòng)平均
df['7日移動(dòng)平均'] = df['銷售額'].rolling(window=7).mean()
# 30天移動(dòng)平均
df['30日移動(dòng)平均'] = df['銷售額'].rolling(window=30).mean()
print("含移動(dòng)平均:")
print(df.head(15))
# ===== 其他窗口計(jì)算 =====
# 滑動(dòng)窗口求和(7天累計(jì))
df['7天累計(jì)銷售'] = df['銷售額'].rolling(window=7).sum()
# 滑動(dòng)窗口標(biāo)準(zhǔn)差(波動(dòng)率)
df['7日波動(dòng)率'] = df['銷售額'].rolling(window=7).std()
# 滑動(dòng)窗口最大值/最小值
df['7日最高'] = df['銷售額'].rolling(window=7).max()
df['7日最低'] = df['銷售額'].rolling(window=7).min()
# 滑動(dòng)窗口內(nèi)的排名
df['7日排名'] = df['銷售額'].rolling(window=7).apply(
lambda x: pd.Series(x).rank().iloc[-1]
)
print(df.tail(10))
expanding:擴(kuò)展窗口
# expanding 是"越來(lái)越大"的窗口(從開(kāi)始到當(dāng)前位置) # 等價(jià)于 cumsum、cummean 等累計(jì)函數(shù) df['累計(jì)銷售額'] = df['銷售額'].expanding().sum() df['累計(jì)均值'] = df['銷售額'].expanding().mean() df['累計(jì)最大值'] = df['銷售額'].expanding().max() print(df.head(10))
ewm:指數(shù)加權(quán)移動(dòng)平均
# 指數(shù)加權(quán)移動(dòng)平均(最近的數(shù)據(jù)權(quán)重更大)
df['EMA_7'] = df['銷售額'].ewm(span=7).mean()
df['EMA_30'] = df['銷售額'].ewm(span=30).mean()
print("含 EMA:")
print(df[['銷售額', 'EMA_7', 'EMA_30']].head(15))
時(shí)區(qū)處理
# ===== 設(shè)置時(shí)區(qū) =====
dates = pd.date_range('2024-01-01', periods=5, freq='D')
print("無(wú)時(shí)區(qū):")
print(dates)
# 設(shè)置為 UTC
dates_utc = pd.date_range('2024-01-01', periods=5, freq='D', tz='UTC')
print("\nUTC時(shí)區(qū):")
print(dates_utc)
# ===== 時(shí)區(qū)轉(zhuǎn)換 =====
dates_utc = pd.date_range('2024-01-01', periods=5, freq='H', tz='UTC')
dates_shanghai = dates_utc.tz_convert('Asia/Shanghai')
print("\n轉(zhuǎn)為上海時(shí)間:")
print(dates_shanghai)
# ===== 本地化(無(wú)時(shí)區(qū) → 有時(shí)區(qū))=====
dates_naive = pd.date_range('2024-01-01', periods=5, freq='H')
dates_local = dates_naive.tz_localize('Asia/Shanghai')
print("\n本地化:")
print(dates_local)
日期偏移(DateOffset)
# ===== 日期偏移計(jì)算 =====
from pandas.tseries.offsets import Day, Week, MonthEnd, BusinessDay
date = pd.Timestamp('2024-03-15')
# 加 5 天
print(date + Day(5)) # 2024-03-20
# 加 2 周
print(date + Week(2)) # 2024-03-29
# 月末
print(date + MonthEnd(0)) # 2024-03-31(已經(jīng)在3月,所以回到3月末)
print(date + MonthEnd(1)) # 2024-04-30
# 加 3 個(gè)工作日
print(date + BusinessDay(3)) # 2024-03-20(排除周末)
# ===== 在 DataFrame 中使用 =====
df = pd.DataFrame({
'下單日期': pd.date_range('2024-01-01', periods=5)
})
df['預(yù)計(jì)發(fā)貨'] = df['下單日期'] + BusinessDay(2) # 2個(gè)工作日后
df['預(yù)計(jì)送達(dá)'] = df['下單日期'] + BusinessDay(5) # 5個(gè)工作日后
print(df)
實(shí)戰(zhàn)練習(xí)
練習(xí) 1:股票數(shù)據(jù)移動(dòng)平均分析
題目:模擬股票數(shù)據(jù),計(jì)算多種技術(shù)指標(biāo)。
# 參考答案
import pandas as pd
import numpy as np
# 模擬 60 天的股價(jià)數(shù)據(jù)
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=60, freq='B') # 工作日
df = pd.DataFrame({
'日期': dates,
'收盤價(jià)': 100 + np.cumsum(np.random.randn(60) * 2) # 隨機(jī)游走
}).set_index('日期')
# 1. 計(jì)算 5日、10日、20日移動(dòng)平均線
df['MA5'] = df['收盤價(jià)'].rolling(5).mean()
df['MA10'] = df['收盤價(jià)'].rolling(10).mean()
df['MA20'] = df['收盤價(jià)'].rolling(20).mean()
# 2. 計(jì)算日收益率
df['日收益率'] = df['收盤價(jià)'].pct_change() * 100
# 3. 計(jì)算 20日波動(dòng)率(收益率的標(biāo)準(zhǔn)差)
df['20日波動(dòng)率'] = df['日收益率'].rolling(20).std()
# 4. 計(jì)算月度統(tǒng)計(jì)
monthly = df.resample('M')['收盤價(jià)'].agg(['first', 'last', 'max', 'min'])
monthly['月漲跌'] = (monthly['last'] - monthly['first']) / monthly['first'] * 100
print("月度統(tǒng)計(jì):")
print(monthly.round(2))
print("\n技術(shù)指標(biāo)(后10行):")
print(df.tail(10))
練習(xí) 2:網(wǎng)站流量時(shí)間分析
題目:分析網(wǎng)站的小時(shí)級(jí)流量數(shù)據(jù)。
# 參考答案
import pandas as pd
import numpy as np
# 模擬 7 天的小時(shí)級(jí)流量
np.random.seed(42)
hours = pd.date_range('2024-03-01', periods=7*24, freq='H')
df = pd.DataFrame({
'時(shí)間': hours,
'訪客數(shù)': np.random.poisson(lam=100, size=len(hours))
}).set_index('時(shí)間')
# 模擬高峰期(9-18點(diǎn))
df.loc[df.index.hour.between(9, 18), '訪客數(shù)'] *= 2
# 1. 每日總訪客
daily = df.resample('D')['訪客數(shù)'].sum()
print("每日訪客:")
print(daily)
# 2. 每小時(shí)平均訪客(找出高峰時(shí)段)
df['小時(shí)'] = df.index.hour
hourly_avg = df.groupby('小時(shí)')['訪客數(shù)'].mean()
print("\n每小時(shí)平均訪客:")
print(hourly_avg.round(1))
# 3. 24小時(shí)移動(dòng)平均
df['MA24'] = df['訪客數(shù)'].rolling(24).mean()
# 4. 工作日與周末對(duì)比
df['類型'] = np.where(df.index.dayofweek < 5, '工作日', '周末')
weekday_avg = df.groupby('類型')['訪客數(shù)'].mean()
print("\n工作日vs周末平均:")
print(weekday_avg.round(1))
本節(jié)總結(jié)
本節(jié)我們學(xué)習(xí)了 Pandas 強(qiáng)大的時(shí)間序列處理能力:
日期處理:
pd.to_datetime()—— 字符串轉(zhuǎn)日期.dt訪問(wèn)器 —— 提取年、月、日、季度等屬性pd.date_range()—— 生成日期序列
重采樣(resample):
- 降采樣:高頻 → 低頻(日 → 月)
- 升采樣:低頻 → 高頻(月 → 日)
- 配合聚合函數(shù):
resample('M').sum()
滑動(dòng)窗口(rolling):
rolling(window=N).mean()—— 移動(dòng)平均expanding()—— 累計(jì)窗口ewm(span=N)—— 指數(shù)加權(quán)移動(dòng)平均
時(shí)區(qū)與偏移:
tz_localize/tz_convert處理時(shí)區(qū)DateOffset進(jìn)行日期偏移計(jì)算
以上就是Pandas中時(shí)間序列分析的核心功能和實(shí)戰(zhàn)指南的詳細(xì)內(nèi)容,更多關(guān)于Pandas時(shí)間序列分析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用Python開(kāi)發(fā)一個(gè)簡(jiǎn)單的本地圖片服務(wù)器
本文介紹了如何結(jié)合wxPython構(gòu)建的圖形用戶界面GUI和Python內(nèi)建的 Web服務(wù)器功能,在本地網(wǎng)絡(luò)中搭建一個(gè)私人的,即開(kāi)即用的網(wǎng)頁(yè)相冊(cè),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2025-04-04
Python3與fastdfs分布式文件系統(tǒng)如何實(shí)現(xiàn)交互
這篇文章主要介紹了Python3與fastdfs分布式文件系統(tǒng)如何實(shí)現(xiàn)交互,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
python 利用 PIL 將數(shù)組值轉(zhuǎn)成圖片的實(shí)現(xiàn)
這篇文章主要介紹了python 利用 PIL 將數(shù)組值轉(zhuǎn)成圖片的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
Python數(shù)據(jù)分析與處理(二)——處理中國(guó)地區(qū)信息
這篇文章主要介紹了Python數(shù)據(jù)分析與處理-處理中國(guó)地區(qū)信息,上文介紹了北京高考分?jǐn)?shù)線統(tǒng)計(jì)分析,這篇文章依然圍繞Python數(shù)據(jù)分析與處理的相關(guān)資料來(lái)介紹處理中國(guó)地區(qū)信息,需要的朋友可以參考一下2021-12-12
Python設(shè)置和解除Word文檔保護(hù)的實(shí)現(xiàn)步驟
在日常工作和學(xué)習(xí)中,我們經(jīng)常需要使用Word文檔來(lái)記錄和分享重要的信息,為了確保文檔內(nèi)容的安全性和完整性,了解如何保護(hù)和取消保護(hù)Word文檔顯得尤為重要,這篇博客將詳細(xì)介紹如何使用Python設(shè)置和解除Word文檔的保護(hù),需要的朋友可以參考下2025-02-02
python muggle_ocr庫(kù)用法及實(shí)例代碼
在本篇文章里小編給大家整理的是一篇關(guān)于python muggle_ocr庫(kù)用法及實(shí)例代碼內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)參考下。2021-07-07
Python中如何使用pypandoc進(jìn)行格式轉(zhuǎn)換操作
這篇文章主要介紹了Python中如何使用pypandoc進(jìn)行格式轉(zhuǎn)換操作,pypandoc是一個(gè)強(qiáng)大的文檔轉(zhuǎn)換工具,它可以將各種標(biāo)記語(yǔ)言轉(zhuǎn)換為不同的格式,支持多種輸入和輸出格式,并允許用戶添加自定義樣式、模板和過(guò)濾器2021-06-06
Python實(shí)現(xiàn)線程池之線程安全隊(duì)列
這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)線程池之線程安全隊(duì)列,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05

