1.标准化(也称去均值和方差按比例缩放)
(1)原因:
数据集的标准化对scikit-learn中实现的大多数机器学习算法来说是常见的要求 。
如果个别特征或多或少看起来不是很像标准正态分布(具有零均值和单位方差),那么它们的表现力可能会较差。在实际情况中,我们经常忽略特征的分布形状,直接经过去均值来对某个特征进行中心化,再通过除以非常量特征(non-constant features)的标准差进行缩放。
具体原因可以归纳为:去量纲、缩小差别加快收敛
(2)实现:(基于preprocessing模块,scale方法)
自己实现的话,可以基于上面的标准化公式:z=(x-mean)/variance
def my_scale(data):
mean = sum(data) / len(data) #先求均值
variance = ( sum([ (I-mean) ** 2 for I in data]) ) / len(data) #再求方差
normal = [(I - mean) / (variance ) ** 0.5 for I in data] #按照公式标准化
return normal
sklearn提供了专门的解决方法scale:
from sklearn import preprocessing
import numpy as np
X_train = np.array([[ 1., -1., 2.],[ 2., 0., 0.],[ 0., 1., -1.]])
X_scaled = preprocessing.scale(X_train)
StandarScaler方法能够允许我们进行fit,从而保存我们的模型,然后进行transform转换:
from sklearn import preprocessing
scaler = preprocessing.StandardScaler().fit(X_train) 以模型形式实现标准化方法的保存,便于用在测试集上
print(scaler.transform(X_train))
scaler.transform(X_test) 因为前面scaler是fit训练出来的模型,因此可以用于测试集中,相当于实现相同的标准化操作
2.将结果缩放到一个区间内
(1)原因:
这种方法也称为0-1标准化,使用这个缩放的情况包括:增强极小方差的值还有保留稀疏样本中的零值。
这种也很常见,可以实现将数据值缩放到[-1,1]区间,。这种情况适合在均值在0附近的值,或者稀疏矩阵。
(2)实现:(基于 MinMaxScaler 和 MaxAbsScaler 方法)
基于 MinMaxScaler方法的实现
import numpy as np
from sklearn import preprocessing
X_train = np.array([[ 1., -1., 2.], [ 2., 0., 0.], [ 0., 1., -1.]])
min_max_sacler = preprocessing.MinMaxScaler()
min_max_sacler.fit(X_train)
print(min_max_sacler.transform(X_train))
基于 MaxAbsScaler 方法的实现:
import numpy as np
from sklearn import preprocessing
X_train = np.array([[ -4., -2., 2.],[ -5., 0., 0.],[ 0., 1., 6.],[10, 2, 3]])
max_abs_sacler = preprocessing.MaxAbsScaler()
max_abs_sacler.fit(X_train)
print(max_abs_sacler.transform(X_train))
附:
特殊数据缩放:
【1】缩放稀疏数据: 使用MaxAbsScaler可以进行稀疏数据的缩放;
【2】缩放异常点较多的数据: 使用robust_scale 或者RobustScaler;
3.非线性转换–分位数转换
(1)原因:
分位数转换的目的也是把特征数据转换到一定的范围内,或者让他们符合一定的分布。
分位数转换利用的是数据的分位数信息进行变换。它能够平滑那些异常分布,对于存在异常点的数据也很适合。
但是它会破坏原来数据的相关性和距离信息。
(2)实现:(基于QantitleTransformer方法)
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
import numpy as np
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
quantile_transformer = preprocessing.QuantileTransformer(random_state=0)
X_train_trans = quantile_transformer.fit_transform(X_train)
X_test_trans = quantile_transformer.fit_transform(X_test)
#查看分位数信息,经过转换以后,分位数的信息基本不变
print(np.percentile(X_train[:, 0], [0, 25, 50, 75, 100]))
print(np.percentile(X_train_trans[:, 0], [0, 25, 50, 75, 100]))
4.归一化
(1)原因:
需要说明是,这里的归一化不是对一列的特征进行操作,而是对一行的样本(记录)进行操作!
归一化适用于这样的场景:需要使用点积,或者有的模型需要对样本的相似性进行度量。
(2)实现:(基于normalize方法)
normalize方法里面有个参数叫norm,可以实现L1、L2、max这三种计算
L1范数公式:
L2范数公式:
from sklearn import preprocessing
X = [[ 1., -1., 2.],
[ 2., 0., 0.],
[ 0., 1., -1.],
[ 3., 4., 5.]]
X1_normalized = preprocessing.normalize(X, norm='l1')
X2_normalized = preprocessing.normalize(X, norm='l2')
print(X1_normalized)
print(X2_normalized)
5.二值化
(1)原因:
特征二值化是将数值特征用阈值过滤得到布尔值 的过程。(就是基于阈值做个判断)
这对于下游的概率型模型是有用的,它们假设输入数据是多值 伯努利分布(Bernoulli distribution) 。
(2)实现:
X = [[ 1., -1., 2.],[ 2., 0., 0.],[ 0., 1., -1.]]
binarizer = preprocessing.Binarizer().fit(X) # fit does nothing
>>> binarizer
Binarizer(copy=True, threshold=0.0)
>>> binarizer.transform(X)
array([[ 1., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.]])
当然也可以手动指定阈值
binarizer = preprocessing.Binarizer(threshold=1.1)
>>> binarizer.transform(X)
array([[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 0., 0.]])
6.分类特征编码
6.1序号编码(就是按1,2,3顺序这样编码)(基于LabelEncoder()方法)
这个的整数特征表示并不能在scikit-learn的估计器中直接使用,因为这样的连续输入,估计器会认为类别之间是有序的,
但实际却是无序的。
>>> le = preprocessing.LabelEncoder()
>>> le.fit(["paris", "paris", "tokyo", "amsterdam"])
LabelEncoder()
>>> list(le.classes_)
['amsterdam', 'paris', 'tokyo']
>>> le.transform(["tokyo", "tokyo", "paris"])
array([2, 2, 1]...)
>>> list(le.inverse_transform([2, 2, 1]))
['tokyo', 'tokyo', 'paris']
6.2One-Hot编码(基于OneHotEncoder()方法)
One-Hot编码针对的是希望将转换后的结果直接能够在后续估计器中使用的情况。本质上相当于破坏了上面连续序号编码所造成的不存在的数值关系。
OneHotEncoder方法将分类特征转换为能够被scikit-learn中模型使用的编码。这种编码只有对应位置有一个1,其余位置都是0,以示区分。这样显然数值间就不存在1,2,3这样产生的数值关系了。
>>> enc = preprocessing.OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
OneHotEncoder(categorical_features='all', dtype=<... 'numpy.float64'>,
handle_unknown='error', n_values='auto', sparse=True)
>>> enc.transform([[0, 1, 3]]).toarray()
array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])
6.3二进制编码
主要分两步:1.先用序号编码给每个类别赋予一个类别ID;2.然后将类别ID对应的二进制编码作为结果。
(其实就是用序号编码的结果做一个十进制转二进制的转换)
7.缺失值的填补
基于Imputer方法,可以用均值、最值等形式进行填充
>>> import numpy as np
>>> from sklearn.preprocessing import Imputer
>>> imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0)
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> print(imp.transform(X))
[[ 4. 2. ]
[ 6. 3.666...]
[ 7. 6. ]]
8.生成多项式特征
(1)原因:
在机器学习中,通过增加一些输入数据的非线性特征来增加模型的复杂度通常是有效的。一个简单通用的办法是使用多项式特征,这可以获得特征的更高维度和互相间关系的项。
(2)实现:基于 PolynomialFeatures方法
>>> import numpy as np
>>> from sklearn.preprocessing import PolynomialFeatures
>>> X = np.arange(6).reshape(3, 2)
>>> X
array([[0, 1],
[2, 3],
[4, 5]])
>>> poly = PolynomialFeatures(2) 比较容易,直接给定多项式幂次即可自动组合
>>> poly.fit_transform(X)
array([[ 1., 0., 1., 0., 0., 1.],
[ 1., 2., 3., 4., 6., 9.],
[ 1., 4., 5., 16., 20., 25.]])
>>> X = np.arange(9).reshape(3, 3)
>>> X
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> poly = PolynomialFeatures(degree=3, interaction_only=True)
>>> poly.fit_transform(X)
array([[ 1., 0., 1., 2., 0., 0., 2., 0.],
[ 1., 3., 4., 5., 12., 15., 20., 60.],
[ 1., 6., 7., 8., 42., 48., 56., 336.]])
这种是指定只要特征交互项的情况,利用interaction_only=True来指定。
9.自定义转换
基于FunctionTransformer方法
>>> import numpy as np
>>> from sklearn.preprocessing import FunctionTransformer
>>> transformer = FunctionTransformer(np.log1p)
>>> X = np.array([[0, 1], [2, 3]])
>>> transformer.transform(X)
array([[ 0. , 0.69314718],
[ 1.09861229, 1.38629436]])