第 2 篇:初探時間序列 - 可視化與基本概念
(圖片來源: Luke Chesser on Unsplash)
在上一篇《你好,時間序列!》中,我們了解了什么是時間序列數據以及學習它的重要性。現在,是時候卷起袖子,真正開始接觸和探索這些按時間流動的數據了!
本篇我們將聚焦于:
- 如何使用 Python 加載和處理時間序列數據? (基礎操作)
- 如何通過可視化讓時間序列“說話”? (核心技能)
- 時間序列通常由哪些基本“成分”構成? (核心概念)
準備好你的 Python 環境 (Pandas, Matplotlib/Seaborn),讓我們開始吧!
數據加載與基礎操作:Pandas 的魔法
處理時間序列數據,Pandas 庫是我們的得力助手。它提供了強大的 Timestamp
和 DatetimeIndex
對象,專門用于處理時間信息。
假設我們有一個 CSV 文件 my_time_series.csv
,內容如下:
Date,Value
2023-01-01,10
2023-01-02,12
2023-01-03,15
2023-01-04,13
2023-01-05,16
...
我們可以這樣加載它,并確保日期列被正確識別為時間索引:
import pandas as pd# 加載數據
# parse_dates=['Date'] 告訴 Pandas 'Date' 列包含日期信息
# index_col='Date' 將 'Date' 列設置為 DataFrame 的索引
try:# 假設文件在當前目錄下df = pd.read_csv('my_time_series.csv', parse_dates=['Date'], index_col='Date')print("數據加載成功!")
except FileNotFoundError:print("錯誤:找不到 my_time_series.csv 文件。請確保文件路徑正確。")# 為了演示,我們創建一個簡單的示例 DataFrameprint("將創建一個示例 DataFrame 繼續演示...")dates = pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04', '2023-01-05'])values = [10, 12, 15, 13, 16]df = pd.DataFrame({'Value': values}, index=dates)# 查看數據前幾行和索引類型
print("\n數據概覽:")
print(df.head())
print("\n索引類型:")
print(type(df.index))
關鍵點:
parse_dates=['列名']
:讓 Pandas 嘗試將指定列解析為日期時間格式。index_col='列名'
:將解析后的日期時間列設置為 DataFrame 的索引。這會創建一個DatetimeIndex
。
為什么 DatetimeIndex
很重要?
擁有 DatetimeIndex
后,我們可以方便地進行基于時間的各種操作,例如:
- 按時間范圍選擇數據 (Slicing):
# 選擇 2023 年 1 月的數據
print("\n選擇 2023 年 1 月數據:")
try:print(df['2023-01'])
except KeyError:print("示例數據中沒有完整的 1 月數據,此為切片示例。")print(df['2023-01-01':'2023-01-03']) # 選擇特定日期范圍# 選擇特定日期
print("\n選擇 2023 年 1 月 2 日的數據:")
print(df.loc['2023-01-02'])
- 重采樣 (Resampling): 改變時間序列的頻率(例如,從日數據變為月度平均數據)。我們后面會更詳細地接觸。
# 簡單示例:計算月度平均值 (如果數據足夠多)
# 'M' 表示 月末 (Month End)
# .mean() 計算平均值
try:monthly_mean = df.resample('M').mean()print("\n月度平均值 (如果數據覆蓋多月):")print(monthly_mean)
except Exception as e:print(f"\n計算月度平均值出錯 (可能是數據量太少): {e}")
可視化:讓數據“說話”
時間序列最直觀的探索方式就是畫圖!折線圖 (Line Plot) 是我們的首選,它能清晰地展示數據點如何隨著時間變化。
我們將使用 Matplotlib 或 Seaborn (通常基于 Matplotlib 提供更美觀的圖形) 來繪圖。
import matplotlib.pyplot as plt
import seaborn as sns# 設置繪圖風格 (可選)
sns.set_style("whitegrid")# 創建圖形
plt.figure(figsize=(12, 6)) # 設置圖形大小# 繪制折線圖
plt.plot(df.index, df['Value'], marker='o', linestyle='-')
# 或者使用 Seaborn
# sns.lineplot(data=df, x=df.index, y='Value', marker='o')# 添加標題和標簽
plt.title('My Time Series Data Over Time')
plt.xlabel('Date')
plt.ylabel('Value')# 優化日期顯示 (可選)
plt.xticks(rotation=45)
plt.tight_layout() # 調整布局防止標簽重疊# 顯示圖形
plt.show()
(請運行上面的代碼,生成的圖就是這里應該展示的內容。一個簡單的折線圖,X 軸是時間,Y 軸是數值。)
如何解讀圖形?
盯著這張圖,試著回答以下問題:
- 整體趨勢 (Trend): 數據是長期來看是上升的?下降的?還是保持水平?(看大方向)
- 周期性模式 (Seasonality/Cycles): 是否存在固定時間間隔內(比如每年、每周、每天)反復出現的模式?(看重復的波峰波谷)
- 異常點 (Outliers): 是否有某個或某幾個點顯得特別“突兀”,遠離整體模式?
- 波動性 (Volatility): 數據變化的幅度是大致恒定的,還是時大時小?
通過可視化,我們就能對時間序列的特性有一個初步的、直觀的認識。
時間序列的基本成分 (概念引入)
剛才我們在解讀圖形時提到了“趨勢”、“周期性模式”等,這些其實就是時間序列數據通常包含的基本成分。理解這些成分對于后續分析和建模至關重要。
一個時間序列 Y(t)
通常被認為可以分解為以下幾個(并非所有序列都包含全部)主要部分:
-
趨勢 (Trend, T(t)):
- 描述數據在長期內的主要走向或基本趨勢。
- 可以是上升的(如經濟增長)、下降的(如某種技術被淘汰)或水平的。
- 想象成一條貫穿數據中心的平滑曲線。
-
季節性 (Seasonality, S(t)):
- 指數據在一個固定且已知的時間周期內(如一年、一季度、一周、一天)表現出的、可預測的模式性波動。
- 例如:冰淇淋銷量夏季高、冬季低(周期為年);工作日通勤交通量早晚高峰(周期為天)。
- 關鍵: 周期長度是固定的。
-
周期性 (Cyclicality, C(t)):
- 指數據在非固定長度的時期內出現的長期波動,通常與經濟周期等宏觀因素相關。
- 周期長度通常比季節性長(比如幾年甚至幾十年),且沒有固定的時間間隔。
- 注意: 這個成分對于初學者來說比較難識別和處理,我們初期會更多關注趨勢和季節性。
-
隨機性 / 噪聲 / 殘差 (Noise / Irregular / Residual, R(t)):
- 剔除掉趨勢、季節性和周期性成分后,數據中剩余的、不規則的、通常是隨機的波動。
- 可以看作是模型無法解釋的部分。
(這張圖展示了一個序列 (Data) 被分解為趨勢 (Trend)、季節性 (Seasonal) 和殘差 (Remainder/Residual) 的經典示例)
我們目前只需要理解這些概念即可,下一篇我們將學習如何使用工具實際地將一個時間序列分解開來。
小結與代碼示例回顧
今天我們:
- 學會了使用
pandas
加載時間序列數據,并理解了parse_dates
和index_col
的重要性,創建了DatetimeIndex
。 - 掌握了使用
matplotlib
或seaborn
繪制時間序列折線圖這一核心可視化技能。 - 學習了如何從圖中初步觀察趨勢和季節性等模式。
- 理解了時間序列通常包含的趨勢 (T)、季節性 (S)、周期性 ? 和隨機性 ? 四個基本成分(概念層面)。
完整代碼示例:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns# 1. 生成示例數據 (包含趨勢和季節性)
np.random.seed(42) # for reproducibility
dates = pd.date_range(start='2022-01-01', periods=365 * 2, freq='D') # 2 年的日數據
trend = np.linspace(0, 10, len(dates)) # 線性上升趨勢
seasonality = 5 * np.sin(2 * np.pi * dates.dayofyear / 365.25) # 年度季節性
noise = np.random.normal(0, 1, len(dates)) # 隨機噪聲
values = trend + seasonality + noise + 20 # 基線值為 20# 創建 DataFrame
df_generated = pd.DataFrame({'Value': values}, index=dates)print("生成的示例數據概覽:")
print(df_generated.head())
print("\n索引類型:")
print(type(df_generated.index))# 2. 可視化
sns.set_style("whitegrid")
plt.figure(figsize=(14, 7))# 繪制折線圖
sns.lineplot(data=df_generated, x=df_generated.index, y='Value')# 添加標題和標簽
plt.title('Generated Time Series with Trend and Seasonality')
plt.xlabel('Date')
plt.ylabel('Value')# 優化日期顯示
plt.xticks(rotation=30)
plt.tight_layout()# 顯示圖形
plt.show()# 3. 初步解讀
print("\n觀察上圖:")
print("- 整體看,數據是不是有一個向上的大方向?(趨勢)")
print("- 數據是不是每年都在重復相似的上下波動模式?(季節性)")
通過觀察生成的圖,你應該能比較清晰地看到我們定義的“趨勢”(整體向上)和“季節性”(每年重復的波浪形)。
下一篇預告
現在我們對時間序列有了直觀感受,也知道了它可能包含哪些成分。那么,如何更精確地把這些成分分離出來呢?下一篇,我們將深入探討時間序列分解 (Time Series Decomposition) 技術,學習如何量化地識別和提取趨勢與季節性。
敬請期待!