机器学习中的特征工程:实用指南

更新于 2026-02-05

Srujana Maddula 2025-03-19

特征工程的核心在于选择或创建能够提升模型性能的重要特征。无论你使用哪种机器学习算法,几乎都会依赖特征工程技术来进行数据准备。

在本文中,我们将深入探讨特征工程及其常用方法,并通过一个房价预测的实战案例,手把手教你如何应用这些技术。

什么是机器学习中的特征工程?

我记得曾在工作中参与一个“运输时效”项目,目标是提高准时交付率。我们没有训练复杂的集成模型,而是仅使用了一个简单的回归算法,并从现有数据中额外衍生出三个新特征。

仅凭这一做法,我们的准时交付率就从48%提升到了56%。考虑到数据量高达一千万条记录,这已经是巨大的进步了!由此可见,像特征提取这样的特征工程技术能带来多么显著的效果!

简单来说,特征工程就是从现有数据中挑选出合适的特征。

例如,假设你有一个天气数据集,包含温度、地点、月份、年份和日期等列。其中“日期”列对于捕捉季节性趋势可能并没有太大价值,因为“月份”列已经提供了足够的季节信息。此时,删除“日期”列可以在不影响天气预测准确性的前提下,降低数据集的维度。

机器学习中的特征类型

在深入各种特征工程技术之前,我们先来了解机器学习中常见的特征类型。

数值型特征(Numerical features)

顾名思义,数值型特征以数字形式表示数据,属于连续的定量变量。例如身高、年龄和薪资等。

类别型特征(Categorical features)

类别型列只能包含离散的取值。例如,一个人的性别是一个类别型列,因为它只能有少数几种性别类型;出生月份也是类别型特征,因为其取值必须在1月到12月之间。

类别型变量还可进一步分为二元类别多元类别。二元类别只有两种可能取值,而多元类别则可以有多个取值。

文本型与时间序列特征(Textual and time-series features)

文本型列仅包含文本数据,例如零售数据集中的商品评论或商品描述列。

另一方面,时间序列特征表示随时间变化的数据,例如每周销售额或一年内的股价波动。

机器学习中的特征类型

特征工程技术

特征工程提供了多种强大的技术,可将原始列转换为理想的特征。下面我们将讨论一些主流方法。

处理缺失值

缺失值会扭曲模型性能,因此妥善处理至关重要。主要有两种方法:

  • 插补(Imputation):利用已有信息填充缺失值。例如,可以用均值、众数或中位数来替代缺失值。
  • 删除(Deletion):直接删除含有缺失值的行,适用于缺失数据占比小于10%的情况。

处理异常值(Outliers)

异常值是指明显偏离其他数据点的异常数值。例如,在一个薪资数据集中,大多数观测值在9万至12万美元之间,那么40万美元或1万美元的薪资就属于异常值。

处理方法包括:

  • 替换:用统计值(如列的最大值或最小值)替换异常值。
  • 变换:应用对数(log)或平方根等变换,以减轻异常值的影响。
  • 使用鲁棒模型:某些模型对异常值不敏感,如决策树、梯度提升和岭回归。
  • 删除:如果上述方法都不奏效,最后的选择是直接从数据集中剔除异常值。

编码类别型变量

机器学习模型无法直接处理类别型变量,因此必须将其转换为数值形式。以下是几种常用的编码技术:

独热编码(One-hot encoding)

为类别型特征中的每个类别创建一个独立的列,若样本属于该类别,则对应列为1,其余为0。

例如,考虑以下包含“性别”列的数据集:

Name Gender
John Male
Rachel Female
Emma Female

经独热编码后,得到:

Name Female Male
John 0 1
Rachel 1 0
Emma 1 0

由于John是男性,“Male”列为1,“Female”列为0;Rachel和Emma是女性,则相反。

标签编码(Label encoding)

为类别型特征中的每个类别分配一个唯一的数值。这种方法适用于有序数据(类别之间存在有意义的顺序),但用于无序类别时可能导致模型误认为数值大小代表类别等级。

例如,某数据集中“Location”列包含以下值:

Location Encoded value
New York 1
California 2
Texas 3
California 2
Texas 3

虽然California被编码为2,New York为1,Texas为3,但实际上California并不“介于”New York和Texas之间。因此,对无序类别使用标签编码可能误导模型。此时应优先使用独热编码,以避免引入虚假的数值关系。

序数编码(Ordinal encoding)

与标签编码类似,但专门用于有序类别。它根据类别的实际排序分配数值,确保高排名类别对应更高的数值。

例如,“教育水平”列:

Education level Encoded value
UG (本科) 1
PG (硕士) 2
PhD (博士) 3

由于博士学历高于硕士,硕士高于本科,因此数值分配反映了这一层级关系。

目标编码(Target encoding)

