Pandas 提供了強大的時間序列處理能力,讓開發者能輕鬆地操作和分析時間相關資料。重取樣是其中一個重要功能,可以將時間序列資料轉換到不同的頻率,例如從每日資料轉換到每週或每小時資料。這個過程涉及到資料聚合和缺失值處理,需要仔細選擇適當的策略以確保分析結果的準確性。在實際應用中,例如分析感測器資料或金融市場資料時,重取樣和缺失值處理是不可或缺的步驟。

時間資料型別與演算法深入解析

在處理時間序列資料時,pandas 提供了豐富的功能來進行重取樣(resampling)操作。重取樣是一種將時間序列資料從一個頻率轉換到另一個頻率的過程,可以是降取樣(downsampling)或升取樣(upsampling)。

降取樣:從高頻到低頻的資料轉換

降取樣是指將高頻率的資料轉換為低頻率的資料。例如,將每日資料轉換為每週或每月資料。在 pandas 中,可以使用 pd.Series.resample() 方法來實作降取樣。

import pandas as pd

# 建立一個每日頻率的時間序列
index = pd.date_range(start="2024-01-01", freq="D", periods=10)
ser = pd.Series(range(10), index=index, dtype=pd.Int64Dtype())

# 檢視原始資料
print("原始資料:")
print(ser)

# 將每日資料降取樣為每週資料,週日為週期結束日
weekly_sum = ser.resample("W").sum()
print("\n每週資料總和(週日結束):")
print(weekly_sum)

# 也可以選擇不同的週期結束日,例如週六
weekly_sum_sat = ser.resample("W-SAT").sum()
print("\n每週資料總和(週六結束):")
print(weekly_sum_sat)

程式碼解析:

  1. 首先建立一個每日頻率的時間序列 ser,包含從 2024-01-01 開始的 10 天資料。
  2. 使用 resample("W") 將資料降取樣為每週頻率,預設是週日結束的週期。
  3. 使用 resample("W-SAT") 將每週結束日改為週六。
  4. sum() 方法用於計算每週資料的總和。

升取樣:從低頻到高頻的資料轉換

升取樣是指將低頻率的資料轉換為高頻率的資料。例如,將每日資料轉換為每12小時的資料。在 pandas 中,同樣可以使用 pd.Series.resample() 方法來實作升取樣,但需要搭配 asfreq() 方法。

# 將每日資料升取樣為每12小時
ser_12h = ser.resample("12h").asfreq()
print("\n升取樣後的資料(每12小時):")
print(ser_12h.iloc[:6])

程式碼解析:

  1. 使用 resample("12h") 將每日資料升取樣為每12小時的頻率。
  2. asfreq() 方法用於將結果轉換為新的頻率,但會產生缺失值。
  3. 列印出前6個資料點,可以看到缺失值被表示為 <NA>

缺失值處理

在升取樣過程中會產生缺失值,pandas 提供了幾種方法來處理這些缺失值:

  1. 向前填充(Forward Fill):使用前一個有效值填充缺失值。
ser_12h_ffill = ser.resample("12h").asfreq().ffill()
print("\n向前填充後的資料:")
print(ser_12h_ffill.iloc[:6])
  1. 向後填充(Backward Fill):使用後一個有效值填充缺失值。
ser_12h_bfill = ser.resample("12h").asfreq().bfill()
print("\n向後填充後的資料:")
print(ser_12h_bfill.iloc[:6])
  1. 插值法(Interpolation):根據前後值進行數學插值,預設為線性插值。
ser_12h_interp = ser.resample("12h").asfreq().interpolate()
print("\n線性插值後的資料:")
print(ser_12h_interp.iloc[:6])

圖表視覺化:重取樣過程示意圖

  flowchart TD
    A[原始時間序列] --> B{重取樣}
    B -->|降取樣| C[降低頻率]
    B -->|升取樣| D[提高頻率]
    C --> E[聚合運算]
    D --> F[缺失值處理]
    F --> G[向前填充]
    F --> H[向後填充]
    F --> I[插值法]

圖表解析:

