跳至主要內容

Python 資料處理:Pandas 進階技巧與實戰範例

Python 資料處理:Pandas 進階技巧與實戰範例

在資料分析的日常工作中,Pandas 幾乎是不可或缺的工具。這篇文章整理了一些實用但文件中不太容易找到的進階技巧,希望能幫助大家提升資料處理的效率。

環境設定

pip install pandas numpy matplotlib openpyxl
import pandas as pd
import numpy as np

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', 50)
pd.set_option('display.float_format', lambda x: '%.3f' % x)

1. 高效讀取大型 CSV

當 CSV 檔案超過幾百 MB,直接 pd.read_csv() 可能 OOM。用 chunksize 分批讀取:

def process_large_csv(filepath: str, chunk_size: int = 10000):
    results = []
    for chunk in pd.read_csv(filepath, chunksize=chunk_size):
        filtered = chunk[chunk['amount'] > 1000]
        summary = filtered.groupby('category')['amount'].sum()
        results.append(summary)
    return pd.concat(results).groupby(level=0).sum()

指定 dtype 減少記憶體用量:

dtype_spec = {
    'user_id': 'int32',
    'category': 'category',
    'amount': 'float32',
}
df = pd.read_csv('transactions.csv', dtype=dtype_spec)
print(f"記憶體使用:{df.memory_usage(deep=True).sum() / 1024**2:.2f} MB")

2. 多層索引(MultiIndex)操作

data = {
    'year': [2024, 2024, 2025, 2025] * 3,
    'quarter': ['Q1', 'Q2', 'Q1', 'Q2'] * 3,
    'region': ['北部'] * 4 + ['中部'] * 4 + ['南部'] * 4,
    'sales': np.random.randint(100, 500, 12)
}
df = pd.DataFrame(data)
df_multi = df.set_index(['region', 'year', 'quarter'])

# 使用 xs 取特定層的資料
north_data = df_multi.xs('北部', level='region')

# 用 loc 取多層索引
specific = df_multi.loc[('北部', 2025), :]

3. apply、map、applymap 的正確使用時機

grade_map = {'A': 4.0, 'A+': 4.3, 'B': 3.0}
df['gpa'] = df['grade'].map(grade_map)

def classify_student(row):
    if row['score'] >= 90:
        return '優秀'
    elif row['score'] >= 80:
        return '良好'
    return '普通'

df['classification'] = df.apply(classify_student, axis=1)

效能提醒:優先使用向量化操作:

# 慢(apply)
df['score_cat'] = df['score'].apply(lambda x: 'pass' if x >= 60 else 'fail')

# 快(np.where 向量化)
df['score_cat'] = np.where(df['score'] >= 60, 'pass', 'fail')

# 多條件判斷
conditions = [df['score'] >= 90, df['score'] >= 80, df['score'] >= 70]
choices = ['A', 'B', 'C']
df['letter_grade'] = np.select(conditions, choices, default='D')

4. 時間序列處理

dates = pd.date_range('2025-01-01', periods=365, freq='D')
ts = pd.Series(np.random.randn(365).cumsum(), index=dates)

weekly = ts.resample('W').mean()
rolling_mean = ts.rolling(window=7).mean()
rolling_std = ts.rolling(window=30).std()

jan_data = ts['2025-01']
ts_taipei = ts.tz_localize('UTC').tz_convert('Asia/Taipei')

5. 高效合併資料表

orders = pd.DataFrame({
    'order_id': [1, 2, 3, 4],
    'user_id': [101, 102, 101, 103],
    'amount': [500, 300, 800, 200]
})

users = pd.DataFrame({
    'user_id': [101, 102, 104],
    'name': ['Alice', 'Bob', 'David']
})

left = pd.merge(orders, users, on='user_id', how='left')
assert len(left) == len(orders), "Left join 應保留所有左表紀錄"

6. 資料清理實用技巧

# 處理缺失值
df.dropna(subset=['critical_column'])
df.fillna({'age': df['age'].median(), 'name': 'Unknown'})

# 移除重複值
df.drop_duplicates(subset=['user_id', 'date'], keep='last')

# 字串清理
df['phone'] = (
    df['phone']
    .str.strip()
    .str.replace(r'[^\d]', '', regex=True)
    .str.zfill(10)
)

# 偵測離群值(IQR 方法)
Q1 = df['amount'].quantile(0.25)
Q3 = df['amount'].quantile(0.75)
IQR = Q3 - Q1
outliers = df[(df['amount'] < Q1 - 1.5*IQR) | (df['amount'] > Q3 + 1.5*IQR)]
print(f"偵測到 {len(outliers)} 筆離群值")

效能優化小結

  1. 優先向量化:避免 Python 迴圈,用 Pandas/NumPy 內建操作
  2. 適當指定 dtypecategory 對重複字串欄位效果顯著
  3. 用 query 取代 boolean indexing:更易讀
  4. 善用 evaldf.eval('total = price * quantity') 在大資料集上效能更好

資料處理的功力需要時間累積,建議多練習真實的資料集,Kaggle 上有很多公開資料可以拿來練手。

分享這篇文章