Pandas 值的替換

在資料處理中,經常需要將欄位中的值替換成其他值。Pandas 提供了 map()replace() 等方法來處理。

map():映射值

map() 用於將 Series 中的每個值根據映射關係替換成新值。

使用 dict 映射

import pandas as pd

df = pd.DataFrame({
    'grade': ['A', 'B', 'C', 'A', 'B']
})

# 將等級對應到分數
grade_map = {'A': 90, 'B': 80, 'C': 70}
df['score'] = df['grade'].map(grade_map)
print(df)
  grade  score
0     A     90
1     B     80
2     C     70
3     A     90
4     B     80

沒有對應的值會變成 NaN

df = pd.DataFrame({'grade': ['A', 'B', 'D']})
grade_map = {'A': 90, 'B': 80, 'C': 70}
df['score'] = df['grade'].map(grade_map)
# D 沒有對應,會變成 NaN

使用函數映射

df['grade_upper'] = df['grade'].map(str.lower)

# 或使用 lambda
df['grade_len'] = df['grade'].map(lambda x: len(x))

replace():取代值

replace() 更靈活,可以直接取代指定的值。

取代單一值

df = pd.DataFrame({
    'status': ['active', 'inactive', 'active', 'pending']
})

# 將 inactive 取代為 disabled
df['status'] = df['status'].replace('inactive', 'disabled')

取代多個值

# 使用 dict
df['status'] = df['status'].replace({
    'active': 1,
    'inactive': 0,
    'pending': -1
})

# 使用 list
df['status'] = df['status'].replace(
    ['active', 'inactive'],
    ['on', 'off']
)

在整個 DataFrame 取代

df = pd.DataFrame({
    'A': [1, 2, 3],
    'B': [2, 3, 4]
})

# 取代所有欄位中的值
df = df.replace(2, 200)
print(df)
     A    B
0    1  200
1  200    3
2    3    4

使用正規表達式

df = pd.DataFrame({
    'text': ['hello-world', 'foo-bar', 'test-case']
})

# 將 - 取代為空格
df['text'] = df['text'].replace('-', ' ', regex=True)

# 更複雜的正規表達式
df['text'] = df['text'].replace(r'\d+', 'NUM', regex=True)

map() vs replace() 比較

特性map()replace()
適用對象只能用於 SeriesSeries 和 DataFrame
沒有對應時變成 NaN保持原值
正規表達式不支援支援
使用場景完整映射部分取代
s = pd.Series(['A', 'B', 'C'])
mapping = {'A': 1, 'B': 2}

# map:C 會變成 NaN
print(s.map(mapping))     # [1, 2, NaN]

# replace:C 保持原值
print(s.replace(mapping))  # [1, 2, 'C']

where() 和 mask()

根據條件取代值:

where():條件為 False 時取代

df = pd.DataFrame({'value': [1, 2, 3, 4, 5]})

# value <= 3 時保持原值,否則取代為 0
df['result'] = df['value'].where(df['value'] <= 3, 0)
print(df)
   value  result
0      1       1
1      2       2
2      3       3
3      4       0
4      5       0

mask():條件為 True 時取代

# value > 3 時取代為 0
df['result'] = df['value'].mask(df['value'] > 3, 0)

clip():限制值的範圍

df = pd.DataFrame({'value': [1, 5, 10, 15, 20]})

# 限制在 5 到 15 之間
df['clipped'] = df['value'].clip(lower=5, upper=15)
print(df)
   value  clipped
0      1        5
1      5        5
2     10       10
3     15       15
4     20       15

實際應用範例

編碼轉換

df = pd.DataFrame({
    'gender': ['M', 'F', 'M', 'F']
})

# 轉換為數字
df['gender_code'] = df['gender'].map({'M': 0, 'F': 1})

# 或轉換為文字
df['gender_full'] = df['gender'].map({'M': 'Male', 'F': 'Female'})

處理異常值

df = pd.DataFrame({
    'age': [25, 30, -5, 150, 35]  # 有異常值
})

# 將不合理的年齡設為 NaN
df['age'] = df['age'].where((df['age'] > 0) & (df['age'] < 120))

清理資料

df = pd.DataFrame({
    'status': ['yes', 'Yes', 'YES', 'no', 'No', 'N/A']
})

# 統一格式
df['status'] = df['status'].str.lower().replace({
    'yes': True,
    'no': False,
    'n/a': None
})