此圖示展示了時間序列重取樣的流程。根據不同的需求,可以選擇降取樣或升取樣。升取樣後需要進行缺失值處理,可以選擇向前填充、向後填充或插值法來填補缺失的資料點。

使用 Grouper 實作重取樣

除了使用 resample() 方法,pandas 也提供了 pd.Grouper 來實作類別似的功能。

# 使用 pd.Grouper 進行重取樣
ser_grouper = ser.groupby(pd.Grouper(freq="3s")).sum()
print("\n使用 pd.Grouper 重取樣的結果:")
print(ser_grouper)

程式碼解析:

  1. pd.Grouper(freq="3s") 指定了重取樣的頻率為每3秒。
  2. groupby() 方法根據指定的頻率進行分組。
  3. sum() 方法計算每個分組的總和。

實際應用:丹佛犯罪資料集分析

在實際應用中,可以使用重取樣技術來分析大型資料集,例如丹佛犯罪資料集。透過將犯罪事件按週或月進行彙總,可以更好地理解犯罪趨勢。

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

# 按週彙總犯罪事件
weekly_crimes = df.resample("W").size()
print("\n每週犯罪事件數量:")
print(weekly_crimes.head())

程式碼解析:

  1. 使用 read_parquet() 方法讀取犯罪資料集,並將 REPORTED_DATE 設定為索引。
  2. 使用 resample("W") 將資料按週彙總。
  3. size() 方法計算每週的事件數量。

透過上述技術,可以有效地分析和理解時間序列資料在不同頻率下的特性和趨勢。重取樣技術在資料分析和視覺化中具有重要的應用價值。

時間資料型別與演算法分析

在處理時間序列資料時,pandas 提供了強大的工具來進行資料重構和分析。以下將詳細介紹如何使用 pandas 進行時間序列資料的處理和分析。

時間序列資料重構

首先,我們需要了解如何將資料按照時間進行重構。假設我們有一個犯罪資料集,其中包含了犯罪事件的報告日期。我們可以使用 pd.DataFrame.resample 方法來按照周、月、季度或年進行資料重構。

import pandas as pd

# 載入犯罪資料集
df = pd.read_parquet("data/crime.parquet")
df.set_index("REPORTED_DATE", inplace=True)

# 按照周進行重構並計算犯罪數量
weekly_crime_count = df.resample("W").size()
print(weekly_crime_count.head())

程式碼解說:

此程式碼首先載入犯罪資料集,並將報告日期設為索引。然後使用 resample 方法按照周進行重構,並使用 size 方法計算每週的犯罪數量。結果是一個 pd.Series 物件,其中索引是每週的最後一天(預設為星期日)。

時間序列資料分析

為了進一步分析資料,我們可以繪製時間序列圖來觀察趨勢。

import matplotlib.pyplot as plt

# 繪製每週犯罪數量圖表
weekly_crime_count.plot(title="All Denver Crimes")
plt.show()

圖表翻譯:

此圖表展示了丹佛市每週的犯罪數量趨勢。透過觀察圖表,可以發現犯罪數量的季節性變化和長期趨勢。

季度資料分析

除了每週資料,我們還可以按照季度進行資料分析。

# 按照季度進行重構並計算犯罪和交通事故數量
quarterly_summary = df.resample("QS")[["IS_CRIME", "IS_TRAFFIC"]].sum()
print(quarterly_summary.head())

程式碼解說:

此程式碼使用 resample 方法按照季度進行重構,並計算每季度的犯罪和交通事故數量。結果是一個 DataFrame 物件,其中包含了每季度的犯罪和交通事故總數。

年度變化分析

為了分析年度變化,我們可以使用 pd.Series.pct_change 方法來計算年對年變化率。

# 按照年度進行分組並計算犯罪數量
annual_crime_count = df.groupby([
    "OFFENSE_CATEGORY_ID",
    pd.Grouper(key="REPORTED_DATE", freq="YS"),
]).agg(total_crime=pd.NamedAgg(column="IS_CRIME", aggfunc="sum"))

# 計算年對年變化率
annual_crime_count["yoy_change"] = annual_crime_count.groupby(level=0)["total_crime"].pct_change()
print(annual_crime_count.head(10))

