Pandas 類別資料

Categorical 是 Pandas 的一種特殊資料型別,用於處理只有有限幾種值的欄位(如性別、等級、城市等)。使用 Categorical 可以節省記憶體並提升效能。

建立 Categorical

從 Series 轉換

import pandas as pd

s = pd.Series(['low', 'high', 'medium', 'low', 'high'])

# 轉換成 category 型別
s_cat = s.astype('category')
print(s_cat)
0       low
1      high
2    medium
3       low
4      high
dtype: category
Categories (3, object): ['high', 'low', 'medium']

使用 Categorical 類別

# 基本建立
cat = pd.Categorical(['a', 'b', 'a', 'c'])

# 指定類別
cat = pd.Categorical(['a', 'b', 'a'], categories=['a', 'b', 'c'])

# 有順序的類別
cat = pd.Categorical(
    ['low', 'high', 'medium'],
    categories=['low', 'medium', 'high'],
    ordered=True
)

在 DataFrame 中使用

df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'grade': pd.Categorical(['A', 'B', 'A'], categories=['A', 'B', 'C', 'D'])
})

print(df.dtypes)
name      object
grade    category
dtype: object

Categorical 的優點

節省記憶體

s_str = pd.Series(['apple'] * 10000)
s_cat = s_str.astype('category')

print(f"字串: {s_str.memory_usage(deep=True)} bytes")
print(f"類別: {s_cat.memory_usage(deep=True)} bytes")

當有大量重複值時,Categorical 的記憶體使用量會小很多。

提升效能

分組和排序等操作在 Categorical 上通常更快。

有序類別

# 建立有順序的類別
size = pd.Categorical(
    ['M', 'S', 'L', 'M', 'S'],
    categories=['S', 'M', 'L'],
    ordered=True
)

s = pd.Series(size)

# 可以進行比較
print(s > 'S')
0     True
1    False
2     True
3     True
4    False
dtype: bool

排序

df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'size': pd.Categorical(['M', 'S', 'L'], categories=['S', 'M', 'L'], ordered=True)
})

# 按照定義的順序排序
df_sorted = df.sort_values('size')
print(df_sorted)
      name size
1      Bob    S
0    Alice    M
2  Charlie    L

類別操作

查看類別

s = pd.Series(['a', 'b', 'a', 'c']).astype('category')

# 查看所有類別
print(s.cat.categories)
# Index(['a', 'b', 'c'], dtype='object')

# 查看類別編碼
print(s.cat.codes)
# 0    0
# 1    1
# 2    0
# 3    2
# dtype: int8

新增類別

s = pd.Series(['a', 'b']).astype('category')

# 新增類別(不會新增資料)
s = s.cat.add_categories(['c', 'd'])
print(s.cat.categories)
# Index(['a', 'b', 'c', 'd'], dtype='object')

移除類別

# 移除指定類別
s = s.cat.remove_categories(['d'])

# 移除未使用的類別
s = s.cat.remove_unused_categories()

重新命名類別

s = pd.Series(['a', 'b', 'a']).astype('category')

# 重新命名
s = s.cat.rename_categories({'a': 'A', 'b': 'B'})
print(s)
0    A
1    B
2    A
dtype: category
Categories (2, object): ['A', 'B']

設定類別

# 設定新的類別(會把不在新類別中的值變成 NaN)
s = s.cat.set_categories(['A', 'C'])
print(s)
0      A
1    NaN
2      A
dtype: category
Categories (2, object): ['A', 'C']

重新排序類別

s = pd.Series(['low', 'high', 'medium']).astype('category')

# 設定順序
s = s.cat.reorder_categories(['low', 'medium', 'high'], ordered=True)

實際應用

等級資料

df = pd.DataFrame({
    'student': ['Alice', 'Bob', 'Charlie', 'David'],
    'grade': ['B', 'A', 'C', 'A']
})

# 轉換成有順序的類別
df['grade'] = pd.Categorical(
    df['grade'],
    categories=['F', 'D', 'C', 'B', 'A'],
    ordered=True
)

# 找出 B 以上的學生
print(df[df['grade'] >= 'B'])

編碼轉換

df = pd.DataFrame({
    'color': ['red', 'blue', 'red', 'green']
})

df['color'] = df['color'].astype('category')

# 取得數字編碼(用於機器學習)
df['color_code'] = df['color'].cat.codes
print(df)
   color  color_code
0    red           2
1   blue           0
2    red           2
3  green           1

統計分析

df = pd.DataFrame({
    'age_group': pd.Categorical(
        ['young', 'adult', 'young', 'senior', 'adult'],
        categories=['young', 'adult', 'senior'],
        ordered=True
    ),
    'value': [10, 20, 15, 30, 25]
})

# 分組統計(會按照類別順序)
print(df.groupby('age_group', observed=False)['value'].mean())
age_group
young     12.5
adult     22.5
senior    30.0
Name: value, dtype: float64

處理缺失類別

df = pd.DataFrame({
    'month': pd.Categorical(['Jan', 'Mar'], categories=['Jan', 'Feb', 'Mar'])
})

# value_counts 會包含所有類別
print(df['month'].value_counts())
month
Jan    1
Mar    1
Feb    0
Name: count, dtype: int64