有这么一句话在业界广泛流传:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。
特征工程其本质是一项工程活动,目的是最大限度地从原始数据中提取特征以供算法和模型使用。通过总结和归纳,人们认为特征工程包括以下方面:
特征选择的经典经验总结起来主要有三种:
1)Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
2)Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。
3)Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。
特征预处理是通过统计方法(数学方法)将数据转换成算法要求的数据,所以特征预处理也叫做数据预处理。
归一化
特点:通过对原始数据进行变换把数据映射到(默认在[0,1])之间公式:
其中公式作用于每一列(列:特征,行:样本),max和min分别代表每一列的最大值和最小值,X''为最终结果,mx,mi分别为指定的映射区间的最大值和最小值默认值为1和0。
下面是归一化的例子:
当多个特征同等重要的时候需要进行归一化处理,目的是使每一个特征不会对最终结果造成更大的影响。
归一化的缺点是:异常点对最大值和最小值影响太大,所以说只适合传统精确小数据场景。
下面是归一化的Python代码(使用sklearn):
from sklearn import preprocessing
import numpy as np
X = np.array([[ 1., -1., 2.],
[ 2., 0., 0.],
[ 0., 1., -1.]])
min_max_scaler = preprocessing.MinMaxScaler()
X_minMax = min_max_scaler.fit_transform(X)
print(X_minMax)
下面是运行结果:
[[ 0.5 0. 1. ]
[ 1. 0.5 0.33333333]
[ 0. 1. 0. ]]
标准化
特点:通过对原始数据进行变换把数据变换到均值为0,方差为1范围内。
公式:(由于输入不方便,所以直接引用)
标准化的优点是具有一定数据量,少量的异常点对于平均值得影响并不太大即异常点对于方差和平均值得影响是比较小。
下面是标准化的Python代码:
from sklearn import preprocessing
import numpy as np
X = np.array([[ 1., -1., 2.],
[ 2., 0., 0.],
[ 0., 1., -1.]])
# calculate mean
X_mean = X.mean(axis=0)
print('X_mean:\n',X_mean)
# calculate variance
X_std = X.std(axis=0)
print('X_std:\n',X_std)
# standardize X
X1 = (X-X_mean)/X_std
print('X1:\n',X1)
# use function preprocessing.scale to standardize X
X_scale = preprocessing.scale(X)
print('X_scale:\n',X_scale)
运行结果:
X_mean:
[ 1. 0. 0.33333333]
X_std:
[ 0.81649658 0.81649658 1.24721913]
X1:
[[ 0. -1.22474487 1.33630621]
[ 1.22474487 0. -0.26726124]
[-1.22474487 1.22474487 -1.06904497]]
X_scale:
[[ 0. -1.22474487 1.33630621]
[ 1.22474487 0. -0.26726124]
[-1.22474487 1.22474487 -1.06904497]]
正则化(Normalization)
正则化的过程是将每个样本缩放到单位范数(每个样本的范数为1),如果后面要使用如二次型(点积)或者其它核方法计算两个样本之间的相似性这个方法会很有用。
Normalization主要思想是对每个样本计算其p-范数,然后对该样本中每个元素除以该范数,这样处理的结果是使得每个处理后样本的p-范数(l1-norm,l2-norm)等于1。
p-范数的计算公式:||X||p=(|x1|^p+|x2|^p+...+|xn|^p)^1/p
- 1
- 2
该方法主要应用于文本分类和聚类中。例如,对于两个TF-IDF向量的l2-norm进行点积,就可以得到这两个向量的余弦相似性。
1、可以使用preprocessing.normalize()函数对指定数据进行转换:
>>> X = [[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]]
>>> X_normalized = preprocessing.normalize(X, norm='l2')
>>> X_normalized
array([[ 0.40..., -0.40..., 0.81...],
[ 1. ..., 0. ..., 0. ...],
[ 0. ..., 0.70..., -0.70...]])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2、可以使用processing.Normalizer()类实现对训练集和测试集的拟合和转换:
>>> normalizer = preprocessing.Normalizer().fit(X) # fit does nothing
>>> normalizer
Normalizer(copy=True, norm='l2')
>>> normalizer.transform(X)
array([[ 0.40..., -0.40..., 0.81...],
[ 1. ..., 0. ..., 0. ...],
[ 0. ..., 0.70..., -0.70...]])
>>> normalizer.transform([[-1., 1., 0.]])
array([[-0.70..., 0.70..., 0. ...]])
在卷积神经网处理图像问题的时候,图像数据有3种常见的预处理可能会用到,如下。我们假定数据表示成矩阵为X
,其中我们假定X
是[N*D]维矩阵(N是样本数据量,D为单张图片的数据向量长度)。
- 去均值,这是最常见的图片数据预处理,简单说来,它做的事情就是,对待训练的每一张图片的特征,都减去全部训练集图片的特征均值,这么做的直观意义就是,我们把输入数据各个维度的数据都中心化到0了。使用python的numpy工具包,这一步可以用
X -= np.mean(X, axis = 0)
轻松实现。当然,其实这里也有不同的做法:简单一点,我们可以直接求出所有像素的均值,然后每个像素点都减掉这个相同的值;稍微优化一下,我们可以在RGB三个颜色通道分别做这件事。 - 归一化,归一化的直观理解含义是,我们做一些工作去保证所有的维度上数据都在一个变化幅度上。通常我们有两种方法来实现归一化。一个是在数据都去均值之后,每个维度上的数据都除以这个维度上数据的标准差(
X /= np.std(X, axis = 0)
)。另外一种方式是我们除以数据绝对值最大值,以保证所有的数据归一化后都在-1到1之间。多说一句,其实在任何你觉得各维度幅度变化非常大的数据集上,你都可以考虑归一化处理。不过对于图像而言,其实这一步反倒可做可不做,因为大家都知道,像素的值变化区间都在[0,255]之间,所以其实图像输入数据天生幅度就是一致的。
上面的E(xk)指的是每一批训练数据神经元xk的平均值;然后分母就是每一批数据神经元xk激活度的一个标准差了。卷积层上的BN使用,其实也是使用了类似权值共享的策略,把一整张特征图当做一个神经元进行处理,求取所有样本所对应的一个特征图的所有神经元的平均值、方差,然后对这个特征图神经元做归一化.
- PCA和白化/whitening,这是另外一种形式的数据预处理。在经过去均值操作之后,我们可以计算数据的协方差矩阵,从而可以知道数据各个维度之间的相关性,说到神经网络输入数据预处理,最好的算法莫过于白化预处理。然而白化计算量太大了,很不划算,还有就是白化不是处处可微的,所以在深度学习中,其实很少用到白化。