Pandas 提供了便捷的工具來處理時間序列資料,讓開發者能輕鬆地進行日期時間選擇、時區轉換以及資料重取樣。理解這些操作對於有效地分析和利用時間相關資料至關重要。本文除了介紹這些核心功能外,也將探討如何處理重取樣過程中可能出現的缺失值,並提供一些在不同資料頻率下的注意事項。

時間序列資料選擇與操作

時間序列資料選擇

時間序列資料選擇是資料分析中的基本操作。Pandas 提供了靈活的方式來選擇特定時間範圍內的資料。以下是一些常見的操作:

首先,我們可以建立一個時間序列並選擇特定範圍內的資料:

import pandas as pd

# 建立時間序列
index = pd.date_range(start="2024-02-05", freq="10D", periods=6)
ser = pd.Series(range(4, 10), index=index)

# 選擇特定範圍內的資料
print(ser.loc["2024-02":"2024-03"])

內容解密:

在上述程式碼中,我們使用 pd.date_range 函式建立了一個頻率為 10 天的時間索引,並將其分配給一個 Pandas Series。然後,我們使用 loc 屬性來選擇從 2 月到 3 月之間的資料。這樣的操作非常靈活,可以根據需要選擇特定的時間範圍。

# 選擇整年的資料
print(ser.loc["2024"].head())
# 建立帶有時區資訊的時間索引
index = pd.date_range(start="2023-12-27", freq="12h", periods=6, tz="US/Eastern")
ser = pd.Series(range(6), index=index)

# 輸出結果
print(ser)
# 使用字串選擇
print(ser.loc[:"2023-12-27 11:59:59"])
print(ser.loc[:"2023-12-27 12:00:00"])
# 建立秒級別的時間索引
index = pd.date_range(start="2024-01-01", periods=10, freq="s")
ser = pd.Series(range(10), index=index, dtype=pd.Int64Dtype())

# 輸出結果
print(ser)
# 下采樣到每三秒一次
print(ser.resample("3s").sum())
# 自定義重樣化行為
print(ser.resample("3s", closed="right").sum())
print(ser.resample("3s", closed="right", label="right").sum())
# 月末重樣化
print(ser.resample("ME").sum())
# 建立日度資料
index = pd.date_range(start="2024-01-01", freq="D", periods=10)
ser = pd.Series(range(10), index=index, dtype=pd.Int64Dtype())

# 檢視日期對應周幾
print(ser.index.day_name())

# 周度重樣化(預設以星期日結束)
print(ser.resample("W").sum())
import matplotlib.pyplot as plt

# 設定圖形為互動模式
plt.ion()

# 重樣化資料並繪製圖表
df.resample("W").size().plot(title="丹佛所有犯罪事件")
plt.show()
# 讀取犯罪資料集
df = pd.read_parquet("data/crime.parquet")

# 按 OFFENSE_CATEGORY_ID 和 REPORTED_DATE 分組並計算每年總犯罪數量
crime_summary = df.groupby([
    "OFFENSE_CATEGORY_ID",
    pd.Grouper(key="REPORTED_DATE", freq="YS"),
], observed=True).agg(
    total_crime=pd.NamedAgg(column="IS_CRIME", aggfunc="sum"),
)

# 新增年度變動率
yoy_crime = crime_summary.assign(
    yoy_change=lambda x: x.groupby(level=0, observed=True).pct_change().astype(pd.Float64Dtype())
)

print(yoy_crime.head(10))
# 選取部分犯罪型別進行視覺化
crimes = tuple(("aggravated-assault", "arson", "auto-theft"))

fig, axes = plt.subplots(nrows=len(crimes), ncols=2, sharex=True)
for idx, crime in enumerate(crimes):
    crime_df = yoy_crime.loc[crime]
    ax0 = axes[idx][0]
    ax1 = axes[idx][1]
    crime_df.plot(kind="bar", y="total_crime", ax=ax0, legend=False)
    crime_df.plot(kind="bar", y="yoy_change", ax=ax1, legend=False)
    xlabels = [x.year for x in crime_df.index]
    ax0.set_xticklabels(xlabels)

plt.show()

時序資料處理與重樣化

在現代資料分析中,時序資料處理是一個至關重要的領域。Pandas 作為一個強大的資料分析函式庫,提供了豐富的功能來處理時序資料,包括日期選擇、時區處理以及重樣化操作。本文將探討這些功能,並結合實際案例來說明其應用。

時間序列資料選擇與操作

時間序列資料選擇

時間序列資料選擇是資料分析中的基本操作。Pandas 提供了靈活的方式來選擇特定時間範圍內的資料。以下是一些常見的操作:

首先,我們可以建立一個時間序列並選擇特定範圍內的資料:

import pandas as pd

