返回文章列表

Zscore標準化與Pandas時間序列處理技巧

本文探討如何使用 Z-score 標準化方法提升資料比較準確性,並深入解析 Pandas 處理時間序列資料的技巧,包含時區處理、日期偏移操作、重取樣技術以及自定義工作日設定等,有效解決時間序列資料分析中的常見挑戰。

資料科學 Python

在資料分析領域,比較不同群體或時間段的資料時,直接比較原始資料往往難以真實反映資料差異。Z-score 標準化提供一種有效方法,將資料轉換為具有相同均值和標準差的分佈,方便進行比較。Pandas 提供簡潔的 API,方便實作 Z-score 標準化,例如使用 groupbytransform 方法即可對分組資料進行標準化處理。此外,時間序列資料處理是資料分析中另一個重要議題,Pandas 提供了完善的工具來應對時間資料的各種挑戰,包括時區處理、日期偏移、重取樣和自定義工作日等。理解和運用這些技巧,能更有效地分析和利用時間序列資料。

使用Z-score標準化提升資料比較的準確性

在資料分析中,特別是在比較不同群體或不同時間段的資料時,直接比較原始資料可能無法準確反映真實情況。這時,資料標準化就顯得尤為重要。Z-score標準化是一種常見的標準化方法,可以幫助我們更好地理解和比較資料。

Z-score標準化的數學表示

Z-score標準化的公式如下:

$z = \frac{x - \mu}{\sigma}$

其中,$\mu$是資料的平均值,$\sigma$是資料的標準差。

在Pandas中實作Z-score標準化

在Pandas中,我們可以輕鬆地實作Z-score標準化。首先,定義一個自定義的標準化函式:

def normalize(ser: pd.Series) -> pd.Series:
    return (ser - ser.mean()) / ser.std()

然後,將這個函式應用於分組資料,以計算每個群組內的標準化值:

averages.assign(
    normalized_avg=averages.groupby("year").transform(normalize)
)

實際應用:比較不同年份的棒球選手打擊率

透過使用Z-score標準化,我們可以更公平地比較不同年份棒球選手的打擊率。以下是一個例子:

(
    averages.assign(
        normalized_avg=averages.groupby("year").transform(normalize)
    )
    .groupby("year").agg(
        league_mean_avg=pd.NamedAgg(column="avg", aggfunc="mean"),
        league_max_avg=pd.NamedAgg(column="avg", aggfunc="max"),
        batting_champion=pd.NamedAgg(column="avg", aggfunc="idxmax"),
        max_normalized_avg=pd.NamedAgg(column="normalized_avg", aggfunc="max"),
    )
    .sort_values(by="max_normalized_avg", ascending=False)
).head()

結果顯示,2023年Luis Arráez的打擊率表現是最令人印象深刻的,即使他的絕對打擊率不是最高的。

時間資料型別和演算法

處理時間資料看似簡單,但實際上卻充滿了挑戰。不同的使用者對時間的測量單位不同,有些需要處理時區問題,有些則不需要。此外,不同的國家和地區對夏令時的處理也不同。

Pandas中的時間資料處理

幸運的是,Pandas提供了豐富的功能來幫助我們處理時間資料。從建立時間序列到進行時間序列的重取樣和聚合,Pandas都提供了簡潔而強大的API。

時區處理

時區問題是時間資料處理中的一個常見挑戰。在Pandas中,我們可以輕鬆地建立和轉換時區感知(timezone-aware)的時間資料。

建立時區感知的時間序列

ser = pd.Series([
    "2024-01-01 00:00:00",
    "2024-01-02 00:00:01",
    "2024-01-03 00:00:02"
], dtype="datetime64[ns]")

圖表翻譯:

此圖表顯示了建立時區感知時間序列的基本步驟。首先,我們需要建立一個包含日期時間字串的Series。然後,透過指定dtype為"datetime64[ns]",Pandas會自動將這些字串轉換為datetime64型別,從而建立一個時區感知的時間序列。

