机器学习技术(四)——特征工程与模型评估

机器学习技术(四)——特征工程与模型评估(1️⃣)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9nP9coPh-1689079280130)(D:\文件\CSDN\华为实训\机器学习基础\特征工程与模型调优\特征工程与模型调优.png)]

🚀机器学习技术(四)包含了十二种特征工程的应用方法,主要包括标准化,特征缩放,缩放有离群的值的数据,非线性转换,样本归一化,特征二值化,one-hot编码,缺失值插补以及生成多项式特征等步骤。

🚢通过这些步骤可以显著提高数据的质量。同时,实验包含了基于Python代码的对特征集进行筛选的多种方法。一个典型的机器学习任务,是通过样本的特征来预测样本所对应的值。而现实中的情况往往是特征太多了,需要减少一些特征。

🚢减少特征具有重要的现实意义,不仅减少过拟合、减少特征数量(降维)、提高模型泛化能力,而且还可以使模型获得更好的解释性,增强对特征和特征值之间的理解,加快模型的训练速度,一般的,还会获得更好的性能。基于sklearn自带数据集iris,应用多种特征筛选方法进行特征选择。

🚀包含关于几个评估模型指标的参数计算及其原理。在日常业务有中,当我们训练模型时常常需要在多个模型中选择出最优模型,因此本实验中precision, recall rate等参数就成为评判的依据,帮助我们选择和评价模型表现。

一、特征工程

在实际应用中,数据往往都需要进行预处理,提高数据质量,也有利于后续数据分析以及挖掘,

主要包括标准化,特征缩放,缩放有离群的值的数据,非线性转换,样本归一化,特征二值化,one-hot编码,缺失值插补以及生成多项式特征等步骤。通过这些步骤可以显著提高数据的质量。基于Python代码的对特征集进行筛选的多种方法

1、标准化

导入相关库,并自定义训练集数据以及测试集数据

from sklearn import preprocessing
import numpy as np

X_train = np.array([[ 1., -1.,  -2.],
                    [ 2.,  0.,  0.],
                    [ 3.,  1., -1.]])
X_test = [[-1., 1., 0.]]

将每组特征减去均值并除以标准差,使得均值为0,方差为1

#计算数据集的尺度(也就是数据集的均值和方差)(各列)
scaler = preprocessing.StandardScaler().fit(X_train)   # 计算均值和方差
print('均值:',scaler.mean_ )
print('方差:',scaler.scale_ )

#通过尺度去处理另一个数据集,当然另一个数据集仍然可以是自己。
X_scaled = scaler.transform(X_train)
print('均值:',X_scaled.mean(axis=0))  # transform会转化数据集为均值为0
print('方差:',X_scaled.std(axis=0))   # transform会转化数据集为方差为1

#上面两步的综合:缩放样本,是样本均值为0,方差为1(各列)
X_scaled = preprocessing.scale(X_train,axis=0)      # 标准化:去均值和方差
print('均值:',X_scaled.mean(axis=0))
print('方差:',X_scaled.std(axis=0))

均值以及方差以及标准化后均值以及方差显示如下

均值: [ 2.  0. -1.]
方差: [0.81649658 0.81649658 0.81649658]
均值: [0. 0. 0.]
方差: [1. 1. 1.]
均值: [0. 0. 0.]
方差: [1. 1. 1.]

2、特征缩放

计算样本和数据集中所有已知标签样本的欧氏距离并排序进行投票。

MinMaxScaler将特征缩放至特定范围内(默认为0-1)

min_max_scaler = preprocessing.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train)  # 训练同时转换
print('每列最大值:',X_train_minmax.max(axis=0))   # 每列最大值为1
print('每列最小值:',X_train_minmax.min(axis=0))    # 每列最小值为0

X_test_minmax = min_max_scaler.transform(X_test)   # 转换实例应用到测试数据:实现和训练数据一致的缩放和移位操作:

#MaxAbsScaler通过除以每个特征的最大值将训练数据特征缩放至 [-1, 1] 范围内。可以应用在稀疏矩阵上保留矩阵的稀疏性。
X_train = np.array([[ 0., -1.,  0.],
                    [ 0., 0.,  0.2],
                    [ 2.,  0., 0]])
max_abs_scaler = preprocessing.MaxAbsScaler()
X_train_maxabs = max_abs_scaler.fit_transform(X_train)
print('每列最大值:',X_train_maxabs.max(axis=0))   # 每列最大值为1
print('每列最小值:',X_train_maxabs.min(axis=0))    # 每列最小值不低于-1
print('缩放比例:',max_abs_scaler.scale_)
X_test_maxabs = max_abs_scaler.transform(X_test)   # 转换实例应用到测试数据:实现和训练数据一致的缩放和移位操作:
print('缩放后的矩阵仍然具有稀疏性:\n',X_train_maxabs)

