一、特征工程的概念
特征工程是机器学习中的一个重要概念,它是从原始数据中提取和构建对模型预测任务更有用的特征的过程。特征工程的目的是提高模型的性能,使其能够更准确地捕捉到数据中的关键信息,合适的特征选择和转换可以帮助模型在新的、未见过的数据上表现更好,减少过拟合的风险。
二、常见的特征工程方法
1、特征选择
特征选择是机器学习中的一项重要任务,目的是从诸多的特征中选择出对建模真正有意义的特征,从而减少特征维度、提升建模效果。试想有一份数据,每个样本都有1000个特征,我们必然不会直接使用这1000个特征进行建模,因为过多的特征维度不管从计算效率还是模型效果上都有着很大的劣势。这时候,我们可以通过一些恰当的特征选择方法选择出对建模真正有用的(即与标签分布强相关)特征,或许是10个特征,也或许是20个,但都比直接使用1000个特征建模好多了。
(1)过滤法(Filter)
过滤法是一种快速的特征选择方法,它基于统计测试来评估每个特征与目标变量之间的关系。常见的过滤法包括:
- 方差选择法(Variance Threshold):去除方差小于某个阈值的特征,因为低方差的特征可能不包含太多信息。
- 相关系数法:选择与目标变量相关性最强的特征。
- 卡方检验(Chi-squared test):评估类别特征与目标变量之间的独立性。
- 互信息法:选择与目标变量互信息量最大的特征。
(2)包裹法(Wrapper)
包裹法将特征选择过程视为搜索问题,通过候选特征子集的评估来找到最佳特征集合。这种方法通常使用模型的性能作为特征子集的评价标准。常见的包裹法包括:
- 递归特征消除(Recursive Feature Elimination, RFE):递归地考虑越来越小的特征集。
- 前向选择:从空集开始,逐渐添加特征,直到满足某个条件。
- 后向消除:从全集开始,逐渐删除最不重要的特征。
(3)嵌入法(Embedded)
嵌入法在模型训练过程中进行特征选择。一些模型,如决策树和正则化线性模型,能够提供特征的重要性评分,这些评分可以用于特征选择。常见的嵌入法包括:
- 基于模型的特征选择:使用模型系数的大小来选择特征。
- L1正则化:通过将特征系数压缩至零来选择特征。
2、特征构造
特征构造是特征工程中的一个重要环节,它从原始数据中创建新的特征,以提高机器学习模型的性能。特征构造的原理基于对数据的深入理解,包括数据的业务背景、统计特性和潜在的模式。常见的特征构造方法有:
(1)转换:将现有特征转换为新的形式,以更好地捕捉数据的模式。例如,对数变换、平方根变换或归一化等。一些机器学习/深度学习模型训练之前,都需要将特征归一化/标准化,这是为了避免特征取值量纲差异对模型产生太大影响。
(2)聚合:通过对数据的不同部分进行聚合操作来创建新特征,比如计算时间序列数据的滑动平均值。
(3)组合:将多个特征组合成一个新的特征,以揭示它们之间的关系。比如组合两个特征进行相加、相乘或计算比率。
(4)分解:将单个特征分解为多个特征,以增加模型的解释力。
(5)编码:将类别特征转换为数值形式,如独热编码(One-Hot Encoding)或标签编码(Label Encoding)。
(6)差分:计算特征之间的差异,以提取变化率或趋势信息。
(7)降维:通过方法如主成分分析(PCA)、UMAP降维来减少特征的数量,同时尽量保留原始数据的信息。
三、python应用示例
1、特征选择
这里使用卡方检验作为特征选择的示例:
from sklearn.feature_selection import SelectKBest, chi2
from sklearn.datasets import load_iris
# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target
# 使用卡方检验选择特征
selector = SelectKBest(chi2, k=2)
X_new = selector.fit_transform(X, y)
# 输出选择的特征
print("Selected features: ", iris.feature_names[selector.get_support()])
2、特征构造
假设有一个关于二手车的数据集,我们想要构造新的特征来预测车辆的价格,可以进行以下特征的构造:计算车龄;计算里程与车龄的比率;根据车辆的功率和排量构造新特征;对品牌、燃油类型和变速箱类型进行独热编码;对车型进行标签编码;从注册日期中提取年份;根据是否有损伤构造二值特征等。
import pandas as pd
import numpy as np
# 创建一个示例 DataFrame
data = {
'first_registered': [2010, 2012, 2015, 2017, 2019], # 首次注册年份
'mileage': [50000, 30000, 20000, 15000, 5000], # 里程
'power': [100, 150, 120, 180, 160], # 功率
'displacement': [1.6, 2.0, 1.4, 1.8, 2.5], # 排量
'brand': ['BrandA', 'BrandB', 'BrandA', 'BrandC', 'BrandB'], # 品牌
'fuel_type': ['Diesel', 'Petrol', 'Diesel', 'Petrol', 'Hybrid'], # 燃油类型
'transmission': ['Manual', 'Automatic', 'Manual', 'Automatic', 'Automatic'], # 变速箱类型
'category': ['Compact', 'SUV', 'Sedan', 'Hatchback', 'Coupe'], # 车型
'damage': [0, 0, 1, 0, 0], # 是否有损伤
'registration': ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05'] # 注册日期
}
df = pd.DataFrame(data)
# 计算车龄
df['age'] = 2024 - df['first_registered']
# 计算里程与车龄的比率
df['mileage_age_ratio'] = df['mileage'] / df['age']
# 根据车辆的功率和排量构造新特征
df['power_to_volume_ratio'] = df['power'] / df['displacement']
# 将类别特征进行独热编码
df_encoded = pd.get_dummies(df, columns=['brand', 'fuel_type', 'transmission'])
# 标签编码
df['category_label'] = df['category'].astype('category').cat.codes
# 特征拆解
df['registration_year'] = df['registration'].str[:4]
# 特征二值化
df['has_damage'] = (df['damage'] > 0).astype(int)
# 输出结果
print(df)
print(df_encoded)
这些新特征可以用于训练机器学习模型,当然,新特征同样需要通过特征选择方法评估是否有效,并非所有构造的新特征都对模型的训练起到正面作用。
四、总结
笔者所介绍的特征工程方法主要是对特征进行选择和构造的过程,但需要注意的是,在进行特征工程之前的数据清洗是必不可少的一步(也可以把数据清洗看成是特征工程的一部分,而且是第一步)。对数据进行清洗,去空值、去非法值、去无效字段、删除诸如“序号”和“ID”等不相关特征之后,才能让数据保持比较干净的状态(俗话说“Garbage in,Garbage out”)。然后再进行特征工程才能起到事半功倍的效果。