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 文本特征预处理

文本特征需要经过分词、清洗、向量化三步才能进入特征矩阵。核心流程如下:

  1. 文本清洗: 去除标点、数字、停用词,统一小写。
  2. 分词: 英文按空格分词,中文使用 jieba 等工具。
  3. 向量化: 常用 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)必须只在训练集上拟合,然后使用相同的参数转换验证集与测试集,避免数据泄露。
特征预处理与标准化流程 特征预处理与标准化流程 原始数据集 数值特征处理 类别特征编码 文本向量化 异常值截断 对数/Box-Cox变换 One-Hot / Target编码 分词 + 清洗 TF-IDF / Word2Vec 缺失值填充(均值/中位数/KNN) 标准化 / 归一化(Z-score / Min-Max)

2.7 预处理顺序与最佳实践

特征预处理各步骤之间存在依赖关系,错误的顺序会导致信息泄露或数据失真。推荐的标准流水线如下:

  1. 缺失值填充(先于所有变换)
  2. 异常值截断(避免极端值影响后续变换)
  3. 类别编码(将类别转为数值)
  4. 文本向量化(若存在文本特征)
  5. 数值变换(对数/Box-Cox)
  6. 标准化/归一化(最后一步,确保所有特征在同一尺度)
实战建议: 使用 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)

完成上述预处理后,数据将具备统一的数值尺度、完整的缺失值填充以及正确的特征编码,为后续的特征筛选与模型训练奠定坚实基础。