用每个类别对应的目标变量均值来替代原始类别值。目标变量即模型试图预测的因变量。该方法特别适用于高基数类别特征(即具有大量唯一值的类别),可在降低维度的同时保留相关信息。

例如,某数据集中“Location”为类别特征,“Target variable”为数值型目标变量:

Location Target variable
New York 2
California 3
Texas 5
California 1
Texas 4

对“Location”进行目标编码时,计算每个类别的目标变量均值:

  • California: (3 + 1) / 2 = 2
  • Texas: (5 + 4) / 2 = 4.5
  • New York: 仅一个值(2),故为2

编码结果如下:

Location Encoded value
New York 2
California 2
Texas 4.5
California 2
Texas 4.5

特征缩放(Feature scaling)

特征缩放确保数值型特征落在标准化范围内,防止某些特征因其数值较大而在学习过程中占据主导地位。

依赖距离计算的模型(如线性回归、K近邻、神经网络)在特征尺度差异较大时容易受到影响。

例如,员工数据集中:

  • 年龄范围:20–60
  • 收入范围:3万–15万美元

由于收入数值远大于年龄,模型可能仅因尺度原因而赋予收入更高权重,而非其实际相关性更强。

常用缩放方法包括:

  • 归一化(Min-Max Scaling):将所有特征值缩放到0–1区间。公式为:

    Scaled value=datapointmin(column)max(column)min(column)\text{Scaled value} = \frac{\text{datapoint} - \min(\text{column})}{\max(\text{column}) - \min(\text{column})}
  • 标准化(Z-score Scaling):将特征转换为均值为0、标准差为1的分布。公式为:

    Scaled value=datapointmean(column)std(column)\text{Scaled value} = \frac{\text{datapoint} - \text{mean(column)}}{\text{std(column)}}

创建新特征

从现有数据中创建新的、有意义的特征,能为模型提供更直观的洞察。

例如,在房价预测数据集中,若已有“长度”和“宽度”两列,可衍生出新特征:面积 = 长度 × 宽度。该特征可能与目标变量“价格”直接相关,输入模型后有助于发现隐藏模式。

特征选择(Feature selection)

特征选择通过移除无关列,仅保留相关特征。聚焦于最具信息量的数据有助于防止过拟合、降低计算复杂度并提升模型性能。常用方法包括:

  • 过滤法(Filter methods):基于统计特性选择重要特征。例如,可通过相关性热力图去除信息冗余的特征。其他技术包括卡方检验、ANOVA和信息增益等。
  • 包装法(Wrapper methods):通过迭代训练不同特征子集的模型,选择性能最优的子集。前向选择、后向选择和递归特征消除均属此类。

Python中的特征工程:实战示例

特征工程最好通过动手实践来理解。

我们选用著名的“房价预测”数据集——该数据集规模庞大,包含81列,特征类型丰富,非常适合用于演示各种特征工程技术。

入门步骤:

  1. Kaggle下载数据集。
  2. 使用Pandas加载为DataFrame,进行分析与特征工程。

处理类别型缺失值

以下代码识别数据集中的类别型列,并用最频繁出现的类别(众数)填充缺失值:

import pandas as pd

# 加载数据集(将 'your_file.csv' 替换为实际文件名)
df = pd.read_csv('your_file.csv')

# 选择类别型列
categorical_cols = df.select_dtypes(include=['object']).columns

# 用最频繁类别(众数)填充缺失值
for col in categorical_cols:
    mode = df[col].mode()[0]  # 获取最常见值
    df[col].fillna(mode, inplace=True)  # 填充缺失值

处理数值型缺失值

数值型缺失值通常用均值或中位数填充。均值适用于分布较均匀的数据,而中位数在存在异常值时更稳健。因此,我们先检测异常值再决定方法。

可通过箱线图可视化潜在异常值。以下Python代码用于检测指定数值列中的异常值:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

features = ['LotFrontage', 'MasVnrArea', 'GarageYrBlt']  

# 对特征取对数(便于观察)
df[features] = np.log(df[features])
df[features].boxplot(figsize=(8, 4))

plt.title('Box Plot for Outlier Detection')
plt.ylabel('Values')
plt.xticks(rotation=45)
plt.show()

输出:
异常值检测箱线图

上图中箱线外的点即为异常值。因此,我们使用中位数填充缺失值:

import pandas as pd

# 选择数值型列
numerical_columns = df.select_dtypes(include=['number']).columns

# 用中位数填充缺失值
for col in numerical_columns:
    median = df[col].median()  
    df[col].fillna(median, inplace=True)

创建新特征

“YearBuilt”、“YearRemodAdd”、“GarageYrBlt”和“YrSold”等列包含年份(如2001、1976),这些绝对年份本身对房价影响有限。但我们可以计算房屋或翻新的“年龄”,从而获得更有意义的信息。

例如,用“YrSold − YearBuilt”创建“House Age”(房龄)特征。