程式碼解說:

此程式碼首先按照犯罪類別和年度進行分組,並計算每年的犯罪數量。然後使用 pct_change 方法計算年對年變化率。為了避免不同犯罪類別之間的比較,我們在 groupby 物件上呼叫 pct_change 方法。

Mermaid 圖表展示

  flowchart TD
    A[資料載入] --> B[時間索引設定]
    B --> C[按周重構]
    C --> D[計算每週犯罪數量]
    D --> E[繪製時間序列圖]
    E --> F[按季度重構]
    F --> G[計算季度犯罪和交通事故數量]
    G --> H[分析年度變化]
    H --> I[計算年對年變化率]

圖表翻譯:

此圖表展示了時間序列資料分析的流程。首先載入資料並設定時間索引,然後按照周和季度進行重構,並計算相關的統計資料。最後分析年度變化並計算年對年變化率。這個流程清晰地展示了從資料載入到最終分析的整個過程。

時間序列資料分析與缺失值處理

在進行時間序列資料分析時,資料的完整性和準確性至關重要。資料缺失可能對分析結果產生重大影響,因此需要仔細處理缺失值。

案例分析:芝加哥智慧綠色基礎設施監測感測器資料

本案例使用芝加哥市提供的智慧綠色基礎設施監測感測器歷史資料。該資料集包含多個感測器測量的不同環境因素,如水流和溫度。理想情況下,感測器應該持續運作並回報數值,但實際上它們容易出現間歇性故障,導致資料缺失。

資料載入與初步處理

首先,我們載入所需的Parquet檔案:

import pandas as pd

# 載入Parquet檔案
df = pd.read_parquet("data/sgi_monitoring.parquet", dtype_backend="numpy_nullable")

# 檢視資料前幾行
print(df.head())

資料時間欄位轉換

檢查Measurement Time欄位,發現其資料型別為字串,需要轉換為datetime型別。同時,根據資料檔案的說明,該時間是芝加哥當地的時間,因此需要進行時區設定:

# 將Measurement Time轉換為datetime並設定時區
df["Measurement Time"] = pd.to_datetime(df["Measurement Time"]).dt.tz_localize("US/Central")

# 檢視轉換後的結果
print(df["Measurement Time"].head())

資料篩選與整理

由於不同感測器測量不同的環境因素,我們需要篩選出特定的感測器資料。本例中,我們關注的是TM1 Temp Sensor,且Data Stream ID為39176的資料:

# 篩選特定感測器資料
mask = (df["Measurement Description"] == "TM1 Temp Sensor") & (df["Data Stream ID"] == 39176)
df_filtered = df[mask].set_index("Measurement Time").sort_index()

# 檢視篩選後的資料
print(df_filtered[["Measurement Type", "Units"]].value_counts())

資料重取樣與視覺化

對篩選後的資料進行重取樣,計算每日的平均值,並繪製圖表:

# 重取樣並繪製每日平均值
df_filtered.resample("D")["Measurement Value"].mean().plot()

# 顯示圖表
import matplotlib.pyplot as plt
plt.tight_layout()
plt.show()

Mermaid圖表:資料處理流程

  flowchart TD
    A[資料載入] --> B[時間欄位轉換]
    B --> C[資料篩選]
    C --> D[資料重取樣]
    D --> E[視覺化展示]

圖表翻譯:

此圖示展示了資料處理的主要流程。首先進行資料載入,接著將時間欄位轉換為適當的格式。然後根據特定條件篩選資料,隨後進行資料重取樣以獲得每日的匯總資料。最後,將處理後的資料進行視覺化展示,以便更直觀地理解資料特徵。

技術要點解析

  1. 時間序列資料型別轉換:正確轉換時間欄位至datetime型別,並設定正確的時區,是時間序列分析的基礎。
  2. 資料篩選:根據研究需求,篩選出相關的感測器資料,以避免不同感測器資料之間的不可比性。
  3. 重取樣技術:使用重取樣技術,可以將高頻資料匯總為低頻資料,以便於分析和視覺化。
  4. 缺失值處理:在實際應用中,需要進一步檢查和處理資料中的缺失值,以確保分析結果的準確性。

