Pandas 作為 Python 資料科學領域的核心函式庫,其資料型別應用對於資料處理效率至關重要。本文不僅詳述浮點數精確度的選擇與影響,更深入探討布林值與字串型別的最佳實務,同時也涵蓋時間序列資料的處理技巧。透過理解不同資料型別的特性,開發者能避免因精確度不足或型別轉換造成的錯誤,並藉由選擇合適的資料型別提升程式碼執行效能。此外,文章也提供缺失值處理的相關知識,讓讀者在面對實際資料分析情境時,能更有效率地處理資料,並建立更穩健的資料分析流程。

資料型別詳解與應用實務

在資料分析與處理的過程中,選擇正確的資料型別是至關重要的。正確的資料型別不僅能提高運算效率,還能避免潛在的錯誤。本文將深入探討 pandas 中常見的資料型別,包括浮點數、布林值和字串,並詳細說明其應用方式及缺失值處理的相關議題。

浮點數型別的精確度考量

在大多數情況下,除非系統資源受限,否則建議使用 64 位浮點數型別。相較於 32 位浮點數,64 位浮點數具有更高的精確度,能有效避免因精確度不足導致的計算錯誤。以下是一個典型的例子,展示了使用 32 位浮點數時可能遇到的精確度問題:

import pandas as pd

# 建立兩個使用32位浮點數的Series
ser1 = pd.Series([1_000_000.123], dtype=pd.Float32Dtype())
ser2 = pd.Series([1_000_000.124], dtype=pd.Float32Dtype())

# 比較兩個Series是否相等
print(ser1.eq(ser2))

輸出結果:

0    True
dtype: boolean

在上述例子中,明明兩個數值並不相同,但由於 32 位浮點數的精確度限制,比較結果卻顯示它們相等。這是因為 32 位浮點數只能提供 6 到 9 位的有效數字,無法準確表示更精確的數值。

  flowchart TD
    A[建立浮點數Series] --> B{選擇浮點數精確度}
    B -->|32位浮點數| C[可能出現精確度問題]
    B -->|64位浮點數| D[較高精確度,較少錯誤]
    C --> E[比較數值可能出錯]
    D --> F[比較結果更可靠]

圖表翻譯:

此圖示展示了選擇不同浮點數精確度對數值比較的影響。選擇 32 位浮點數可能導致精確度問題,而使用 64 位浮點數則能提供更高的精確度,減少比較錯誤的可能性。

布林資料型別的應用

布林資料型別用於表示真(True)或假(False)的值,在資料分析中非常有用,尤其是在機器學習演算法中,常用來將類別型資料轉換為數值型資料(1 和 0)。建立布林型別的 Series 可以使用 pd.BooleanDtype()

# 建立布林型別的Series
ser_bool = pd.Series([True, False, True], dtype=pd.BooleanDtype())
print(ser_bool)

輸出結果:

0     True
1    False
2     True
dtype: boolean

pandas 會自動將數值 1 和 0 轉換為布林值 True 和 False:

# 使用數值建立布林Series
ser_bool_num = pd.Series([1, 0, 1], dtype=pd.BooleanDtype())
print(ser_bool_num)

輸出結果與前例相同:

0     True
1    False
2     True
dtype: boolean

對於缺失值,pandas 使用 pd.NA 來表示,同時也會自動將 None 轉換為 pd.NA

# 處理缺失值的布林Series
ser_bool_na = pd.Series([1, pd.NA, None], dtype=pd.BooleanDtype())
print(ser_bool_na)

輸出結果:

0     True
1     <NA>
2     <NA>
dtype: boolean

字串資料型別的應用與處理

字串資料型別適用於儲存文字資料。在 pandas 3.0 之後,字串的處理機制有了顯著的改進,效能更好且佔用記憶體更少。建議安裝 PyArrow 以獲得最佳效能。

建立字串型別的 Series 可以使用 pd.StringDtype()

# 建立字串型別的Series
ser_str = pd.Series(["foo", "bar", "baz"], dtype=pd.StringDtype())
print(ser_str)

輸出結果:

0    foo
1    bar
2    baz
dtype: string

對於字串的處理,pandas 提供了 str 存取器,可以用來進行各種字串操作,例如取得字串長度、轉換大小寫等:

# 建立範例Series
ser = pd.Series(["xx", "YyY", "zZzZ"], dtype=pd.StringDtype())

# 取得字串長度
print(ser.str.len())
# 轉換為大寫
print(ser.str.upper())
# 轉換為小寫
print(ser.str.lower())
# 轉換為標題格式(首字母大寫)
print(ser.str.title())

輸出結果:

# 長度
0    2
1    3
2    4
dtype: Int64

# 大寫
0      XX
1     YYY
2    ZZZZ
dtype: string

