2. 特征类型与数据预处理:数值特征、类别特征、文本特征、缺失值处理、数据标准化与归一化
在进入特征筛选之前,必须对原始数据进行系统性的预处理。不同特征类型(数值、类别、文本)具有不同的数学含义,需要采用差异化的清洗与变换策略。本章将逐一拆解各类特征的处理方法,并重点讲解缺失值填充与无量纲化操作,为后续筛选算法提供干净、可比的数据基础。
2.1 特征类型的识别与分类
特征类型决定了后续预处理与筛选算法的选择。下表总结了三种主要特征类型的定义、常见形式与典型算法适配性:
| 特征类型 | 定义 | 常见形式 | 典型筛选算法 |
|---|---|---|---|
| 数值特征 | 连续或离散的定量数值,具有大小与距离意义 | 年龄、价格、温度、收入 | 方差分析、皮尔逊相关系数、互信息 |
| 类别特征 | 有限个离散取值,无天然顺序或距离含义 | 性别、城市、颜色、产品类型 | 卡方检验、信息增益、WOE编码 |
| 文本特征 | 非结构化字符串,需先转化为数值向量 | 评论、摘要、日志、描述 | TF-IDF筛选、词频方差、LDA主题权重 |
实践提示: 在数据加载后,建议立即使用
df.dtypes 与 df.nunique() 快速扫描特征类型。对于取值数 ≤ 20 的整型列,通常先按类别特征处理;对于取值数 > 20 的整型列,按数值特征处理。
2.2 数值特征预处理
数值特征的处理核心在于消除量纲影响与处理异常分布。主要步骤包括:
- 异常值截断: 使用 IQR 或 Z-score 识别极端值,将其替换为边界值(Winsorize)。
- 对数/Box-Cox变换: 对右偏分布(如收入、点击量)做对数变换,使其更接近正态分布。
- 标准化与归一化: 详见 2.5 节。
import numpy as np
import pandas as pd
from scipy import stats
# 示例:对数变换 + 标准化
df['log_income'] = np.log1p(df['income'])
df['z_score_income'] = (df['log_income'] - df['log_income'].mean()) / df['log_income'].std()
2.3 类别特征预处理
类别特征必须转换为数值形式才能被模型使用。常见编码方式及其适用场景如下:
| 编码方法 | 原理 | 适用场景 | 注意事项 |
|---|---|---|---|
| Label Encoding | 将类别映射为 0,1,2,… | 树模型、有序类别 | 线性模型会误认为有大小关系 |
| One-Hot Encoding | 每个取值生成一个 0/1 列 | 线性模型、KNN、SVM | 类别过多时导致维度爆炸 |
| Target Encoding | 用目标变量均值替换类别 | 高基数类别、树模型 | 需做交叉验证防止过拟合 |
| Frequency Encoding | 用类别出现频次替换 | 类别分布差异大时 | 丢失类别语义信息 |
# One-Hot Encoding 示例
df_encoded = pd.get_dummies(df, columns=['city'], drop_first=True)
# Target Encoding 示例(需配合交叉验证)
from category_encoders import TargetEncoder
encoder = TargetEncoder(cols=['product_type'])
df['product_encoded'] = encoder.fit_transform(df['product_type'], df['target'])
2.4 文本特征预处理
文本特征需要经过分词、清洗、向量化三步才能进入特征矩阵。核心流程如下:
- 文本清洗: 去除标点、数字、停用词,统一小写。
- 分词: 英文按空格分词,中文使用 jieba 等工具。
- 向量化: 常用 TF-IDF 或 Word2Vec 将文本转为数值向量。
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = ["这个产品非常好用", "质量很差,不推荐", "性价比很高"]
vectorizer = TfidfVectorizer(max_features=100, stop_words='english')
X_tfidf = vectorizer.fit_transform(corpus)
print(X_tfidf.shape) # (3, 100)
注意: 文本特征维度通常极高(数千到数万),在特征筛选阶段必须配合降维(如 SVD、LDA)或稀疏矩阵筛选方法,否则会严重拖慢训练速度并引入噪声。
2.5 缺失值处理
缺失值处理是数据预处理中最常见的环节。不同缺失机制与特征类型对应不同策略:
| 缺失机制 | 含义 | 推荐处理方法 |
|---|---|---|
| MCAR | 完全随机缺失 | 直接删除行(缺失率 < 5%)或均值/中位数填充 |
| MAR | 随机缺失(与其他特征相关) | KNN填充、回归填充、多重插补 |
| MNAR | 非随机缺失(与自身值相关) | 单独标记缺失指示列 + 模型填充 |
# 数值特征:中位数填充
df['age'].fillna(df['age'].median(), inplace=True)
# 类别特征:众数填充
df['gender'].fillna(df['gender'].mode()[0], inplace=True)
# 高级:KNN填充
from sklearn.impute import KNNImputer
imputer = KNNImputer(n_neighbors=5)
df_imputed = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)
2.6 数据标准化与归一化
标准化与归一化是消除特征量纲差异的核心手段,直接影响基于距离或梯度的模型(如 SVM、KNN、神经网络)的性能。
| 方法 | 公式 | 输出范围 | 适用模型 |
|---|---|---|---|
| Z-score 标准化 | \( x' = \frac{x - \mu}{\sigma} \) | 均值0,标准差1 | SVM、线性回归、PCA、神经网络 |
| Min-Max 归一化 | \( x' = \frac{x - min}{max - min} \) | [0, 1] | KNN、神经网络(需正区间) |
| Robust 标准化 | \( x' = \frac{x - median}{IQR} \) | 受异常值影响小 | 含异常值的数据集 |
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
# Z-score 标准化
scaler_std = StandardScaler()
X_std = scaler_std.fit_transform(X)
# Min-Max 归一化
scaler_mm = MinMaxScaler()
X_mm = scaler_mm.fit_transform(X)
# Robust 标准化
scaler_rob = RobustScaler()
X_rob = scaler_rob.fit_transform(X)
关键原则: 标准化/归一化的参数(均值、标准差、min、max)必须只在训练集上拟合,然后使用相同的参数转换验证集与测试集,避免数据泄露。
2.7 预处理顺序与最佳实践
特征预处理各步骤之间存在依赖关系,错误的顺序会导致信息泄露或数据失真。推荐的标准流水线如下:
- 缺失值填充(先于所有变换)
- 异常值截断(避免极端值影响后续变换)
- 类别编码(将类别转为数值)
- 文本向量化(若存在文本特征)
- 数值变换(对数/Box-Cox)
- 标准化/归一化(最后一步,确保所有特征在同一尺度)
实战建议: 使用
sklearn.pipeline.Pipeline 将上述步骤封装为可复用的流水线,避免在交叉验证中重复编写代码,同时自动防止数据泄露。
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
])
# 使用流水线
X_processed = preprocessor.fit_transform(X_train)
完成上述预处理后,数据将具备统一的数值尺度、完整的缺失值填充以及正确的特征编码,为后续的特征筛选与模型训练奠定坚实基础。