# 建立時間序列
index = pd.date_range(start="2024-02-05", freq="10D", periods=6)
ser = pd.Series(range(4, 10), index=index)

# 選擇特定範圍內的資料
print(ser.loc["2024-02":"2024-03"])

內容解密:

在上述程式碼中,我們使用 pd.date_range 函式建立了一個頻率為 10 天的時間索引,並將其分配給一個 Pandas Series。然後,我們使用 loc 屬性來選擇從 2 月到 3 月之間的資料。這樣的操作非常靈活,可以根據需要選擇特定的時間範圍。

選擇整年資料

我們也可以使用類別似的方法來選擇整年的資料。以下是具體的程式碼:

# 選擇整年的資料
print(ser.loc["2024"].head())

內容解密:

這段程式碼展示瞭如何使用 loc 屬性來選擇整年的資料。透過指定年份(例如 “2024”),我們可以輕鬆地取得該年份內的所有資料。

時間區處理

Pandas 不僅支援本地時間(timezone-naive),還支援時區感知時間(timezone-aware)。以下是如何為時間索引新增時區資訊:

# 建立帶有時區資訊的時間索引
index = pd.date_range(start="2023-12-27", freq="12h", periods=6, tz="US/Eastern")
ser = pd.Series(range(6), index=index)

# 輸出結果
print(ser)

內容解密:

在這段程式碼中,我們使用 tz 引數將時間索引設定為 “US/Eastern” 時區。這樣做可以讓我們在處理全球性資料時更加方便。

使用字串選擇

當使用字串來選擇時區感知的時間索引時,Pandas 會自動將字串轉換為相應的時區。以下是具體的例子:

# 使用字串選擇
print(ser.loc[:"2023-12-27 11:59:59"])
print(ser.loc[:"2023-12-27 12:00:00"])

內容解密:

在這段程式碼中,我們使用字串來選擇特定時間點之前或之後的資料。第一個例子中,我們選擇的是某個時間點之前的一小時之內的資料;第二個例子中,我們則選擇了該時間點及其後的一小時之內的資料。這種靈活性使得時間資料處理變得非常方便。

時間重樣化

重樣化(resampling)是指將高頻率資料轉換為低頻率資料的一種操作。Pandas 提供了強大的重樣化功能,可以根據需要將秒級別的資料轉換為分鐘或小時級別的資料。

建立秒級別的時間索引

首先,我們建立一個秒級別的時間索引:

# 建立秒級別的時間索引
index = pd.date_range(start="2024-01-01", periods=10, freq="s")
ser = pd.Series(range(10), index=index, dtype=pd.Int64Dtype())

# 輸出結果
print(ser)

內容解密:

這段程式碼展示瞭如何建立一個頻率為秒級別的時間索引並分配給一個 Pandas Series。這樣做可以方便地處理高頻率資料。

下采樣到每三秒一次

接著,我們使用 resample 函式將秒級別的資料下采樣到每三秒一次:

# 下采樣到每三秒一次
print(ser.resample("3s").sum())

內容解密:

在這段程式碼中,我們使用 resample 函式將原始秒級別的資料下采樣到每三秒一次。這裡使用的是求和操作(sum),即將每三秒內的值相加。這樣做可以減少資料量,同時保留重要資訊。

自定義重樣化行為

Pandas 的重樣化功能非常靈活,我們可以透過 closedlabel 引數來自定義重樣化行為:

# 自定義重樣化行為
print(ser.resample("3s", closed="right").sum())
print(ser.resample("3s", closed="right", label="right").sum())

內容解密:

在這些例子中,我們透過 closed 引數來指定區間是左閉右開還是右閉左開;透過 label 引數來指定標籤應該放置在區間的哪一端。這些引數提供了更多靈活性,使得我們可以根據具體需求進行重樣化操作。

不同頻率下的一些注意事項

在不同頻率下的一些引數預設值會有所不同。例如,「ME」(月末)和「YE」(年末)等頻率會預設建立右閉區間並使用右標籤:

# 月末重樣化
print(ser.resample("ME").sum())

內容解密:

在這段程式碼中,我們對月末進行重樣化操作。預設情況下,Pandas 會建立右閉區間並使用右標籤。

日度資料到週度重樣化

最後,讓我們看看如何將日度資料重樣化到週度:

# 建立日度資料
index = pd.date_range(start="2024-01-01", freq="D", periods=10)
ser = pd.Series(range(10), index=index, dtype=pd.Int64Dtype())

# 檢視日期對應周幾
print(ser.index.day_name())

# 周度重樣化(預設以星期日結束)
print(ser.resample("W").sum())

內容解密:

這段程式碼展示瞭如何將日度資料重樣化到週度。預設情況下,週度重樣化會以星期日結束。

技術選型與未來趨勢