# 小寫
0      xx
1     yyy
2    zzzz
dtype: string

# 標題格式
0      Xx
1     Yyy
2    Zzzz
dtype: string

此外,str 存取器還支援檢查字串是否包含特定內容:

# 檢查是否包含特定字串
ser = pd.Series(["foo", "bar", "baz"], dtype=pd.StringDtype())
print(ser.str.contains("foo"))

輸出結果:

0     True
1    False
2    False
dtype: boolean

也可以使用正規表示式進行更複雜的比對:

# 使用正規表示式比對
print(ser.str.contains("ba.", regex=True))

輸出結果:

0    False
1     True
2     True
dtype: boolean

缺失值處理機制解析

在 pandas 中,缺失值的處理機制因資料型別而異。早期的 pandas 主要根據 NumPy,而 NumPy 的資料型別不支援缺失值。因此,pandas 採用了不同的策略來處理缺失值,例如使用 np.nan 來表示浮點數的缺失值。

# 建立整數Series並賦予缺失值
ser = pd.Series(range(3))
ser.iloc[1] = None
print(ser)

輸出結果:

0    0.0
1    NaN
2    2.0
dtype: float64

在上述例子中,原本的整數 Series 在賦予缺失值後被轉換為浮點數型別。對於不同的資料型別,pandas 採用了不同的缺失值表示方法,例如 pd.NaT 用於日期時間型別。

為了統一缺失值的處理,pandas 引入了擴充套件型別(Extension Types),並使用 pd.NA 作為統一的缺失值表示。不過,由於歷史相容性的問題,不同資料型別的缺失值處理仍存在不一致的情況。

幸運的是,pandas 提供了 pd.isna 函式,可以用來檢查任意型別的缺失值:

# 檢查缺失值
print(pd.isna(pd.Series([1, np.nan, 2])))
print(pd.isna(pd.Series([1, pd.NA, 2], dtype=pd.Int64Dtype())))

輸出結果:

0    False
1     True
2    False
dtype: bool

0    False
1     True
2    False
dtype: bool
圖表翻譯:

此圖示展示了在資料分析過程中選擇不同資料型別的流程。根據不同的資料特性選擇合適的型別,並注意相關的處理細節,例如浮點數的精確度問題、布林值的自動轉換、以及字串的操作方式。最終,展望了正確選擇資料型別後如何有效進行資料處理。

資料型別進階應用:布林與類別型資料的最佳實踐

在資料分析與處理過程中,正確選擇和使用資料型別對於提升效能、確保資料準確性至關重要。本文將深入探討pandas中布林與類別型資料的應用技巧,幫助開發者更好地掌握這些特殊資料型別的使用方法。

布林擴充型別:pd.BooleanDtype的應用

pd.BooleanDtype是pandas中用於處理布林資料的擴充型別,它允許在布林運算中正確處理缺失值。與傳統的布林型別不同,pd.BooleanDtype可以明確表示三種狀態:True、False和缺失值(pd.NA)。

程式碼範例:使用pd.BooleanDtype處理布林資料

import pandas as pd

# 建立整數型Series
ser = pd.Series(range(3), dtype=pd.Int64Dtype())

# 建立包含缺失值的布林遮罩
mask = pd.Series([True, pd.NA, False], dtype=pd.BooleanDtype())

# 使用布林遮罩篩選資料
result = ser[mask]
print(result)

內容解密:

此範例展示瞭如何使用pd.BooleanDtype建立可包含缺失值的布林遮罩。程式碼首先建立了一個整數型Series,接著建立了一個包含True、False和pd.NA的布林遮罩。最後使用此遮罩篩選原始資料,只傳回遮罩為True的對應值。

類別型資料:pd.CategoricalDtype的最佳實踐

類別型資料用於表示具有有限個不同值的資料集,如性別、尺碼等。透過將字串值對映為整數編碼,類別型資料可以顯著降低記憶體使用量並提升運算效率。

建立類別型資料的兩種方法

  1. 使用astype()轉換
values = ["foo", "bar", "baz"]
ser = pd.Series(values, dtype=pd.StringDtype()).astype(pd.CategoricalDtype())
print(ser)
  1. 使用pd.CategoricalDtype物件
cat_type = pd.CategoricalDtype(["foo", "bar", "baz"], ordered=True)
ser = pd.Series(["foo", "bar", "baz"], dtype=cat_type)
print(ser)

內容解密:

這兩種方法都可以將資料轉換為類別型,但第二種方法提供了更多控制選項,如指定類別順序。類別型資料在記憶體使用上更為高效,因為它內部使用整數編碼儲存資料。

類別型資料的記憶體優勢

類別型資料的記憶體優勢主要來自於其內部實作機制。以下是一個簡單的效能對比:

import pandas as pd