時間資料型別與演算法最佳化

在處理時間序列資料時,資料缺失是一個常見問題。本文將探討如何使用 pandas 來處理時間序列資料中的缺失值,並介紹相關的資料重取樣和插值技術。

資料缺失問題的識別

首先,我們需要檢查資料中是否存在缺失值。透過對資料進行重取樣,可以清晰地看到缺失的天數:

df.loc["2017-07-24":"2017-08-01"].resample("D")["Measurement Value"].mean()

結果分析

從結果中可以看到,2017年7月31日的資料完全缺失。這種缺失可能是由於感測器故障或其他資料收集問題引起的。

資料插值處理

為瞭解決資料缺失問題,可以使用 pd.Series.interpolate() 方法對缺失值進行插值:

df.resample("D")["Measurement Value"].mean().interpolate().plot()

內容解密

上述程式碼首先對資料進行日重取樣,然後使用線性插值方法填充缺失值。插值後的資料可以更平滑地展示趨勢,避免因缺失值導致的視覺化斷層。

不同聚合函式的影響

選擇不同的聚合函式會對結果產生顯著影響。例如,使用平均值聚合可以較好地掩蓋缺失值,但如果使用求和聚合,則會暴露資料缺失的問題:

df.resample("D")["Measurement Value"].sum().plot()

結果分析

從每日求和的結果可以看到,7月下旬和10月的資料缺失導致了明顯的下降。這表明在進行資料分析時,選擇合適的聚合函式至關重要。

詳細資料檢查

進一步檢查資料可以發現,感測器在某些時間段內完全停止了資料收集。例如,從2017年7月30日15:50:46到2017年8月1日15:21:33之間存在近2天的資料缺失:

df.loc["2017-07-30 15:45:00":"2017-08-01"].head()

資料解讀

上述結果顯示了資料中斷前後的時間戳,證實了長時間的資料缺失。

資料頻率分析

檢查資料的收集頻率可以發現,每小時的資料點數量並非始終保持一致:

df.resample("h").size().plot()

結果解讀

結果顯示,大多數小時內有接近60個資料點,但實際上完全達到60個資料點的情況非常少見:

df.resample("h").size().loc[lambda x: x >= 60]

分鐘級重取樣與插值

為了獲得更精確的資料,可以進行分鐘級的重取樣和插值:

df.resample("min")["Measurement Value"].sum().interpolate()

內容解密

上述程式碼將資料重取樣到分鐘級別,並對缺失值進行插值處理。然而,需要注意的是,pandas 在對缺失值求和時會傳回0,而不是缺失值指標。

修正缺失值處理

為了正確處理缺失值,可以使用 min_count 引數來指定非缺失值的最小數量:

interpolated = df.resample("min")["Measurement Value"].sum(min_count=1).interpolate()

結果驗證

修正後的結果顯示,之前為0的值現在被正確插值為合理的數值。

最終驗證與視覺化

最後,檢查每小時的資料點數量是否達到預期:

interpolated.resample("h").size().plot()

並將資料重取樣到日級別,檢視總和趨勢:

interpolated.resample("D").sum().plot()

結果分析

經過處理後的資料圖表顯示了更合理的趨勢,並且下界值也有所提升,從而獲得了更有價值的洞察。

流程圖示

  flowchart TD
 A[資料載入] --> B{檢查資料缺失}
 B -->|有缺失| C[進行插值處理]
 B -->|無缺失| D[進行資料分析]
 C --> E[重取樣到分鐘級別]
 E --> F[使用min_count引數處理缺失值]
 F --> G[最終資料視覺化]
 D --> G

圖表翻譯

此圖示展示了時間序列資料處理的完整流程。首先載入資料並檢查是否存在缺失值。如果存在缺失值,則進行插值處理;如果沒有,則直接進行資料分析。插值處理包括重取樣到分鐘級別,並使用 min_count 引數正確處理缺失值。最終,所有資料都會進行視覺化展示,以獲得有價值的洞察。