# 获取包含 'Yr' 或 'Year' 的列
year_columns = [feature for feature in numerical_columns if 'Yr' in feature or 'Year' in feature]

# 将年份转换为年龄相关特征
for col in year_columns:
    df[col] = df['YrSold'] - df[col]

特征变换

在机器学习中,偏态(skewed)的数值特征会负面影响模型性能,尤其对假设正态分布的模型(如线性回归)。为此,我们采用对数变换进行校正。

首先需识别偏态特征,但需排除含零值的列(因为log(0)无定义)。

以下代码用于识别偏态列:

import pandas as pd

# 获取数值型列
numerical_columns = df.select_dtypes(include=['number']).columns

# 找出包含零值的列
numerical_0s = df.loc[:, (df == 0).any()].select_dtypes(include=['number']).columns

# 排除含零列
numerical_columns = numerical_columns.difference(numerical_0s)

# 计算剩余数值列的偏度
skewness = df[numerical_columns].skew()

# 设定偏度阈值(如绝对值 > 1 表示高度偏态)
skewed_columns = skewness[abs(skewness) > 1]

# 输出偏态列
print("Skewed Columns:")
print(skewed_columns)

输出

img

我们将对以下五个高度偏态的特征应用对数变换,使其接近高斯分布:

import numpy as np

# 高度偏态特征列表
skew_features = ['LotFrontage', 'LotArea', '1stFlrSF', 'GrLivArea', 'SalePrice']

# 对每个偏态特征应用对数变换
for col in skew_features:
    df[col] = np.log(df[col])

将类别型特征转换为数值型

前文介绍了多种编码方法,本例中我们采用目标编码

# 选择类别型变量
categorical_columns = df.select_dtypes(include=['object', 'category']).columns

# 应用目标编码
for col in categorical_columns:
    # 按类别分组,计算 SalePrice 均值并排序
    labels_ordered = df.groupby([col])['SalePrice'].mean().sort_values().index
    
    # 为每个类别分配数值(按均值排序后的索引)
    labels_ordered = {x: i for i, x in enumerate(labels_ordered, 0)}
    
    # 将编码值映射回DataFrame
    df[col] = df[col].map(labels_ordered)

上述代码中,目标变量为“SalePrice”。我们按每个类别分组,计算其对应的平均房价,并将该均值作为该类别的编码值。

至此,我们的数据集已准备好用于机器学习!

特征工程工具与库

本节介绍最常用的Python库和自动化工具。

Pandas

Pandas是处理结构化数据最常用的Python框架,支持多种特征工程操作,如变换、数据聚合和特征提取,也使数据清洗与操作变得简单。

Scikit-Learn

Scikit-learn是功能强大的机器学习库,提供多种特征工程工具,如OneHotEncoderLabelEncoder用于类别转数值,以及StandardScalerMinMaxScaler用于特征缩放。

Feature-Engine

Feature-engine是一个开源Python库,提供多种专用转换器(transformers)以简化特征工程,包括缺失值插补、异常值处理、特征选择和离散化等。这些转换器完全兼容scikit-learn,可作为超参数调优的输入参数。

自动化特征工程工具

  • Featuretools:开源库,用于自动化特征工程,特别适用于关系型数据库。其核心是深度特征合成(DFS)算法,通过变换和聚合操作自动生成新特征。
  • TSFresh:全称“Time Series Feature Extraction based on Scalable Hypothesis Tests”,专为时间序列数据设计,通过假设检验筛选统计显著的特征。
  • Autofeat:自动执行特征选择、创建与变换以提升线性模型精度。例如,其fit_transform()方法可同时完成拟合与变换。还提供FeatureSelectorAutoFeatLight模型用于特征选择与缩放。

特征工程最佳实践

要高效实施特征工程,请遵循以下最佳实践:

了解你的数据

理解每个特征的含义与重要性,能让你更轻松地执行特征选择或提取。建议深入研究数据及其相关领域知识。

进行探索性数据分析(EDA)

利用Pandas、Matplotlib等库进行全面的EDA,包括统计信息、可视化和相关性分析,以发现数据中的模式与潜在关系。

创建交互特征

交互特征指通过现有特征之间的关系衍生新特征。例如,在房价预测中,用“出售年份 − 建造年份”计算房龄,可揭示“房价随时间推移而下降”的趋势。

提前选定模型

不同机器学习模型对特征工程的需求不同。例如,线性回归、SVM和KNN通常受益于特征标准化,但树模型对此无感。因此,提前确定模型有助于构建高效的特征工程流水线。

结语

特征工程是构建机器学习解决方案不可或缺的一环,能帮助你以最高效的方式利用特征。无论是数据科学家还是机器学习工程师,在处理任何数据集时都会进行特征工程。如果你是数据从业者,或希望成为其中一员,掌握本文所述的所有技术将极大助力你的职业发展!