時區感知與日期偏移處理

在處理時間序列資料時,時區資訊的正確處理至關重要。pandas 提供了豐富的功能來管理時區感知(timezone-aware)的 datetime 物件。

時區天真與時區感知 datetime 物件

預設情況下,pandas 的 datetime 物件是時區天真(timezone-naive)的,這意味著它們不包含任何時區資訊。例如:

ser = pd.Series([
    "2024-01-01 00:00:00",
    "2024-01-02 00:00:01",
    "2024-01-03 00:00:02",
], dtype="datetime64[ns]")

內容解密:

此範例建立了一個包含三個 datetime 物件的 Series,預設為時區天真。

要檢查一個 Series 是否為時區天真,可以使用 dt.tz 屬性:

ser.dt.tz is None  # 輸出:True

內容解密:

dt.tz 屬性用於檢查 Series 中的 datetime 物件是否具有時區資訊。若傳回 None,則表示該 Series 為時區天真。

設定時區資訊

使用 dt.tz_localize 方法可以為時區天真的 datetime 物件設定時區:

ny_ser = ser.dt.tz_localize("America/New_York")

內容解密:

此操作將 Series 中的 datetime 物件轉換為時區感知,並設定時區為 “America/New_York”。此時,datetime 物件會根據指定的時區進行調整。

檢查設定後的時區:

ny_ser.dt.tz  # 輸出:<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>

內容解密:

dt.tz 現在傳回指定的時區資訊,確認 datetime 物件已變為時區感知。

時區轉換

使用 dt.tz_convert 方法,可以將時區感知的 datetime 物件轉換到其他時區:

la_ser = ny_ser.dt.tz_convert("America/Los_Angeles")

內容解密:

此操作將原本在 “America/New_York” 時區的 datetime 物件轉換到 “America/Los_Angeles” 時區。時間會根據兩個時區之間的差異進行調整。

輸出結果如下:

0   2023-12-31 21:00:00-08:00
1   2024-01-01 21:00:01-08:00
2   2024-01-02 21:00:02-08:00
dtype: datetime64[ns, America/Los_Angeles]

內容解密:

轉換後的 datetime 物件現在處於 “America/Los_Angeles” 時區,並且時間已根據時差進行了調整。

移除時區資訊

在某些情況下,可能需要移除時區資訊以便於資料交換或儲存。使用 dt.tz_localize(None) 可以實作這一點:

la_ser.dt.tz_localize(None)

內容解密:

此操作會移除 datetime 物件的時區資訊,使其再次變為時區天真。

輸出結果如下:

0   2023-12-31 21:00:00
1   2024-01-01 21:00:01
2   2024-01-02 21:00:02
dtype: datetime64[ns]

內容解密:

移除時區資訊後,datetime 物件不再包含任何時區相關的資料。

日期偏移處理

在處理日期時,經常需要對日期進行偏移,例如增加或減少特定的時間間隔。pandas 提供了 pd.DateOffset 物件來實作這一功能。

基本使用

首先,建立一個簡單的日期 Series:

ser = pd.Series([
    "2024-01-01",
    "2024-01-02",
    "2024-01-03",
], dtype="datetime64[ns]")

內容解密:

此範例建立了一個包含三個日期的 Series,用於示範日期偏移操作。

使用 pd.DateOffset 可以對日期進行偏移,例如增加一個月:

ser + pd.DateOffset(months=1)

內容解密:

此操作將 Series 中的日期都增加一個月,即從一月變為二月。

輸出結果如下:

0   2024-02-01
1   2024-02-02
2   2024-02-03
dtype: datetime64[ns]

內容解密:

日期已成功偏移到二月份,並且保持了原有的日份。

處理不存在的日期

當偏移日期導致不存在的日期時(例如,將1月30日偏移到2月),pd.DateOffset 會自動調整到最近的有效日期:

