Pandas 提供了強大的群組分析和時間序列處理功能,能有效地分析和理解資料。群組分析允許根據特定條件分組資料,並對每個群組進行聚合計算,例如計算每年的聯盟均值、最高打擊平均數等。時間序列處理則涵蓋了日期偏移、時區處理等方面,能更準確地操作時間資料,避免因時區差異導致的錯誤。理解和運用這些功能,能提升資料分析效率和準確性。

import pandas as pd

# 群組分析範例
def normalize(ser: pd.Series) -> pd.Series:
    return (ser - ser.mean()) / ser.std()

# averages = pd.DataFrame({'year': [2022, 2022, 2023, 2023], 'avg': [0.3, 0.4, 0.35, 0.45]})
# averages['normalized_avg'] = averages.groupby("year").transform(normalize)

# result = (
#     averages.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()

# 時間序列處理範例
ser = pd.Series(pd.to_datetime(['2024-01-31', '2024-01-31', '2024-01-31']))
ser + pd.offsets.MonthBegin()

ser = pd.Series(pd.to_datetime(['2024-01-01', '2024-01-02', '2024-01-03']))
bd_ser = ser + pd.offsets.BusinessDay(n=3)

ser + pd.offsets.CustomBusinessDay(n=3, weekmask="Mon Tue Wed Thu")
ser + pd.offsets.CustomBusinessDay(n=3, weekmask="Mon Tue Wed Thu", holidays=["2024-01-04"])

ser = pd.Series(pd.to_datetime(['2024-01-31', '2024-01-31', '2024-01-31']))
ser + pd.offsets.MonthEnd()

pd.date_range(start="2023-12-27", freq="10D", periods=5)
pd.date_range(start="2023-12-31", freq="2W-SUN", periods=5)

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

ser.dt.tz is None
ny_ser = ser.dt.tz_localize("America/New_York")
la_ser = ny_ser.dt.tz_convert("America/Los_Angeles")
la_ser_dropped = la_ser.dt.tz_localize(None)

df = la_ser.to_frame().assign(
    datetime=la_ser_dropped,
    timezone=str(la_ser.dt.tz),
).drop(columns=[0])

使用 Pandas 的群組分析功能

在進行資料分析時,群組分析(Group By)是一個非常強大且常用的功能。它允許我們根據特定的條件對資料進行分組,然後對每個群組進行聚合計算。這在處理多維度資料時非常有用,特別是在比較不同群組之間的表現時。

如何進行群組分析

假設我們有一個包含棒球選手打擊平均數的資料集,我們想要比較每年不同球員的打擊表現。這裡我們可以使用 Z-score 正規化來標準化每年每位球員的打擊平均數,這樣可以更公平地比較不同年份的表現。

Z-score 正規化

Z-score 是一種常見的正規化方法,它將資料轉換為標準差單位。其公式如下:

[ z = \frac{x - \mu}{\sigma} ]

其中,(\mu) 是均值,(\sigma) 是標準差。

在 Pandas 中實作 Z-score 正規化

在 Pandas 中實作 Z-score 正規化非常簡單。我們只需定義一個自訂的正規化函式,然後將其作為引數傳遞給 pd.core.groupby.DataFrameGroupBy.transform 函式即可。

以下是具體的實作步驟:

import pandas as pd

# 假設 averages 是一個包含打擊平均數的 DataFrame
# averages = pd.read_csv('batting_averages.csv')

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

# 對每年的打擊平均數進行正規化
averages['normalized_avg'] = averages.groupby("year").transform(normalize)

