
目录
- 目标与原则
- 数据质量检查(探索性数据清洗)
- 缺失值处理(Missing Values)
- 异常值检测与处理(Outliers / Anomalies)
- 重复值处理
- 数据筛选与子集选择
- 数据类型与内存优化
- 插值(Interpolation)
- 数据变换(Scaling / Normalization / Transformation)
- 类别变量编码(Categorical Encoding)
- 时间序列专用处理
- 数据平滑与降噪(Denoising / Smoothing)
- 特征构造与降维(Feature Engineering & Dimensionality Reduction)
- 数据增强(Imbalanced / Augmentation)
- 管道化(Pipelines)、列变换与可复现流程
- 常见实战示例与模板代码
- 最佳实践清单
1. 目标与原则
目标:提高训练数据的质量,保证模型学习到的是可靠、一般化的信号而非噪声或数据泄露。
原则:
- 可复现:所有变换应在训练/验证/测试上以相同方式应用(使用
Pipeline/ColumnTransformer)。 - 最小改动:不随意删除大量数据,优先考虑稳健填补或变换。
- 记录与可视化:对每一步统计并可视化(缺失率、分布、漂移)。
- 以任务为导向:选择对 downstream task 有益的方法(对回归/分类/时间序列选择不同策略)。
2. 数据质量检查(EDA for cleaning)
常用函数 / 库 :pandas (df.info(), df.describe(), df.isna().sum()), matplotlib / seaborn(可视化),missingno(可视化缺失)
作用:发现列类型问题、缺失分布、异常分布、类别不平衡、时间空洞等。
示例:
python
import pandas as pd
df.info()
print(df.isna().sum())
print(df.describe(include='all'))
3. 缺失值处理(Missing Values)
常见方法与 Python 工具
-
删除样本 / 列
- 函数:
df.dropna(axis=0/1, thresh=...) - 作用:当缺失率高且无法可靠填补时删除。
- 原理:简单直接,但可能引入样本选择偏差。
- 函数:
-
常数或统计量填充(均值/中位数/众数)
- 函数:
df.fillna(value),sklearn.impute.SimpleImputer(strategy='mean'|'median'|'most_frequent') - 作用:快速、低成本;对数值常用均值/中位数,对类别用众数。
- 原理:用整体统计量近似替代缺失值,适用于缺失为随机缺失(MCAR)或可近似的场景。
- 函数:
-
基于 KNN 的插补(KNNImputer)
- 函数:
sklearn.impute.KNNImputer。 - 作用:用最近邻相似样本的值进行填补。
- 原理:假定相似样本具有相似特征分布,基于距离加权平均填充。
- 函数:
-
多重插补 / 迭代插补(MICE / IterativeImputer)
- 函数:
sklearn.impute.IterativeImputer(近似 MICE),或fancyimpute中方法。 - 作用:为每个缺失列建立预测模型(如回归)来估计缺失值。
- 原理:基于条件分布迭代估计,保留变量间关联结构,适用于缺失非完全随机的情况(MAR)。
- 函数:
-
基于模型的预测填充
- 方法:训练一个模型(如树模型)预测缺失列,使用预测值填补。
- 作用:在高度相关特征存在时非常有效。
-
填充策略的额外处理
- 增加缺失指示变量(
is_nan_flag),帮助模型学习缺失本身的信息。
- 增加缺失指示变量(
示例
python
from sklearn.impute import SimpleImputer, KNNImputer
imp = SimpleImputer(strategy='median')
df[['col1','col2']] = imp.fit_transform(df[['col1','col2']])
knn = KNNImputer(n_neighbors=5)
df_num = knn.fit_transform(df_num)
4. 异常值检测与处理(Outliers)
经典方法与实现
-
统计方法(Z-score)
- 函数:
scipy.stats.zscore或(x - x.mean())/x.std() - 原理:基于正态假设,若 z-score 超过阈值(如 3)视为异常。
- 函数:
-
IQR(箱型图)法
- 公式:
lower = Q1 - 1.5*IQR,upper = Q3 + 1.5*IQR。 - 函数:
pandas.Series.quantile。
- 公式:
-
基于稳健统计(MAD)
- 原理:中位数绝对偏差对重尾分布更稳健。
-
基于学习的异常检测
- 函数/模型:
sklearn.ensemble.IsolationForest,sklearn.covariance.EllipticEnvelope,one-class SVM。 - 原理:孤立森林基于随机分割,孤立点被更早隔离;协方差方法适用于近似高斯分布。
- 函数/模型:
-
基于聚类或密度
- 函数:
DBSCAN(噪声点作为异常)
- 函数:
-
处理策略
- 删除、截断(capping/winsorize)、替换(中位数)、或保留并用 robust 模型处理。
scipy.stats.mstats.winsorize实现截断。
示例(IQR)
python
q1 = df['x'].quantile(0.25)
q3 = df['x'].quantile(0.75)
iqr = q3 - q1
lower, upper = q1 - 1.5*iqr, q3 + 1.5*iqr
mask = df['x'].between(lower, upper)
df_clean = df[mask]
5. 重复值处理
函数 :df.duplicated(), df.drop_duplicates()。
作用:移除或标记重复记录,避免样本重复导致偏差或数据泄露(例如训练与测试重复)。
实践要点:在判定重复时需指明关键列(subset)与是否保留第一次/最后一次(keep 参数)。
6. 数据筛选与子集选择
函数 :df.query(), df.loc[], 布尔索引。
作用:按条件过滤异常时间段、保留特定用户群或删除采集错误样本。
示例:
python
df_filtered = df.query("age >= 18 and country == 'CN'")
7. 数据类型与内存优化
函数 :df.astype(), pd.to_datetime(), pd.to_numeric();pd.to_numeric(..., downcast='integer')。
作用:正确的数据类型能减少内存、加速计算,并避免错误比较。
技巧 :大表用 category 类型存储低基数类别;数值列根据范围 downcast 为 int8/int16/float32。
python
df['cat_col'] = df['cat_col'].astype('category')
df['ints'] = pd.to_numeric(df['ints'], downcast='integer')
## 三种模式:raise coerce ignore
8. 插值(Interpolation)
常见方法:线性插值、时间插值、样条插值(spline)、最近邻插值
函数 :df.interpolate(method='linear'|'time'|'spline'), scipy.interpolate.interp1d
作用:补全时间序列或连续测量中中断的数值,保留趋势/曲线结构,插值只会对缺失值进行处理。
原理:基于已知点构造连续函数并估算未知点;样条和多项式会拟合更平滑曲线但可能引入振荡。
示例:
python
df['value'] = df['value'].interpolate(method='time')
9. 数据变换(Scaling / Normalization / Transformation)
常见方法与工具:
- 标准化(Standardization):
sklearn.preprocessing.StandardScaler(减均值除以标准差) - 归一化(Min-Max):
MinMaxScaler - 稳健缩放:
RobustScaler(基于中位数和 IQR) - 对数变换 / Box-Cox / Yeo-Johnson:
scipy.stats.boxcox,sklearn.preprocessing.PowerTransformer
作用:消除量纲差异、降低长尾、使优化器收敛更快、提高某些模型(如线性回归、KNN、SVM)的表现。
示例:
python
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df_num)
10. 类别变量编码(Categorical Encoding)
方法:
- One-Hot:
pd.get_dummies,OneHotEncoder(适用于无序类别、基数适中) - 标签编码(Ordinal):
sklearn.preprocessing.OrdinalEncoder(有序类别) - 目标编码(Target Encoding):
category_encoders包(对类别与目标有强关系时) - 频次编码、哈希编码(
FeatureHasher)适用于高基数
注意:目标编码在交叉验证或训练/验证划分时必须防止数据泄露(使用折叠 mean target 或训练集统计)。
python
import category_encoders as ce
enc = ce.TargetEncoder()
df['cat_te'] = enc.fit_transform(df['cat'], y)
11. 时间序列专用处理
操作:
pd.to_datetime(),set_index()为 DatetimeIndex- 重采样:
resample('H').mean() - 滑动窗口特征:
rolling(window=...),expanding() - 时差特征:
shift()(滞后特征) - 季节性/趋势分解:
statsmodels.tsa.seasonal.STL
作用:恢复固定频率、构造滞后与滚动统计量、去趋势与去季节性。
示例:
python
df.index = pd.to_datetime(df['ts'])
df_hour = df.resample('1H').mean()
df['lag1'] = df['val'].shift(1)
df['rolling_mean_3'] = df['val'].rolling(3).mean()
12. 数据平滑与降噪(Smoothing / Denoising)
经典方法:
-
移动平均(MA)
- 函数:
Series.rolling(window).mean() - 作用:低通滤波,去除高频噪声。
- 函数:
-
指数加权移动平均(EWMA)
- 函数:
Series.ewm(span=...).mean() - 作用:对历史数据赋予指数衰减权重,更灵活应对突变。
- 函数:
-
中值滤波(Median filter)
- 函数:
scipy.signal.medfilt,对脉冲噪声鲁棒。
- 函数:
-
Savitzky-Golay 滤波
- 函数:
scipy.signal.savgol_filter - 作用:用局部多项式平滑,保留信号的形状和峰值。
- 函数:
-
小波去噪(Wavelet denoising)
- 库:
pywt(PyWavelets) - 原理:将信号分解到不同频带,阈值化高频系数后重构。
- 库:
-
频域滤波(FFT)与带通/低通滤波
- 函数:
numpy.fft或scipy.signal设计滤波器
- 函数:
示例(EWMA)
python
smoothed = df['val'].ewm(span=10, adjust=False).mean()
13. 特征构造与降维
方法与工具:
- 交互特征、多项式特征:
sklearn.preprocessing.PolynomialFeatures - 主成分分析 (PCA):
sklearn.decomposition.PCA(线性降维,保留方差) - 非负矩阵分解 (NMF):
sklearn.decomposition.NMF - 特征选择:
SelectKBest,RFE,SelectFromModel(L1/Lasso) - 互信息、方差阈值:
sklearn.feature_selection.VarianceThreshold,mutual_info_regression
原理:
- 降维用于降低维度并去除冗余;特征选择用于去掉无关或噪声特征,提高泛化。
示例(PCA)
python
from sklearn.decomposition import PCA
pca = PCA(n_components=10)
X_pca = pca.fit_transform(X_scaled)
14. 数据增强(不平衡与通用增强)
方法:
- 重采样:欠采样(undersampling)、过采样(oversampling)
- SMOTE / ADASYN:
imblearn.over_sampling.SMOTE - 时间序列增强:窗口切片、扰动、时间扭曲(task-specific)
注意:增强应仅在训练集上进行,防止信息泄露到验证/测试。
python
from imblearn.over_sampling import SMOTE
sm = SMOTE()
X_res, y_res = sm.fit_resample(X_train, y_train)
15. 管道化(Pipelines)、列变换与可复现流程
工具 :sklearn.pipeline.Pipeline, sklearn.compose.ColumnTransformer, FunctionTransformer
作用:把预处理、编码、缩放、模型训练串成一条可复现、可保存的流水线(用于交叉验证也不会泄露)。
示例:
python
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
num_cols = ['age','income']
cat_cols = ['city']
num_pipe = Pipeline([('imputer', SimpleImputer(strategy='median')), ('scaler', StandardScaler())])
cat_pipe = Pipeline([('imputer', SimpleImputer(strategy='most_frequent')), ('ohe', OneHotEncoder(handle_unknown='ignore'))])
preproc = ColumnTransformer([('num', num_pipe, num_cols), ('cat', cat_pipe, cat_cols)])
pipe = Pipeline([('preproc', preproc), ('clf', RandomForestClassifier())])
pipe.fit(X_train, y_train)
16. 常见实战示例与模板代码
16.1 数值列的完整清洗模板
python
import pandas as pd
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
# 1. 类型转换
num_cols = ['a','b','c']
df[num_cols] = df[num_cols].apply(pd.to_numeric, errors='coerce')
# 2. 缺失填充
imp = SimpleImputer(strategy='median')
df[num_cols] = imp.fit_transform(df[num_cols])
# 3. 异常值截断(winsorize)
from scipy.stats.mstats import winsorize
df['a_w'] = winsorize(df['a'], limits=[0.01, 0.01])
# 4. 标准化
scaler = StandardScaler()
df[num_cols] = scaler.fit_transform(df[num_cols])
16.2 时间序列特征工程模板
python
df['ts'] = pd.to_datetime(df['ts'])
df = df.set_index('ts').sort_index()
# 重采样到分钟级
df = df.resample('1T').mean()
# 插值
df['val'] = df['val'].interpolate(method='time')
# 构造滞后和滚动特征
for lag in [1,3,6]:
df[f'lag_{lag}'] = df['val'].shift(lag)
for w in [3,6,12]:
df[f'roll_mean_{w}'] = df['val'].rolling(window=w).mean()