pd.Series(["2024-01-30"], dtype="datetime64[ns]") + pd.DateOffset(months=1)

內容解密:

由於2月沒有30日,因此日期會被調整到2月的最後一天,即2月29日(閏年)。

輸出結果如下:

0   2024-02-29
dtype: datetime64[ns]

內容解密:

對於不存在的日期,pd.DateOffset 自動調整到有效的日期。

多重偏移引數

pd.DateOffset 可以接受多個引數,用於同時進行多種時間單位的偏移:

ser + pd.DateOffset(months=1, days=2, hours=3, minutes=4, seconds=5)

內容解密:

此操作同時對日期進行多種單位的偏移,包括月份、天數、小時、分鐘和秒數。

輸出結果如下:

0   2024-02-03 03:04:05
1   2024-02-04 03:04:05
2   2024-02-05 03:04:05
dtype: datetime64[ns]

內容解密:

多重偏移引數使得複雜的時間調整變得簡單直接。

使用 pd.offsets 模組

除了 pd.DateOffset,pandas 的 pd.offsets 模組提供了更多功能,例如將日期調整到特定週期的開始或結束。

例如,使用 pd.offsets.MonthEnd 將日期調整到月底:

ser + pd.offsets.MonthEnd()

內容解密:

此操作將日期調整到各自所在月份的最後一天。

輸出結果如下:

0   2024-01-31
1   2024-01-31
2   2024-01-31
dtype: datetime64[ns]

內容解密:

所有日期都被調整到一月的最後一天,即1月31日。

使用Pandas處理時間序列資料

Pandas是一個強大的Python函式庫,用於資料操作和分析。在處理時間序列資料時,Pandas提供了豐富的功能和工具,使得日期和時間的處理變得簡單高效。

日期偏移

在處理時間序列資料時,經常需要對日期進行偏移操作,例如將日期移動到下個月的第一天或最後一天。Pandas提供了多種日期偏移類別,如pd.offsets.MonthBeginpd.offsets.MonthEnd等,可以用來實作這些操作。

import pandas as pd

# 建立一個包含日期的Series
ser = pd.Series(pd.date_range(start="2024-01-29", periods=3))

# 將日期移動到下個月的第一天
ser + pd.offsets.MonthBegin()

內容解密:

  • pd.date_range用於生成一個日期範圍。
  • pd.offsets.MonthBegin將日期移動到下個月的第一天。

自定義工作日

在某些情況下,需要根據自定義的工作日進行日期偏移。Pandas提供了pd.offsets.CustomBusinessDay類別,可以用來定義自定義的工作日。

# 定義自定義工作日
ser + pd.offsets.CustomBusinessDay(n=3, weekmask="Mon Tue Wed Thu")

內容解密:

  • weekmask引數用於指定一週中的哪些天是工作日。
  • n引數指定偏移的天數。

日期選擇

當使用日期作為索引時,Pandas提供了方便的日期選擇功能。可以使用pd.date_range生成一個日期範圍作為索引,然後使用.loc進行日期選擇。

# 生成一個日期範圍作為索引
index = pd.date_range(start="2023-12-27", freq="10D", periods=20)
ser = pd.Series(range(20), index=index)

# 選擇特定日期範圍內的資料
ser.loc["2024-01-06":"2024-01-18"]

內容解密:

  • pd.date_range生成一個日期範圍。
  • .loc用於根據索引選擇資料。

日期偏移字串

Pandas支援多種日期偏移字串,如"WOM-3THU"表示每月的第三個星期四。這些字串可以用於生成特定的日期序列。

# 生成每月的第三個星期四的日期序列
pd.date_range(start="2023-12-27", freq="WOM-3THU", periods=5)

內容解密:

  • freq引數指定日期偏移的頻率。
  • “WOM-3THU"表示每月的第三個星期四。

時間序列資料處理與重取樣技術

