Pandas-數據清洗與處理
- 一、數據清洗的核心目標
- 二、缺失值處理
- 1. 缺失值檢測
- 2. 缺失值處理策略
- (1)刪除法
- (2)填充法
- 三、異常值識別與處理
- 1. 異常值檢測方法
- (1)統計法
- (2)業務規則法
- 2. 異常值處理策略
- 四、重復數據處理
- 1. 重復數據檢測
- 2. 重復數據處理
- 五、數據格式轉換與標準化
- 1. 日期時間格式轉換
- 2. 文本數據清洗
- 3. 數據類型轉換
- 六、應用實例:完整數據清洗流程
數據清洗與處理往往占據最多的時間,現實世界中的數據很少是完美的——它們可能包含缺失值、異常值、重復記錄,或是格式混亂、命名不規范的字段。Pandas作為Python數據處理的瑞士軍刀,提供了強大而靈活的工具來應對這些問題。
一、數據清洗的核心目標
數據清洗的最終目的是提升數據質量,為后續分析和建模奠定基礎。具體來說,需要實現以下目標:
- 完整性:處理缺失值,確保關鍵信息不缺失
- 一致性:統一數據格式、命名規范和取值標準
- 準確性:識別并修正異常值、錯誤數據
- 唯一性:去除重復記錄,避免分析結果偏差
- 可用性:將數據轉換為便于分析的結構(如日期類型、分類編碼)
圍繞這些目標,Pandas提供了從簡單到復雜的一系列處理函數,掌握它們的組合使用是高效清洗數據的關鍵。
二、缺失值處理
缺失值是數據清洗中最常見的問題,Pandas通過isnull()
、dropna()
和fillna()
等函數形成完整的處理鏈條。
1. 缺失值檢測
首先需要定位缺失值的位置和比例:
import pandas as pd
import numpy as np# 讀取示例數據
df = pd.read_csv('messy_data.csv')# 檢測每列缺失值數量及比例
missing_count = df.isnull().sum()
missing_ratio = (missing_count / len(df)).round(3)
missing_df = pd.DataFrame({'缺失值數量': missing_count,'缺失比例': missing_ratio
})
print("缺失值統計:")
print(missing_df[missing_df['缺失值數量'] > 0]) # 只顯示有缺失的列
2. 缺失值處理策略
根據缺失比例和字段重要性,選擇不同的處理方式:
(1)刪除法
適用于缺失比例極高(如超過80%)或對分析無影響的字段,或缺失行數量極少的情況:
# 刪除缺失比例超過50%的列
threshold = len(df) * 0.5
df = df.dropna(thresh=threshold, axis=1)# 刪除關鍵字段(如用戶ID)缺失的行
df = df.dropna(subset=['user_id', 'order_date'])
(2)填充法
對于重要字段,需根據字段類型選擇合理的填充值:
# 數值型字段:用中位數填充(抗異常值能力強于均值)
df['amount'] = df['amount'].fillna(df['amount'].median())# 分類型字段:用眾數或特殊標記(如"未知")填充
df['category'] = df['category'].fillna(df['category'].mode()[0])
df['city'] = df['city'].fillna('未知城市')# 時間型字段:用前后值填充(適用于時間序列數據)
df['login_time'] = df['login_time'].fillna(method='ffill') # 向前填充
df['logout_time'] = df['logout_time'].fillna(method='bfill') # 向后填充# 分組填充:按類別分組后,用組內均值填充(更精準)
df['score'] = df.groupby('class')['score'].transform(lambda x: x.fillna(x.mean())
)
三、異常值識別與處理
異常值(離群點)會扭曲統計結果和模型訓練,需結合業務邏輯識別并處理。
1. 異常值檢測方法
(1)統計法
適用于數值型字段,通過四分位距(IQR)或標準差判斷:
def detect_outliers_iqr(df, col):"""用IQR法檢測異常值"""q1 = df[col].quantile(0.25)q3 = df[col].quantile(0.75)iqr = q3 - q1lower_bound = q1 - 1.5 * iqrupper_bound = q3 + 1.5 * iqrreturn (df[col] < lower_bound) | (df[col] > upper_bound)# 檢測"金額"字段的異常值
df['is_amount_outlier'] = detect_outliers_iqr(df, 'amount')
print(f"異常值比例:{df['is_amount_outlier'].mean():.2%}")
(2)業務規則法
基于領域知識判斷,如訂單金額不能為負、年齡不能超過150歲:
# 檢測金額為負的異常值
df['is_invalid_amount'] = df['amount'] < 0# 檢測年齡不合理的記錄
df['is_invalid_age'] = (df['age'] < 0) | (df['age'] > 150)
2. 異常值處理策略
# 1. 修正明顯錯誤(如金額為負可能是符號錯誤)
df.loc[df['amount'] < 0, 'amount'] = df.loc[df['amount'] < 0, 'amount'].abs()# 2. 截斷法(將異常值限制在合理范圍內)
q1, q3 = df['amount'].quantile([0.25, 0.75])
df['amount'] = df['amount'].clip(lower=q1 - 1.5 * (q3 - q1), upper=q3 + 1.5 * (q3 - q1))# 3. 標記法(保留異常值但標記,供后續分析)
df['age'] = df['age'].mask(df['age'] > 120, np.nan) # 用NaN標記異常年齡,后續填充
四、重復數據處理
重復數據可能導致分析結果偏誤(如重復計算同一訂單),需檢測并去重。
1. 重復數據檢測
# 檢測完全重復的行
duplicate_rows = df.duplicated().sum()
print(f"完全重復的行數:{duplicate_rows}")# 檢測關鍵字段組合重復(如同一用戶同一時間的重復記錄)
duplicate_combo = df.duplicated(subset=['user_id', 'login_time'], keep=False).sum()
print(f"用戶-時間組合重復的記錄數:{duplicate_combo}")# 查看重復樣本
if duplicate_rows > 0:print("重復樣本示例:")print(df[df.duplicated(keep=False)].head())
2. 重復數據處理
# 保留第一次出現的記錄,刪除后續重復行
df = df.drop_duplicates(keep='first')# 對關鍵字段組合去重,并保留金額最大的記錄
df = df.sort_values('amount', ascending=False) # 按金額降序排列
df = df.drop_duplicates(subset=['user_id', 'product_id'], keep='first')
五、數據格式轉換與標準化
原始數據常存在格式混亂問題(如日期格式不統一、文本大小寫混用),需標準化處理。
1. 日期時間格式轉換
日期字段若以字符串形式存儲,需轉換為datetime
類型才能進行時間運算:
# 轉換日期字符串為datetime類型(支持多種格式自動識別)
df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce')
# errors='coerce'將無效格式轉為NaT(缺失日期)# 提取日期中的年、月、周等信息
df['order_year'] = df['order_date'].dt.year
df['order_month'] = df['order_date'].dt.month
df['is_weekend'] = df['order_date'].dt.dayofweek.isin([5, 6]) # 判斷是否周末
2. 文本數據清洗
處理文本字段中的大小寫、空格、特殊字符等問題:
# 去除字符串前后空格
df['product_name'] = df['product_name'].str.strip()# 統一為小寫(適用于不區分大小寫的場景)
df['category'] = df['category'].str.lower()# 替換特殊字符(如將"手機_"和"手機("統一為"手機")
df['category'] = df['category'].str.replace(r'[_\(\)]', '', regex=True)# 提取文本中的數字(如從"價格:99元"中提取99)
df['price'] = df['price_text'].str.extract(r'(\d+)').astype(float)
3. 數據類型轉換
優化數據類型以減少內存占用,或滿足分析需求:
# 將字符串ID轉換為分類類型(適用于高基數但重復值多的字段)
df['user_id'] = df['user_id'].astype('category')# 將數值型字符串轉換為數值類型(如"100.5"→100.5)
df['amount'] = pd.to_numeric(df['amount_str'], errors='coerce')# 將布爾值轉換為0/1(便于某些模型處理)
df['is_vip'] = df['is_vip'].astype(int)
六、應用實例:完整數據清洗流程
def clean_data(df):"""完整的數據清洗函數"""print(f"原始數據形狀:{df.shape}")# 1. 缺失值處理print("\n=== 處理缺失值 ===")# 刪除無意義的高缺失列df = df.drop(columns=['unused_col1', 'unused_col2'])# 填充數值列和分類型列num_cols = df.select_dtypes(include=['int64', 'float64']).columnsfor col in num_cols:df[col] = df[col].fillna(df[col].median())cat_cols = df.select_dtypes(include=['object', 'category']).columnsfor col in cat_cols:df[col] = df[col].fillna(df[col].mode()[0] if not df[col].mode().empty else '未知')# 2. 異常值處理print("\n=== 處理異常值 ===")df['amount'] = df['amount'].clip(lower=0) # 金額不能為負df['age'] = df['age'].mask((df['age'] < 0) | (df['age'] > 120), df['age'].median())# 3. 重復數據處理print("\n=== 處理重復數據 ===")df = df.drop_duplicates(subset=['order_id'], keep='first')# 4. 格式轉換print("\n=== 格式轉換 ===")df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce')df['product_name'] = df['product_name'].str.strip().str.lower()print(f"清洗后數據形狀:{df.shape}")return df# 執行清洗流程
cleaned_df = clean_data(df)
總結:數據清洗的核心原則
- 理解業務:數據清洗的前提是理解字段含義和業務邏輯(如“年齡為負”在業務中一定是錯誤)。
- 保留痕跡:重要的修改(如異常值替換、缺失值填充)應記錄在日志中,確保可追溯。
- 分步驗證:每完成一步清洗,都需驗證結果(如檢查填充后是否還有缺失值)。
- 自動化復用:將清洗步驟封裝為函數,便于在新數據上重復使用,保證處理邏輯一致。
That’s all, thanks for reading~~
覺得有用就點個贊
、收進收藏
夾吧!關注
我,獲取更多干貨~