Pandas 新增欄位

在資料分析過程中,經常需要根據現有欄位計算出新的欄位。

範例資料

import pandas as pd

df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'price': [100, 200, 150],
    'quantity': [2, 3, 4]
})

新增固定值欄位

# 新增固定值
df['category'] = 'A'
print(df)
      name  price  quantity category
0    Alice    100         2        A
1      Bob    200         3        A
2  Charlie    150         4        A

新增計算欄位

基本運算

# 新增計算欄位
df['total'] = df['price'] * df['quantity']
print(df)
      name  price  quantity  total
0    Alice    100         2    200
1      Bob    200         3    600
2  Charlie    150         4    600

多個欄位運算

df = pd.DataFrame({
    'a': [1, 2, 3],
    'b': [4, 5, 6],
    'c': [7, 8, 9]
})

# 多欄位運算
df['sum'] = df['a'] + df['b'] + df['c']
df['avg'] = (df['a'] + df['b'] + df['c']) / 3

使用 assign()

assign() 會回傳新的 DataFrame,不修改原本的資料:

df = pd.DataFrame({
    'price': [100, 200, 150],
    'quantity': [2, 3, 4]
})

# 新增單一欄位
df_new = df.assign(total=df['price'] * df['quantity'])

# 新增多個欄位
df_new = df.assign(
    total=df['price'] * df['quantity'],
    tax=df['price'] * 0.05
)

# 使用 lambda(可以參考新建立的欄位)
df_new = df.assign(
    total=lambda x: x['price'] * x['quantity'],
    avg_price=lambda x: x['total'] / x['quantity']
)

條件欄位

使用 np.where()

import numpy as np

df['status'] = np.where(df['price'] > 150, 'high', 'low')

多條件

# 使用 np.select
conditions = [
    df['price'] < 120,
    df['price'] < 180,
    df['price'] >= 180
]
choices = ['low', 'medium', 'high']
df['level'] = np.select(conditions, choices, default='unknown')

使用 apply()

def categorize(price):
    if price < 120:
        return 'low'
    elif price < 180:
        return 'medium'
    else:
        return 'high'

df['level'] = df['price'].apply(categorize)

從其他欄位組合

字串組合

df = pd.DataFrame({
    'first_name': ['Alice', 'Bob'],
    'last_name': ['Chen', 'Wang']
})

df['full_name'] = df['first_name'] + ' ' + df['last_name']

使用 f-string

df['display'] = df.apply(lambda x: f"{x['first_name']} ({x['last_name']})", axis=1)

插入欄位到特定位置

insert() 可以指定新欄位的位置:

df = pd.DataFrame({
    'A': [1, 2, 3],
    'C': [7, 8, 9]
})

# 在位置 1(第二個位置)插入新欄位
df.insert(1, 'B', [4, 5, 6])
print(df)
   A  B  C
0  1  4  7
1  2  5  8
2  3  6  9

從 Series 新增

# 從另一個 Series 新增(會根據索引對齊)
s = pd.Series([10, 20, 30], index=[0, 1, 2])
df['new_col'] = s

複製欄位

df['price_copy'] = df['price']

# 或使用 copy 確保是獨立的副本
df['price_copy'] = df['price'].copy()

批次新增多個欄位

# 使用 assign
df = df.assign(
    col1=1,
    col2=2,
    col3=df['a'] * 2
)

# 使用迴圈
for i in range(3):
    df[f'new_{i}'] = i

刪除欄位

新增欄位後如果要刪除:

# 刪除單一欄位
df = df.drop('total', axis=1)

# 刪除多個欄位
df = df.drop(['total', 'tax'], axis=1)

# 使用 del
del df['total']

常見錯誤

SettingWithCopyWarning

# 可能產生警告
df[df['price'] > 100]['new'] = 1

# 正確方式:使用 loc
df.loc[df['price'] > 100, 'new'] = 1

這個警告是因為鏈式索引可能在副本上操作,而不是原始 DataFrame。使用 loc 可以確保直接在原始資料上操作。