# 進一步進行群組聚合
result = (
    averages.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()

print(result)

內容解密:

  1. 定義正規化函式normalize 函式接受一個 pd.Series 作為輸入,並傳回該序列經過 Z-score 正規化後的結果。
  2. 應用正規化:使用 groupbytransform 函式對每年的打擊平均數進行正規化。
  3. 進一步聚合:對正規化後的結果進行進一步的群組聚合,計算每年的聯盟均值、最高打擊平均數、最高正規化值等。
  4. 排序和顯示:根據最高正規化值對結果進行排序,並顯示前五名。

這樣我們就可以更公平地比較不同年份的球員表現了。例如,從結果中我們可以看到,2023 年 Luis Arráez 的表現在所有年份中是最突出的。

應用場景

這種方法不僅適用於棒球選手的打擊平均數分析,還可以應用於其他多維度資料的分析。例如:

  • 評估不同年齡段使用者的行為。
  • 比較不同產品線產品的銷售表現。
  • 分析不同行業股票的漲跌情況。

總之,Pandas 的群組分析功能為我們提供了強大的工具來探索和理解多維度資料。

時間型別及演算法

處理時間型別(例如日期和時間)看似簡單,但在深入瞭解後會發現其實相當複雜。以下是一些常見的問題:

  • 一些使用者以年為單位測量時間,而另一些則以納秒為單位。
  • 一些使用者忽略時區,而另一些則需要協調全球事件。
  • 不同國家有不同的時區和夏令時間政策。

這些問題只是冰山一角,但時間型別資料對於監控、趨勢檢測和預測非常重要。幸運的是,Pandas 提供了豐富的功能來幫助我們處理時間型別資料。

時間處理中的常見問題

  1. 時區處理:這是處理時間型別資料中最常見的錯誤之一。例如,東岸美國的一些分析師可能會讀取到錯誤的日期。
  2. 時間偏移:不同作業系統和版本可能會以不同方式記錄時間。
  3. 夏令時間:不同國家和地區對夏令時間有不同的政策。

這些問題使得時間型別資料處理變得複雜,但 Pandas 提供了強大的工具來幫助我們解決這些問題。

時間型別處理方法

時區處理

首先,我們需要理解何時使用時區感知(timezone-aware)和何時使用無時區資訊(timezone-naive)日期。以下是如何建立和識別這兩種型別日期的範例:

import pandas as pd

# 建立一個包含日期和時間資訊的 Series
ser = pd.Series([
    "2024-01-01 00:00:00",
    "2024-01-02 00:00:01",
    "2024-01-03 00:00:02"
], dtype="datetime64[ns]")

print(ser)

內容解密:

  1. 建立 Series:使用 pd.Series 建立一個包含日期和時間資訊的 Series。
  2. 顯示結果:顯示建立好的 Series。

語言與文化適應

玄貓會確保技術術語精準且完整保留原意,並且不會簡化或誤導。例如,「夏令時間」在台灣稱為「日光節約時間」。此外,玄貓也會避免使用中國大陸慣用語,完全採用台灣本地科技社群繁體中文用語。

時區感知的時間處理

在資料科學和資料分析中,時間處理是一個非常重要的環節。時區感知的時間處理能夠幫助我們更準確地理解和操作時間資料,避免因為時區差異而導致的錯誤。以下是玄貓對於這方面的一些見解和實作範例。

時間資料的基本概念

時間資料通常以 datetime 格式呈現,這些資料可能是時區不感知的(timezone-naive)或時區感知的(timezone-aware)。時區不感知的時間資料並不包含時區資訊,因此無法精確地表示事件發生的具體時刻。例如,以下這段程式碼建立了一個時間序列:

import pandas as pd

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

print(ser)

這些時間資料看似表示了某些事件在特定時刻發生,但由於缺乏時區資訊,我們無法確定這些事件究竟是在紐約還是杜拜發生的。

內容解密:

  1. 建立時間序列:使用 pd.Series 建立一個包含特定時間戳的序列。
  2. 時間戳表示:這些時間戳表示的是某些事件在特定時刻發生,但缺乏時區資訊。

檢查時間資料是否時區感知

我們可以使用 pd.Series.dt.tz 來檢查時間資料是否包含時區資訊。如果傳回 None,則表示這些時間資料是時區不感知的:

print(ser.dt.tz is None)

這段程式碼會輸出 True,表明這些時間資料是時區不感知的。

內容解密:

  1. 檢查時區資訊:使用 pd.Series.dt.tz 來檢查時間資料是否包含時區資訊。
  2. 輸出結果:如果傳回 None,則表示這些時間資料是時區不感知的。

將時間資料轉換為時區感知

我們可以使用 pd.Series.dt.tz_localize 方法將時間資料轉換為時區感知的格式。例如,如果我們知道這些事件發生在紐約,可以這樣做:

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

這樣做後,我們就可以確定這些事件發生在紐約當地時間。現在,ny_ser 的每個元素都包含了具體的時區資訊。

內容解密:

  1. 指定時區:使用 pd.Series.dt.tz_localize 方法將時間資料轉換為特定時區感知的格式。
  2. 輸出結果:轉換後的每個元素都包含了具體的時區資訊。

轉換到其他時區

現在我們已經有了一個包含具體時區資訊的時間序列,我們可以使用 pd.Series.dt.tz_convert 方法將其轉換到其他時區。例如,將紐約時間轉換為洛杉磯時間:

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

這樣做後,我們就可以看到這些事件在洛杉磯當地時間的具體發生時間。

內容解密:

  1. 轉換到其他時區:使用 pd.Series.dt.tz_convert 方法將已經轉換為特定時區感知格式的時間序列轉換到其他目標時區。
  2. 輸出結果:轉換後的每個元素都顯示了目標時區的具體發生時間。

時間資料與互操作性

在某些情況下,我們可能需要與無法保留時區資訊的系統或資料函式庫進行互操作。如果遇到這種情況,我們可以使用 pd.Series.dt.tz_localize(None) 方法去除時間資料中的時區資訊:

la_ser_dropped = la_ser.dt.tz_localize(None)
print(la_ser_dropped)

這樣做後,我們就可以將去除了時區資訊的時間資料傳遞給無法保留此類別資訊的系統或資料函式庫。

內容解密:

  1. 去除時區資訊:使用 pd.Series.dt.tz_localize(None) 方法去除時間資料中的時區資訊。
  2. 輸出結果:輸出去除了時區資訊之後所對應之日期時間列表。

然而,強烈建議將去除了時區資訊之時間資料以及原始時區資訊以字串格式儲存於另一列表中。這對於後續重新將去除時區資訊之時間資料轉換為時區資訊覺察狀態有所幫助:

df = la_ser.to_frame().assign(
    datetime=la_ser_dropped,
    timezone=str(la_ser.dt.tz),
).drop(columns=[0])
print(df)

內容解密:

  1. 將時間資料與時區資訊分開儲存:將時間資料與時區資訊分開儲存於不同之列表當中。
  2. 後續轉換:為了在日後將之前未標明時區之時間資料還原為標明時區狀態之下,我們可藉由適當利用之前已分開儲存之時區資訊來達到目的。

透過以上步驟我們可以確保即使在與無法保留時區資訊之系統或資料函式庫進行互操作過程中也不會丟失重要之時區資訊。

時間序列資料處理

使用 Pandas 處理時間序列資料

在現代資料分析與機器學習中,時間序列資料處理是一個不可或缺的技能。Pandas 是一個強大的 Python 函式庫,提供了豐富的功能來處理時間序列資料。玄貓將帶領大家探討如何使用 Pandas 處理時間序列資料,並深入瞭解其各種功能和應用。

日期偏移

在處理時間序列資料時,常常需要對日期進行偏移操作。Pandas 提供了多種日期偏移類別,可以方便地將日期移動到不同的時間點。例如,pd.offsets.MonthBegin 可以將日期移動到下個月的第一天。以下是一個簡單的例子:

import pandas as pd

# 建立一個包含日期的 Series
ser = pd.Series(pd.to_datetime(['2024-01-31', '2024-01-31', '2024-01-31']))

# 使用 pd.offsets.MonthBegin 偏移日期
ser + pd.offsets.MonthBegin()

內容解密:

在這段程式碼中,我們首先建立了一個包含三個相同日期的 Series。接著,我們使用 pd.offsets.MonthBegin 將這些日期偏移到下個月的第一天。這樣做的目的是展示如何使用 Pandas 的日期偏移功能來處理時間序列資料。

除了 pd.offsets.MonthBegin 外,Pandas 還提供了其他多種偏移類別,例如 pd.offsets.SemiMonthBeginpd.offsets.QuarterBeginpd.offsets.YearBegin 等。這些類別都可以用來將日期移動到不同的時間點。

定製化業務日偏移

在某些情況下,我們可能需要根據特定的業務日來進行偏移操作。Pandas 提供了 pd.offsets.BusinessDay 類別,可以根據業務日的定義來進行偏移。例如,以下程式碼展示瞭如何將日期向前偏移三個業務日:

# 建立一個包含日期的 Series
ser = pd.Series(pd.to_datetime(['2024-01-01', '2024-01-02', '2024-01-03']))

# 使用 pd.offsets.BusinessDay 偏移三個業務日
bd_ser = ser + pd.offsets.BusinessDay(n=3)

內容解密:

在這段程式碼中,我們建立了一個包含三個不同日期的 Series。接著,我們使用 pd.offsets.BusinessDay 將這些日期向前偏移三個業務日。需要注意的是,業務日的定義預設為週一至週五。

如果我們的業務日與預設設定義不同,可以使用 pd.offsets.CustomBusinessDay 來自定義業務日。例如,以下程式碼展示瞭如何自定義業務日為週一至週四:

# 自定義業務日為週一至週四
ser + pd.offsets.CustomBusinessDay(n=3, weekmask="Mon Tue Wed Thu")

內容解密:

在這段程式碼中,我們使用 pd.offsets.CustomBusinessDay 自定義了業務日為週一至週四。然後將日期向前偏移三個自定義業務日。這樣可以更靈活地處理不同的業務需求。

此外,我們還可以透過 holidays 引數來指定特別關閉的日子,以避免在這些天數上進行業務操作。

# 自定義業務日並指定特別關閉的日子
ser + pd.offsets.CustomBusinessDay(n=3, weekmask="Mon Tue Wed Thu", holidays=["2024-01-04"])

月份開始和結束

在處理時間序列資料時,我們經常需要將日期移動到每個月的開始或結束。Pandas 提供了 pd.offsets.MonthEndpd.offsets.MonthBegin 類別來實作這一功能。

# 建立一個包含日期的 Series
ser = pd.Series(pd.to_datetime(['2024-01-31', '2024-01-31', '2024-01-31']))

# 使用 pd.offsets.MonthEnd 偏移日期
ser + pd.offsets.MonthEnd()

內容解密:

在這段程式碼中,我們建立了一個包含三個相同日期的 Series。然後使用 pd.offsets.MonthEnd 將這些日期偏移到當月的最後一天。這樣可以方便地將日期對齊到每個月的結束。

時間選擇

在 Pandas 中,我們可以透過 pd.date_range 函式生成一個包含特定頻率和範圍的 DatetimeIndex。

# 生成從 2023-12-27 開始每隔十天生成五個時間點
pd.date_range(start="2023-12-27", freq="10D", periods=5)

內容解密:

在這段程式碼中,我們使用 pd.date_range 函式生成了一個從 2023 年 12 月 27 日開始每隔十天生成五個時間點 的 DatetimeIndex。這樣可以方便地生成特定頻率和範圍的日期序列。

此外,我們還可以透過修改 freq 引數來生成不同頻率的 DatetimeIndex。例如:

# 生成從 2023 年 12 月 31 日開始每隔兩週生成五個時間點且每次都是周天開始
pd.date_range(start="2023-12-31", freq="2W-SUN", periods=5)