在實際應用中,技術選型非常關鍵。Pandas 提供了豐富且靈活的功能來處理時序資料,無論是基本操作還是高階操作如重樣化和時區處理都非常方便且高效。隨著大資料和人工智慧技術的發展,時序資料分析將變得更加重要。

未來趨勢可能包括更多自動化工具和更智慧化的人工智慧演算法來處理時序資料。此外,雲端運算平台也將提供更多支援和服務來幫助開發者更高效地進行時序資料分析。

時間序列資料的重新取樣技術

時間序列資料處理是資料科學和分析中的重要課題。在Pandas這樣的資料處理工具中,重新取樣(resampling)是一個常見的操作。重新取樣可以幫助我們將資料從更細緻的頻率轉換到較粗略的頻率,或反之。以下玄貓將探討如何在Pandas中進行下取樣(downsampling)和上取樣(upsampling),並且針對這些操作提供具體的實務案例。

下取樣:從細緻到粗略

下取樣是將時間序列資料從更高頻率轉換到較低頻率的過程。例如,從每日資料轉換為每週資料。在Pandas中,這可以透過resample方法來實作。以下是一些具體的範例:

範例1:每週總和計算

假設我們有一個每日事件資料的時間序列,我們可以將其轉換為每週總和。

import pandas as pd

# 建立一個範例時間序列
index = pd.date_range(start="2024-01-01", periods=10, freq="D")
ser = pd.Series(range(10), index=index)

# 每週總和計算
weekly_sum = ser.resample("W").sum()
print(weekly_sum)

內容解密:

此程式碼展示瞭如何使用resample方法將每日事件資料轉換為每週總和。ser.resample("W").sum()的作用是將時間序列中的資料按週進行重新取樣,並計算每週的總和。"W"表示每週,而.sum()則表示計算總和。

上取樣:從粗略到細緻

上取樣是將時間序列資料從較低頻率轉換到較高頻率的過程。例如,從每日資料轉換為每12小時資料。在Pandas中,這也可以透過resample方法來實作,但需要額外使用asfreq方法。

# 每12小時上取樣
upsampled = ser.resample("12H").asfreq()
print(upsampled.iloc[:5])

內容解密:

此程式碼展示瞭如何使用resampleasfreq方法將每日事件資料轉換為每12小時資料。ser.resample("12H").asfreq()的作用是將時間序列中的資料按12小時進行重新取樣,並生成新的索引。如果某些時間點沒有對應的資料,則會填充為缺失值(NA)。

填補缺失值

在上取樣過程中,可能會產生缺失值。Pandas提供了多種方法來填補這些缺失值。

前向填補(Forward Fill)

前向填補會用前一個非缺失值填補缺失值。

forward_filled = upsampled.ffill()
print(forward_filled.iloc[:6])

內容解密:

此程式碼展示瞭如何使用前向填補來處理缺失值。.ffill()方法會將前一個非缺失值填充到缺失值位置。

後向填補(Backward Fill)

後向填補會用後一個非缺失值填補缺失值。

backward_filled = upsampled.bfill()
print(backward_filled.iloc[:6])

內容解密:

此程式碼展示瞭如何使用後向填補來處理缺失值。.bfill()方法會將後一個非缺失值填充到缺失值位置。

插值(Interpolation)

插值會根據前後資料進行線性插值,生成中間的估計值。

interpolated = upsampled.interpolate()
print(interpolated.iloc[:6])

內容解密:

此程式碼展示瞭如何使用線性插值來處理缺失值。.interpolate()方法會根據前後資料進行線性插值,生成中間的估計值。

使用Grouper進行重新取樣

除了使用resample方法,還可以使用pd.Grouper來實作重新取樣。這種方法特別適合需要同時按時間和其他欄位分組的情況。

# 使用Grouper進行重新取樣
grouped = ser.groupby(pd.Grouper(freq="3s")).sum()
print(grouped)

內容解密:

此程式碼展示瞭如何使用pd.Grouper進行重新取樣。ser.groupby(pd.Grouper(freq="3s")).sum()的作用是按3秒鐘進行分組並計算每組的總和。

實務案例:丹佛犯罪資料集

讓我們看看如何應用這些技術到真實世界的資料集中。以下是丹佛犯罪資料集的一個具體應用案例。

# 読取犯罪資料集並設定索引
df = pd.read_parquet("data/crime.parquet").set_index("REPORTED_DATE")

# 每週犯罪次數計算
weekly_crime_count = df.resample("W").size()
print(weekly_crime_count.head())

內容解密:

此程式碼展示瞭如何讀取丹佛犯罪資料集並設定索引為報告日期,然後使用.resample("W").size()計算每週的犯罪次數。這樣我們就能夠知道每週有多少次犯罪報告。

丹佛犯罪資料的時間序列分析

