特征工程是机器学习中非常重要的一步,它可以有效提高模型的性能,特征工程主要包括特征提取、特征变换和特征构造三个方面。
1、特征提取
特征提取是从原始数据中提取特征的过程,常用的特征提取方法包括:
- 基于统计的方法:统计量、相关系数、互信息等
- 基于信息论的方法:如信息增益、卡方检验等
- 基于机器学习的方法:如主成分分析、线性判别分析等
2、特征变化
特征变换是对原始特征进行处理,使其更适合机器学习模型。常用的特征变换方法包括:
- 标准化:将特征值映射到均值为0、方差为1的标准正态分布。
- 归一化:将特征值映射到[0, 1]之间
- 离散化:将连续特征离散化为有限个类别
3、特征构造
特征构造是根据已有特征生成新特征的过程,常用的特征构造方法包括:
- 组合特征:将多个特征组合起来形成新的特征
- 衍生特征:根据已有特征进行计算或变换生成新的特征
- 降维:使用主成分分析、线性判别分析等方法降低特征维度
特征处理事特征工程的核心部分,sklearn提供了较为完整的特征处理方法,包括数据预处理,特征选择,降维等。
数据预处理
数据清洗
涉及检测和处理数据中的缺失值、异常值和重复值,以确保数据的准确性和完整性。
1、缺失值
检测:通过查看数据中的控制、NaN或特定的占位符来检测
处理:删除包含缺失值的行或列;用均值、中位数、众数等填充缺失值或使用插值方法
import pandas as pd
#创建包含缺失值的示例数据集
data={'A':[1,2,None,4],'B':[6,None,8,9]}
df=pd.DataFrame(data)
#删除包含缺失值的行
df.dropna(inplace=True)
#使用均值填充缺失值
df.fillna(df.mean(),inplace=True)
#使用插值方法填充缺失值
df.interpolate(method='linear',inplace=True)
print(df)
df.dropna():用于删除包含缺失值的行或列的方法,inplace=True,表示对原始数据框进行就地修改
df.fillna():用于填充缺失值的方法
df.interpolate():用于在数据中进行插值操作,可以根据已知的数据点的位置和值来预测缺失值的值,并将插值后的值填充到缺失值的位置。
使用preproccessing库的Imputer类对数据进行缺失值计算的代码如下:
from sklearn.impute import SimpleImputer
# 假设 data 是你的 DataFrame 或数组
# 创建一个 SimpleImputer 实例来替换缺失值
imputer = SimpleImputer(strategy='mean')
# 使用 imputer 来转换数据
data_transformed = imputer.fit_transform(data)
# 现在 data_transformed 中的缺失值已经被替换为均值
2、异常值
旨在识别和处理数据中的异常、离群值或者错误值。常见的处理方法:删除异常值、替换异常值、截断处理、缩放/标准化处理、使用插值方法、使用统计模型。
3、重复值
旨在识别和处理数据中的重复观测值,处理方法:删除重复值(df.drop_duplicates())、替换重复值(df.replace())、标记重复值(df.duplicated() ,将结果赋值给新的列,如果重复为True,反之为False)、合并重复值( df.groupby()结合合适的聚合函数(如求和、平均值等)来合并重复记录 )
import pandas as pd
# 创建包含重复行的示例数据
data = {'A': [1, 2, 3, 4, 2, 3, 1],
'B': ['a', 'b', 'c', 'd', 'b', 'c', 'a']}
df = pd.DataFrame(data)
# 打印原始数据
print("原始数据:")
print(df)
# 删除重复行
df = df.drop_duplicates()
4、特征缩放
采用sklearn中的preproccessing库进行数据预处理,通过特征提取,会得到未经处理的特征,这些特征会存在以下的一些问题:
不属于同一量纲:使用的单位或度量标准不同,不能直接进行比较或加减乘除运算,无量纲化可解决该问题。
常见的无量纲化方法有标准化和区间缩放法,标准化的前提是特征值服从正态分布,标准化后,转化成标准正态分布;区间缩放法利用边界值信息,将特征的取值区间缩放到某个范围,例如【0,1】等。
标准化:需要计算特征的均值和标准差
公式如下:
代码表示:
from sklearn.preprocessing import StandardScaler
#标准化,返回值为标准化后的数据
StandardScaler().fit_transform(data)
最大-最小缩放法:
最常见的是利用两个最值进行缩放
公式如下:
代码表示:
from sklearn.preprocessing import MinMaxScaler
#区间缩放,返回值为缩放到[0, 1]区间的数据
MinMaxScaler().fit_transform(data)
归一化:
normalization,通过将每个样本的特征向量转换成单位长度进行缩放
from sklearn.preprocessing import Normalizer
import numpy as np
# 原始特征向量
X = np.array([[3, 4]])
# 创建Normalizer对象
normalizer = Normalizer(norm='l2')
# 使用transform进行正规化
X_normalized = normalizer.transform(X)
5、特征编码
信息冗余:特征包含的有效信息为区间划分,对定值特征二值化(特征可能原本是连续的值,但是可能只需要知道其属于什么区间,所以可以对其设定一个阈值,按照阈值划分)
使用preproccessing库的Binarizer类对数据进行二值化的代码如下:
from sklearn.preprocessing import Binarizer
#二值化,阈值设置为3,返回值为二值化后的数据
Binarizer(threshold=3).fit_transform(data)
对特征进行独热编码:将定性特征转换为定量特征,假设有N种定性值,则将这一个特征扩展为N种特征,当原始特征值为第i种定性值时,第i个扩展特征赋值为1,其他扩展特征赋值为0,独热编码的方式相比直接制定的方式,不用增加调参的工作,对于线性模型来说,使用独热编码后的特征可达到非线性的效果。
from sklearn.preprocessing import OneHotEncoder
#哑编码,对IRIS数据集的目标值,返回值为哑编码后的数据
OneHotEncoder().fit_transform(data.reshape((-1,1)))
6、特征变化
常见的特征变换方法包括多项式特征、对数变换、指数变换。
①多项式特征:通过将原始特征进行多项式组合来生成新的特征。这种方法可以捕捉特征之间的非线性关系
②对数变换:
import numpy as np
# 原始数据
area = np.array([1000, 1500, 2000, 2500, 3000])
price = np.array([50, 75, 100, 125, 150])
# 对数变换
log_price = np.log10(price)
③指数变换:指数变换是一种常见的数据转换方法,用于改变数据的分布或减小数据的尺度。它通过取数据的指数来转换原始数据,从而改变数据的相对大小关系。
# 原始数据
time = np.array([1, 2, 3, 4, 5])
storage = np.array([10, 6, 3, 2, 1])
# 指数变换
exp_storage = np.exp(storage)
对定量变量多项式化,或者进行其他的转换,都能达到非线性的效果。
常见的数据变换有基于多项式的、基于指数函数的、基于对数函数的
使用preproccessing库的PolynomialFeatures类对数据进行多项式转换
基于单变元函数的数据变换可以使用一个统一的方式完成,使用preproccessing库的FunctionTransformer对数据进行对数函数转换
7、时间序列特征提取
常见的时间序列包括:滞后特征、移动平均特征、时序特征
1、滞后特征
滞后特征基于时间序列数据中当前时刻与过去时刻之间的关系,将过去时刻的观测值作为特征
import pandas as pd
# 创建示例时间序列数据
data = pd.DataFrame({
'日期': ['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04', '2022-01-05'],
'销售额': [100, 120, 90, 110, 130]
})
# 将日期列转换为日期时间类型
data['日期'] = pd.to_datetime(data['日期'])
# 添加一阶滞后特征
data['lag_1'] = data['销售额'].shift(1)
2、移动平均特征
移动平均特征基于时间序列数据中一定窗口内观测值的平均值,用于捕捉时间序列的趋势和平滑数据。基本思想:使用一组连续观测值的平均值来代表当前时刻的特征,通过滑动窗口的方式,移动平均特征可以在不同尺度上捕捉时间序列的趋势和周期性。
import pandas as pd
# 创建示例时间序列数据
data = pd.DataFrame({
'日期': ['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04', '2022-01-05'],
'销售额': [100, 120, 90, 110, 130]
})
# 将日期列转换为日期时间类型
data['日期'] = pd.to_datetime(data['日期'])
# 计算简单移动平均特征
window_size = 7 # 窗口大小为7天
data['moving_avg'] = data['销售额'].rolling(window=window_size).mean()
3、时序特性
时序特性指:从时间序列数据中提取的用于描述、表示和分析数据的特征。时序特征可以包括多个方面,例如趋势、周期性、季节性、周期长度、时间延迟等。
import pandas as pd
import statsmodels.api as sm
# 创建示例时间序列数据
data = pd.DataFrame({
'日期': ['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04', '2022-01-05'],
'气温': [15, 18, 20, 16, 22]
})
# 将日期列转换为日期时间类型
data['日期'] = pd.to_datetime(data['日期'])
# 提取趋势特征
X_trend = sm.add_constant(range(len(data)))
model_trend = sm.OLS(data['气温'], X_trend)
results_trend = model_trend.fit()
trend_slope = results_trend.params[1] # 趋势斜率
# 提取周期性特征
X_period = sm.add_constant(range(len(data)))
model_period = sm.OLS(data['气温'], X_period)
results_period = model_period.fit()
period_frequency = 1 / results_period.params[2] # 周期频率
# 提取季节性特征
seasonal_decomposition = sm.tsa.seasonal_decompose(data['气温'], period=1)
seasonal_index = seasonal_decomposition.seasonal
# 提取自回归特征
lag_values = [1, 2, 3] # 指定滞后观测值的数量
lag_features = []
for lag in lag_values:
lag_feature = data['气温'].shift(lag)
lag_features.append(lag_feature)
data['lag_1'] = lag_features[0]
data['lag_2'] = lag_features[1]
data['lag_3'] = lag_features[2]
# 提取统计特征
mean_temperature = data['气温'].mean()
var_temperature = data['气温'].var()
max_temperature = data['气温'].max()
min_temperature = data['气温'].min()
8、组合特征
组合特征是指通过多个原始特征进行组合、衍生或转换,创建新的特征。目的:增加模型对数据的表达能力,捕捉更多的信息和非线性关系。
①特征交叉:是通过将两个或多个特征进行组合、衍生或转换,创建新的特征。目的:捕捉特征之间的相互影响或交互关系,从而提高模型的表达能力。
import pandas as pd
# 示例数据集
data = {'feature1': [3, 4, 5, 6],
'feature2': [6, 7, 8, 9]}
df = pd.DataFrame(data)
# 特征交叉
df['feature_cross'] = df['feature1'] * df['feature2']
②特征合并
将不同特征组合在一起形成新的特征向量或特征矩阵的过程。
③特征降维
特征选择完成后,可能会出现由于特征矩阵过大,导致计算量大,训练时间长的问题,所以需要降低特征矩阵维度,常见的降维方法有:基于L1惩罚项的模型、PCA主成分分析法、LDA线性判别分析。
PCA:是为了让映射后的样本具有最大的发散性(无监督)
使用decomposition库的PCA类选择特征
from sklearn.decomposition import PCA
#主成分分析法,返回降维后的数据
#参数n_components为主成分数目
PCA(n_components=2).fit_transform(iris.data)
LDA:是为了让映射后的样本有最好的分类能力(有监督)
使用Ida库的LDA类选择特征
from sklearn.lda import LDA
#线性判别分析法,返回降维后的数据
#参数n_components为降维后的维数
LDA(n_components=2).fit_transform(iris.data, iris.target)
特征选择
当数据预处理完成后,需要选择有意义的特征输入算法模型进行训练,可以从两个方面考虑来选择特征:
①特征是否发散:如果一个特征不发散,例如方差接近于0,也就是说样本在这个特征上基本没有差异,这个特征对于样本的区分并没有什么用。
②特征与目标的相关性:与目标相关性高的特征,应当优先选择。
根据特征选择的形式可以将特征选择分为3种:
①filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征
方差选择法
先计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征
使用feather_selection库中的variance threshold类来选择特征
from sklearn.feature_selection import VarianceThreshold
#方差选择法,返回值为特征选择后的数据
#参数threshold为方差的阈值
VarianceThreshold(threshold=3).fit_transform(data)
相关系数法
先计算各个特征对目标值的相关系数以及相关系数的P值
使用feature_selection库的SelectKBest类结合相关系数来选择特征
from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
#选择K个最好的特征,返回选择特征后的数据
#第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,输出二元组(评分,P值)的数组,数组第i项为第i个特征的评分和P值。在此定义为计算相关系数
#参数k为选择的特征个数
SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
卡方检验
检验定性自变量对定性因变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距,构建统计量
使用feature_selection库的SelectKBest类结合卡方检验来选择特征
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#选择K个最好的特征,返回选择特征后的数据
SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)
互信息法
使用feature_selection库的SelectKBest类结合最大信息系数法来选择特征
from sklearn.feature_selection import SelectKBest
from minepy import MINE
#由于MINE的设计不是函数式的,定义mic方法将其为函数式的,返回一个二元组,二元组的第2项设置成固定的P值0.5
def mic(x, y):
m = MINE()
m.compute_score(x, y)
return (m.mic(), 0.5)
#选择K个最好的特征,返回特征选择后的数据
SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
②wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征
递归特征消除法
使用一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练
使用feature_selection库的RFE类来选择特征
③embedded:嵌入法,先使用某种机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征
基于惩罚项的特征选择法
除了筛选出特征外,同时也进行了降维
feature_selection库的SelectFromModel类结合带L1惩罚项的逻辑回归模型来选择特征
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#带L1惩罚项的逻辑回归作为基模型的特征选择
SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(iris.data, iris.target)
L1惩罚项降维的原理在于保留多个对目标具有同等相关性的特征中的一个,没选到的特征不代表不重要,所以可以结合L2惩罚项来优化。操作:若一个特征在L1中的权值为1,选择在L2中权值差别不大且在L1中权值为0的特征构成同类集合,将这个集合中的特征平分L1中的权重。
使用feature_selection库的SelectFromModel类结合带L1以及L2惩罚项的逻辑回归模型来选择特征
from sklearn.feature_selection import SelectFromModel
#带L1和L2惩罚项的逻辑回归作为基模型的特征选择
#参数threshold为权值系数之差的阈值
SelectFromModel(LR(threshold=0.5, C=0.1)).fit_transform(iris.data, iris.target)
基于树模型的特征选择法
GBDT可以作为基模型进行特征选择
使用feature_selection库的SelectFromModel类结合GBDT模型来选择特征
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
#GBDT作为基模型的特征选择
SelectFromModel(GradientBoostingClassifier()).fit_transform(iris.data, iris.target)