Python 資料處理:Pandas 進階技巧與實戰範例
Python 資料處理:Pandas 進階技巧與實戰範例
在資料分析的日常工作中,Pandas 幾乎是不可或缺的工具。這篇文章整理了一些實用但文件中不太容易找到的進階技巧,希望能幫助大家提升資料處理的效率。
環境設定
pip install pandas numpy matplotlib openpyxlimport 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)} 筆離群值")效能優化小結
- 優先向量化:避免 Python 迴圈,用 Pandas/NumPy 內建操作
- 適當指定 dtype:
category對重複字串欄位效果顯著 - 用 query 取代 boolean indexing:更易讀
- 善用 eval:
df.eval('total = price * quantity')在大資料集上效能更好
資料處理的功力需要時間累積,建議多練習真實的資料集,Kaggle 上有很多公開資料可以拿來練手。
分享這篇文章