要全面瞭解丹佛犯罪資料的趨勢,我們可以利用重樣化資料進行視覺化處理。透過 Matplotlib 這類別圖形函式庫來繪製圖表,能夠幫助我們更直觀地理解資料的變化趨勢。

資料重樣化與視覺化

在開始之前,我們需要先進一步瞭解如何重樣化資料並將其視覺化。以下是具體步驟及程式碼:

import matplotlib.pyplot as plt

# 設定圖形為互動模式
plt.ion()

# 重樣化資料並繪製圖表
df.resample("W").size().plot(title="丹佛所有犯罪事件")
plt.show()

內容解密:

  1. 匯入 Matplotlib:使用 import matplotlib.pyplot as plt 匯入 Matplotlib 函式庫。
  2. 設定互動模式plt.ion() 使圖形以互動模式顯示,這對於即時更新和觀察結果非常有幫助。
  3. 重樣化資料df.resample("W").size() 將資料按週重樣化並計算每週的事件數量。
  4. 繪製圖表plot(title="丹佛所有犯罪事件") 繪製出來的圖表標題為「丹佛所有犯罪事件」。

這段程式碼的主要目的是將原始資料按週重樣化,然後繪製出每週的事件數量變化趨勢。這樣可以幫助我們觀察到犯罪事件在時間上的變動情況。

內容解密:
  1. 重樣化與總結df.resample("QS")[["IS_CRIME", "IS_TRAFFIC"]].sum() 按季度重樣化並計算每季度的犯罪和交通事故事件總數。
  2. 顯示結果print(quarterly_summary.head()) 輸出前幾筆記錄以檢視結果。

這段程式碼的目的是計算每季度的犯罪和交通事故事件總數,並將結果顯示出來。這樣可以幫助我們瞭解犯罪和交通事故在不同季節的變動情況。

年度變動率分析

對於更細緻的分析,我們可能想要了解不同型別犯罪在年度之間的變動情況。以下是具體步驟及程式碼:

# 讀取犯罪資料集
df = pd.read_parquet("data/crime.parquet")

# 按 OFFENSE_CATEGORY_ID 和 REPORTED_DATE 分組並計算每年總犯罪數量
crime_summary = df.groupby([
    "OFFENSE_CATEGORY_ID",
    pd.Grouper(key="REPORTED_DATE", freq="YS"),
], observed=True).agg(
    total_crime=pd.NamedAgg(column="IS_CRIME", aggfunc="sum"),
)

# 新增年度變動率
yoy_crime = crime_summary.assign(
    yoy_change=lambda x: x.groupby(level=0, observed=True).pct_change().astype(pd.Float64Dtype())
)

print(yoy_crime.head(10))

內容解密:

  1. 讀取資料集df = pd.read_parquet("data/crime.parquet") 從指定路徑讀取犯罪資料集。
  2. 分組與計算df.groupby([...]).agg(...)OFFENSE_CATEGORY_IDREPORTED_DATE 分組,然後計算每年總犯罪數量。
  3. 新增年度變動率assign(yoy_change=lambda x: x.groupby(level=0, observed=True).pct_change().astype(pd.Float64Dtype())) 新增年度變動率欄位。

這段程式碼的目的是計算每種型別犯罪在不同年份之間的變動率,並將結果顯示出來。這樣可以幫助我們瞭解不同型別犯罪在年度之間的變動情況。

視覺化年度變動率

為了更直觀地理解年度變動率,我們可以使用 Matplotlib 進行視覺化。以下是具體步驟及程式碼:

# 選取部分犯罪型別進行視覺化
crimes = tuple(("aggravated-assault", "arson", "auto-theft"))

fig, axes = plt.subplots(nrows=len(crimes), ncols=2, sharex=True)
for idx, crime in enumerate(crimes):
    crime_df = yoy_crime.loc[crime]
    ax0 = axes[idx][0]
    ax1 = axes[idx][1]
    crime_df.plot(kind="bar", y="total_crime", ax=ax0, legend=False)
    crime_df.plot(kind="bar", y="yoy_change", ax=ax1, legend=False)
    xlabels = [x.year for x in crime_df.index]
    ax0.set_xticklabels(xlabels)

plt.show()

內容解密:

  1. 選取部分犯罪型別crimes = tuple(("aggravated-assault", "arson", "auto-theft")) 選取部分犯罪型別進行視覺化。
  2. 建立子圖fig, axes = plt.subplots(nrows=len(crimes), ncols=2, sharex=True) 建立子圖用於顯示不同型別犯罪的年度變動率。
  3. 繪製圖表:遍歷選取的犯罪型別,並依次繪製每種型別的總犯罪數量和年度變動率。
  4. 設定標籤ax0.set_xticklabels(xlabels) 設定 X 軸標籤為年份。

這段程式碼的目的是將不同型別犯罪的年度變動率進行視覺化,從而更直觀地觀察到各型別犯罪在年度之間的變動情況。