# 建立測試資料
data = ["foo", "bar", "baz"] * 100

# 字串型別記憶體使用量
str_series = pd.Series(data, dtype=pd.StringDtype())
print(f"字串型別記憶體使用量:{str_series.memory_usage()} bytes")

# 類別型別記憶體使用量
cat_series = str_series.astype(pd.CategoricalDtype())
print(f"類別型別記憶體使用量:{cat_series.memory_usage()} bytes")

圖表視覺化:記憶體使用量比較

  flowchart LR
 A[原始字串資料] --> B[轉換為類別型資料]
 B --> C[記憶體使用量顯著降低]
 C --> D[提升運算效率]

圖表翻譯:

此流程圖展示了將字串資料轉換為類別型資料的過程及其帶來的記憶體使用優勢。首先,原始字串資料被轉換為類別型資料,接著記憶體使用量顯著降低,最終達到提升運算效率的效果。

有序類別型資料的應用場景

在某些場景下,類別之間的順序關係非常重要,如衣物尺碼(S、M、L)。透過指定ordered=True,可以建立有序的類別型資料,方便進行比較運算。

sizes = pd.CategoricalDtype(["S", "M", "L", "XL"], ordered=True)
ser = pd.Series(["XL", "L", "S", "M"], dtype=sizes)

# 進行比較運算
print(ser < "L")

內容解密:

此範例展示瞭如何建立有序的類別型資料並進行比較運算。透過指定類別的順序,可以實作有意義的比較操作,如判斷某個值是否小於特定值。

時間型別:datetime 的應用與注意事項

在資料分析中,時間型別(Temporal types)扮演著至關重要的角色,尤其是在處理時間序列資料時。pandas 提供了一系列強大的功能來處理日期和時間資料,使得趨勢檢測和預測模型的建立變得更加容易。

建構 datetime 型別的資料

與某些資料函式庫系統不同,pandas 並未區分 DATEDATETIMETIMESTAMP 型別,而是統一使用「datetime」型別。建構 datetime 型別的資料可以透過 dtype 引數實作,語法形式為 "datetime64[<unit>]"

# 建構 datetime 型別的 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)

內容解密:

此範例展示瞭如何建立一個包含 datetime 型別資料的 Series。即使輸入的字串不包含時間元件,pandas 內部仍會將這些值儲存為 datetime 型別,而非單純的日期。這一點在後續對資料的操作中至關重要。

  flowchart TD
 A[建立 datetime Series] --> B{檢查輸入資料}
 B -->|含時間元件| C[儲存為 datetime 型別]
 B -->|不含時間元件| C
 C --> D[使用 dt 存取器進行操作]

圖表翻譯:

此圖示描述了建立 datetime 型別 Series 的流程。首先,檢查輸入資料是否包含時間元件。無論是否包含,pandas 都會將資料儲存為 datetime 型別。接著,可以利用 dt 存取器對這些資料進行進一步的操作,如提取年份、月份等資訊。

使用 dt 存取器操作 datetime 資料

當 Series 中包含 datetime 型別的資料時,可以使用 dt 存取器來解鎖一系列便捷的功能。例如,可以輕鬆提取日期的年份、月份或星期幾:

# 提取年份
print(ser.dt.year)

# 提取月份
print(ser.dt.month)

# 提取日期
print(ser.dt.day)

# 提取星期幾(0 代表星期一,6 代表星期日)
print(ser.dt.day_of_week)

內容解密:

dt 存取器提供了一系列屬性,可以用來提取 datetime 資料的不同部分。這使得對時間序列資料的分析變得更加直觀和方便。

時區感知(Timezone-aware)時間戳

在處理全球資料時,時區的正確處理至關重要。預設情況下,pandas 中的 datetime 資料是時區無感知的(timezone-naive)。要使其變為時區感知的,可以使用 pd.DatetimeTZDtype() 並指定時區:

# 建立時區感知(UTC)的 datetime Series
ser_tz = pd.Series([
    "2024-01-01 00:00:01",
    "2024-01-02 00:00:01",
    "2024-01-03 00:00:01"
], dtype=pd.DatetimeTZDtype(tz="UTC"))

print(ser_tz)

內容解密:

透過指定 tz 引數,可以使 datetime 資料與特定的時區關聯起來。這對於跨時區的資料分析和處理尤為重要。

  flowchart TD
 A[建立時區感知 datetime Series] --> B{指定時區}
 B -->|使用 tz 引數| C[建立時區感知 datetime 資料]
 C --> D[進行跨時區資料分析]

圖表翻譯:

此圖示展示瞭如何建立時區感知的 datetime Series。首先,需要透過 tz 引數指定時區。完成時區設定後,便可以進行跨時區的資料分析,確保時間資料的準確性和一致性。