在處理時間序列資料時,Pandas 提供了強大的工具來進行資料選擇、重取樣和分析。本文將探討如何使用 Pandas 進行時間序列資料處理,特別是在資料選擇和重取樣方面的應用。

時間序列資料選擇

Pandas 的 DatetimeIndex 允許我們輕鬆地根據日期和時間選擇資料。例如,我們可以建立一個包含日期索引的 Series:

import pandas as pd

index = pd.date_range(start="2024-01-01", periods=10, freq="D")
ser = pd.Series(range(10), index=index, dtype=pd.Int64Dtype())
print(ser)

輸出:

2024-01-01    0
2024-01-02    1
2024-01-03    2
2024-01-04    3
2024-01-05    4
2024-01-06    5
2024-01-07    6
2024-01-08    7
2024-01-09    8
2024-01-10    9
Freq: D, dtype: Int64

內容解密:

這段程式碼建立了一個日期索引的 Series,從 2024 年 1 月 1 日開始,共 10 天。pd.date_range 用於生成日期範圍,freq="D" 表示每天一個資料點。

我們可以輕鬆地根據日期範圍選擇資料:

print(ser.loc["2024-01-03":"2024-01-06"])

輸出:

2024-01-03    2
2024-01-04    3
2024-01-05    4
2024-01-06    5
Freq: D, dtype: Int64

內容解密:

這段程式碼選擇了從 2024 年 1 月 3 日到 1 月 6 日的資料。ser.loc 用於根據索引標籤選擇資料。

時區感知與選擇

Pandas 也支援時區感知的 DatetimeIndex。我們可以建立一個具有時區的日期索引:

index = pd.date_range(start="2023-12-27", freq="12h", periods=6, tz="US/Eastern")
ser = pd.Series(range(6), index=index)
print(ser)

輸出:

2023-12-27 00:00:00-05:00    0
2023-12-27 12:00:00-05:00    1
2023-12-28 00:00:00-05:00    2
2023-12-28 12:00:00-05:00    3
2023-12-29 00:00:00-05:00    4
2023-12-29 12:00:00-05:00    5
Freq: 12h, dtype: int64

內容解密:

這段程式碼建立了一個具有時區(US/Eastern)的日期索引,每隔 12 小時一個資料點。tz="US/Eastern" 指定了時區。

在選擇時區感知的資料時,Pandas 將自動轉換字串引數到指定的時區:

print(ser.loc[:"2023-12-27 11:59:59"])

輸出:

2023-12-27 00:00:00-05:00    0
Freq: 12h, dtype: int64

內容解密:

這段程式碼選擇了截至 2023 年 12 月 27 日 11:59:59 的資料。Pandas 自動將字串轉換為指定的時區。

重取樣技術

重取樣是將時間序列資料從一個頻率轉換到另一個頻率的過程。Pandas 的 resample 方法允許我們輕鬆地進行重取樣:

index = pd.date_range(start="2024-01-01", periods=10, freq="s")
ser = pd.Series(range(10), index=index, dtype=pd.Int64Dtype())
print(ser.resample("3s").sum())

輸出:

2024-01-01 00:00:00    3
2024-01-01 00:00:03   12
2024-01-01 00:00:06   21
2024-01-01 00:00:09    9
Freq: 3s, dtype: Int64

內容解密:

這段程式碼將原始的每秒資料重取樣為每 3 秒的資料,並計算每個區間的總和。resample("3s") 指定了重取樣的頻率,sum() 指定了聚合函式。

重取樣引數調整

我們可以透過調整 closedlabel 引數來控制重取樣的行為:

print(ser.resample("3s", closed="right", label="right").sum())

輸出:

2024-01-01 00:00:03    6
2024-01-01 00:00:06   15
2024-01-01 00:00:09   24
Freq: 3s, dtype: Int64

內容解密:

這段程式碼將 closed 設定為 "right",表示區間右閉合;將 label 設定為 "right",表示使用區間的右端點作為標籤。