3. 删除法处理缺失值
任务目标
本案例针对金融数据集中常见的缺失值问题,实现两种删除策略:行删除(删除缺失比例超过阈值的样本)与列删除(删除缺失比例过高的特征列)。通过对比删除前后数据集维度及逻辑回归模型性能,验证删除法在缺失比例较低场景下的适用性。
环境与依赖
需要 pandas、numpy、scikit-learn。使用Python 3.8+即可运行,无需额外安装。
完整实现代码
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, f1_score
from sklearn.datasets import make_classification
# ========== 1. 构造含缺失值的金融模拟数据 ==========
np.random.seed(42)
n_samples = 2000
n_features = 8
# 生成基础数据
X, y = make_classification(n_samples=n_samples, n_features=n_features,
n_informative=6, n_redundant=2, random_state=42)
df = pd.DataFrame(X, columns=[f'feat_{i}' for i in range(n_features)])
df['target'] = y
# 人为引入缺失:feat_0缺失5%,feat_1缺失8%,feat_2缺失40%(高缺失列)
missing_rate = {0: 0.05, 1: 0.08, 2: 0.40}
for col, rate in missing_rate.items():
mask = np.random.rand(n_samples) < rate
df.loc[mask, f'feat_{col}'] = np.nan
print(f"原始数据形状: {df.shape}")
print("各列缺失比例:\n", df.isnull().mean().round(4))
# ========== 2. 行删除:删除缺失比例 > 10% 的样本 ==========
row_threshold = 0.10
# 计算每行缺失比例
row_missing_ratio = df.isnull().sum(axis=1) / df.shape[1]
df_row_del = df[row_missing_ratio <= row_threshold].copy()
print(f"\n行删除后形状: {df_row_del.shape} (删除 {df.shape[0] - df_row_del.shape[0]} 行)")
# ========== 3. 列删除:删除缺失比例 > 30% 的列 ==========
col_threshold = 0.30
cols_to_drop = df_row_del.columns[df_row_del.isnull().mean() > col_threshold]
df_clean = df_row_del.drop(columns=cols_to_drop)
print(f"删除的高缺失列: {list(cols_to_drop)}")
print(f"列删除后形状: {df_clean.shape}")
# ========== 4. 模型性能对比 ==========
def evaluate_model(data, target_col='target'):
"""在给定数据上训练逻辑回归并返回指标"""
X_data = data.drop(columns=[target_col])
y_data = data[target_col]
X_train, X_test, y_train, y_test = train_test_split(
X_data, y_data, test_size=0.3, random_state=42, stratify=y_data)
model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
return {
'accuracy': accuracy_score(y_test, y_pred),
'f1': f1_score(y_test, y_pred)
}
# 原始数据(用均值填充以便训练,仅作对比基线)
df_baseline = df.copy()
for col in df_baseline.columns:
if df_baseline[col].isnull().any():
df_baseline[col] = df_baseline[col].fillna(df_baseline[col].mean())
metrics_baseline = evaluate_model(df_baseline)
metrics_clean = evaluate_model(df_clean)
print("\n========== 模型性能对比 ==========")
print(f"基线(均值填充): Accuracy={metrics_baseline['accuracy']:.4f}, F1={metrics_baseline['f1']:.4f}")
print(f"删除法处理后 : Accuracy={metrics_clean['accuracy']:.4f}, F1={metrics_clean['f1']:.4f}")
print(f"样本量变化: {df.shape[0]} → {df_clean.shape[0]}")
print(f"特征数变化: {df.shape[1]-1} → {df_clean.shape[1]-1}")
运行方式
将上述代码保存为 missing_delete.py,在终端执行:
python missing_delete.py
验证方法与判定标准
- 数据维度验证:观察输出中行删除和列删除前后的形状变化。行删除后样本数应减少约2000×10%以内(因为只有feat_0和feat_1缺失率较低,多数行缺失比例不超过10%);列删除后应移除
feat_2(缺失率40%>30%)。 - 模型性能对比:比较基线与删除法处理后的Accuracy和F1值。由于删除法保留了完整样本且移除了高缺失列,模型性能应不低于基线(或仅有小幅波动),证明在缺失比例较低时删除法是有效策略。
- 通过条件:程序无报错运行完毕,输出中明确显示删除的行数、列名及两个模型的性能指标,且删除后数据集形状与代码逻辑一致(即
df_clean不含feat_2列)。
关键说明
本案例使用模拟数据演示删除法的完整流程。实际金融数据中,行删除阈值通常设为5%~10%,列删除阈值设为30%~50%,需根据业务场景调整。当缺失比例较高时,删除法会损失大量信息,应改用插补法(后续案例覆盖)。