缩放对象是记录了,平移距离和缩放大小,再对数据进行的操作

print('先平移:',min_max_scaler.min_)
print('再缩放:',min_max_scaler.scale_)

转换实例应用到测试数据:实现和训练数据一致的缩放和移位操作:

MaxAbsScaler通过除以每个特征的最大值将训练数据特征缩放至 [-1, 1] 范围内。可以应用在稀疏矩阵上保留矩阵的稀疏性。

X_train = np.array([[ 0., -1.,  0.],
                    [ 0., 0.,  0.2],
                    [ 2.,  0., 0]])
max_abs_scaler = preprocessing.MaxAbsScaler()
X_train_maxabs = max_abs_scaler.fit_transform(X_train)
print('每列最大值:',X_train_maxabs.max(axis=0))   # 每列最大值为1
print('每列最小值:',X_train_maxabs.min(axis=0))    # 每列最小值不低于-1
print('缩放比例:',max_abs_scaler.scale_)
X_test_maxabs = max_abs_scaler.transform(X_test)   # 转换实例应用到测试数据:实现和训练数据一致的缩放和移位操作:
print('缩放后的矩阵仍然具有稀疏性:\n',X_train_maxabs)

输出为特征缩放的步骤以及缩放后的矩阵

每列最大值: [1. 1. 1.]
每列最小值: [0. 0. 0.]
先平移: [-0.5  0.5  1. ]
再缩放: [0.5 0.5 0.5]
每列最大值: [1. 0. 1.]
每列最小值: [ 0. -1.  0.]
缩放比例: [2.  1.  0.2]
缩放后的矩阵仍然具有稀疏性:
 [[ 0. -1.  0.]
 [ 0.  0.  1.]
 [ 1.  0.  0.]]

3、缩放有离群值的数据

根据百分位数范围(默认值为IQR:四分位间距)缩放数据。

X_train = np.array([[ 1., -11.,  -2.],
                    [ 2.,  2.,  0.],
                    [ 13.,  1., -11.]])
robust_scale = preprocessing.RobustScaler()
X_train_robust = robust_scale.fit_transform(X_train)  # 训练同时转换
print('缩放后的矩阵离群点被处理了:\n',X_train_robust)

输出:

缩放后的矩阵离群点被处理了:
 [[-0.16666667 -1.84615385  0.        ]
 [ 0.          0.15384615  0.36363636]
 [ 1.83333333  0.         -1.63636364]]

4、非线性转换

sklearn 将数据集映射到均匀分布的方式主要是通过分位数转换的方式实现,通过类QuantileTransformer 类以及quantile_transform 函数实现。

X_train = np.array([[ 1., -1.,  -2.],
                    [ 2.,  0.,  0.],
                    [ 3.,  1., -1.]])
quantile_transformer = preprocessing.QuantileTransformer(n_quantiles=3,random_state=0)  
#将数据映射到了零到一的均匀分布上(默认是均匀分布)
X_train_trans = quantile_transformer.fit_transform(X_train)

#查看分位数信息,经过转换以后,分位数的信息基本不变
print('源分位数情况:',np.percentile(X_train[:, 0], [0, 25, 50, 75, 100]))
print('变换后分位数情况:',np.percentile(X_train_trans[:, 0], [0, 25, 50, 75, 100]))

#下面将数据映射到了零到一的正态分布上:输入的中值称为输出的平均值,并且以0为中心。正常输出被剪切,使得输入的最小和最大值分别对应于1e-7和1-1e-7分位数
quantile_transformer = preprocessing.QuantileTransformer(output_distribution='normal',random_state=0)

输出:

源分位数情况: [1.  1.5 2.  2.5 3. ]
变换后分位数情况: [0.   0.25 0.5  0.75 1.  ]

5、样本归一化

归一化缩放单个样本以具有单位范数 的过程。Normalizer 工具类通过使用 Transformer API实现了相同的归一化效果。但和其他转换器不一样的是,这个转换器没有状态,其fit函数并没有对转换保留状态的。fit函数只是对X进行数组校验,可见它并无状态,整个转换的过程,实际是全在 transform 函数。实际上,该类调用的依旧是normalize 函数。值得一提的是,Normalizer 工具类和 normalize 函数都支持稀疏矩阵的输入,并会自动转化为压缩的稀疏行形式。

使用 l1l2 范式。缩放使每个样本(每行)的一范数或二范数为1

X = [[ 1., -1.,  2.],
     [ 2.,  0.,  0.],
     [ 0.,  1., -1.]]
X_normalized = preprocessing.normalize(X, norm='l1')  # 
print('样本归一化:\n',X_normalized)

当然仍然可以先通过样本获取转换对象,再用转换对象归一化其他数据

normalizer = preprocessing.Normalizer().fit(X)  # 获取转换对象
normalizer.transform(X)  # 转换任何数据,X或测试集

输出为进行l1范数归一化的数据,以及进行l2范数归一化的数据

样本归一化:
 [[ 0.25 -0.25  0.5 ]
 [ 1.    0.    0.  ]
 [ 0.    0.5  -0.5 ]]

array([[ 0.40824829, -0.40824829,  0.81649658],
       [ 1.        ,  0.        ,  0.        ],
       [ 0.        ,  0.70710678, -0.70710678]])

6、特征二值化

特征二值化 是将数值特征用阈值过滤得到布尔值的过程,可以通过binarize 函数实现

获取转换模型,生成的门限,默认为0

binarizer = preprocessing.Binarizer().fit(X)  # 
print(binarizer)
#binarizer = preprocessing.Binarizer(threshold=1) 

自定义转换器。门限以上为1,门限(包含)以下为0

X_normalized = binarizer.transform(X)  # 转换任何数据,X或测试集
print('特征二值化:\n',X_normalized)

输出:

Binarizer(copy=True, threshold=0.0)
特征二值化:
 [[1. 0. 1.]
 [1. 0. 0.]
 [0. 1. 0.]]

7、标称特征编码(one-hot编码)

独热码,在英文文献中称做 one-hot code, 直观来说就是有多少个状态就有多少比特,而且只有一个比特为1,其他全为0的一种码制。举例如下: 假如有三种颜色特征:红、黄、蓝。 在利用机器学习的算法时一般需要进行向量化或者数字化。那么你可能想令 红=1,黄=2,蓝=3. 那么这样其实实现了标签编码,即给不同类别以标签。然而这意味着机器可能会学习到“红<黄<蓝”,但这并不是我们的让机器学习的本意,只是想让机器区分它们,并无大小比较之意。所以这时标签编码是不够的,需要进一步转换。因为有三种颜色状态,所以就有3个比特。即红色:1 0 0 ,黄色: 0 1 0,蓝色:0 0 1 。如此一来每两个向量之间的距离都是根号2,在向量空间距离都相等,所以这样不会出现偏序性,基本不会影响基于向量空间度量算法的效果。

自然状态码为:000,001,010,011,100,101

独热编码为:000001,000010,000100,001000,010000,100000
以下为例子

输入:

from sklearn.preprocessing import OneHotEncoder
enc = OneHotEncoder(categories='auto')
enc.fit([[0, 1, 2],   # 每列一个属性,每个属性一种编码
         [1, 0, 0],
         [0, 2, 1],
         [1, 0, 1]])
print('编码后:',enc.transform([[0, 1, 1]]).toarray()) 

转换目标对象。根据可取值所占位数进行罗列。前2位为第一个数字one-hot编码,紧接着的3位为第二个数字的编码,最后3位为第三个数字的编码

编码后: [[1. 0. 0. 1. 0. 0. 1. 0.]]

8、缺失值插补

在scikit-learn的模型中都是假设输入的数据是数值型的,并且都是有意义的,如果有缺失数据是通过NAN,或者空值表示的话,就无法识别与计算了。要弥补缺失值,可以使用均值,中位数,众数等等。Imputer这个类可以实现。

import numpy as np
from sklearn.impute import SimpleImputer

imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')
x = [[np.nan, 2], [6, np.nan], [7, 6]]
imp = imp_mean.fit(x)
new_x = imp_mean.transform(x)

print(imp)
print('缺失值插值后:\n',new_x)

输出:

SimpleImputer(add_indicator=False, copy=True, fill_value=None,
              missing_values=nan, strategy='mean', verbose=0)
缺失值插值后:
 [[6.5 2. ]
 [6.  4. ]
 [7.  6. ]]

9、生成多项式特征

有的时候线性的特征并不能做出美的模型,于是我们会去尝试非线性。非线性是建立在将特征进行多项式地展开上的。比如将两个特征
( X 1 , X 2 ) (X_1, X_2) (X1,X2)
,它的平方展开式便转换成5个特征
( 1 , X 1 , X 2 , X 1 2 , X 1 X 2 , X 2 2 ) . (1, X_1, X_2, X_1^2, X_1X_2, X_2^2). (1,X1,X2,X12,X1X2,X22).

from sklearn.preprocessing import PolynomialFeatures
X = np.array([[0, 1],
              [2, 3],
              [4, 5]])
# 最大二次方。interaction_only参数设置为True,则会只保留交互项
poly = PolynomialFeatures(2,interaction_only=False)  
 # 从 (X_1, X_2) 转换为 (1, X_1, X_2, X_1^2, X_1X_2, X_2^2)
print('生成多项式:\n',poly.fit_transform(X))  

输出:

生成多项式:
 [[ 1.  0.  1.  0.  0.  1.]
 [ 1.  2.  3.  4.  6.  9.]
 [ 1.  4.  5. 16. 20. 25.]]

10、过滤法

1、导入数据集

我们本实验中特征数据主要是依赖于sklearn自带数据集iris,对其进行多种方法的特征筛选。所以我们首先导入数据集。

#加载数据集

from sklearn.datasets import load_iris
 
iris = load_iris() # 导入IRIS数据集
iris.data # 特征矩阵
iris.target # 目标向量
2、采用方差过滤

方差过滤法需要计算每个特征的方差,然后根据阈值删除取值小于阈值的特征。

例如,假设某特征的取值为0和1,且训练集中有90%以上的数据在该特征的取值为1,那么可认为该特征对于区分不同数据的作用不大。方差过滤法只能用于筛选离散的特征,如果特征的取值是连续的,就需要将连续值离散化之后才能用。

from sklearn.feature_selection import VarianceThreshold
 
#方差选择法,返回值为特征选择后的数据
#参数threshold为方差的阈值
VarianceThreshold(threshold=3).fit_transform(iris.data)

通过筛除方差较小的特征数据,只保留了一个特征。

优点:效果最好速度最快,模式单调,快速并且效果明显。

缺点:但是如何参数设置, 需要深厚的背景知识。

3、采用卡方检验

经典的卡方检验是检验定性自变量对定性因变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距。

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

#选择K个最好的特征,返回选择特征后的数据
SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)

通过卡方检验只留下两个特征值

11、Wrapper

递归消除特征法使用一个基模型来进行多轮训练,每轮训练后,移除若干权值系数的特征,再基于新的特征集进行下一轮训练。

#递归特征消除

from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
 
#递归特征消除法,返回特征选择后的数据
#参数estimator为基模型
#参数n_features_to_select为选择的特征个数
rfe=RFE(estimator=LogisticRegression(C=1.0, class_weight=None, dual=False,
                                 fit_intercept=True, intercept_scaling=1,
                                 l1_ratio=None, max_iter=1000,
                                 multi_class='auto', n_jobs=None, penalty='l2',
                                 random_state=None, solver='lbfgs', tol=0.0001,
                                 verbose=0, warm_start=False),
    n_features_to_select=2, step=1, verbose=0)
rfe.fit_transform(iris.data, iris.target)

上面的代码中,首先,通过全部特征利用logistic回归训练评估函数,得出每个特征的权重。然后,将最小权重的特征从特征集合中去除
循环执行以上两个过程,直到特征数达成需要。

array([[1.4, 0.2],
       [1.4, 0.2],
       [1.3, 0.2],
       [1.5, 0.2],
       [1.4, 0.2],
       [1.7, 0.4],
       [1.4, 0.3],
       [1.5, 0.2],
       [1.4, 0.2],
       ..........

由数据可知,递归特征消除,只留下了两个特征。

12、嵌入法 Embedding

1、基于惩罚项的特征选择法
#通过加入L1惩罚项,将许多系数压缩至0以实现特征筛选
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
SelectFromModel(LogisticRegression(penalty="l1", C=0.3,solver='saga',multi_class='multinomial',max_iter=10000)).fit_transform(iris.data, iris.target)

通过加入L1惩罚项,将许多系数压缩至0以实现特征筛选

array([[1.4, 0.2],
       [1.4, 0.2],
       [1.3, 0.2],
       [1.5, 0.2],
       [1.4, 0.2],
       [1.7, 0.4],
       [1.4, 0.3],
       [1.5, 0.2],
       [1.4, 0.2],
       [1.5, 0.1],
       ..........])
2、基于树模型的特征选择法

树模型中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)

通过特征选择只留下2个特征

输出:

array([[1.4, 0.2],
       [1.4, 0.2],
       [1.3, 0.2],
       [1.5, 0.2],
       [1.4, 0.2],
       [1.7, 0.4],
       .....)

特征工程总结

通过特征工程的一系列代码,可以了解在面对不同数据集时,先进行怎么样的预处理来清洗数据提高数据质量,使得后续实验可以事半功倍。特征选择是数据挖掘中非常重要的一步,可以为后续建模省去很多时间,提高效率以及模型表现能力。在具体业务中,需要根据场景不同选择不同的方法。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天海一直在AI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值