特征缩放

特征缩放

参考资料

维基百科
知乎
数据标准化/归一化normalization
sklearn
pandas & numpy
numpy中标准差std的神坑

目的

1.提高梯度下降的收敛速度。
- 原始数据的代价函数收敛:

- 特征缩放后:

2. 如果原始数据的特征之间差别很大,不进行特征缩放的话,会导致某些机器学习算法无法正常完成工作。比如很多分类器是通过计算欧氏距离来计算数据与数据之间的距离,如果某个特征的范围比其他特征大的多,可能距离就受到了该特征的支配。
3. batch normalization,批规范化,BN,可以防止梯度爆炸\梯度消失\振荡

方法

1. rescaling

将数据的特征按比例缩放到[0,1]的区间,公式如下:

x ^ i ( j ) = x i ( j ) m i n ( x i ) m a x ( x i ) m i n ( x i )

2. mean normalization

缩放到[-1, 1]的区间,公式如下:

x ^ i ( j ) = x i ( j ) m e a n ( x i ) m a x ( x i ) m i n ( x i )

3. standardization

又称之为: Z s c o r e   n o r m a l i z a t i o n ,将所有数据缩放到平均值为0,方差为1, 如果数据服从正态分布,则现在为标准正态分布,如果数据不服从正态分布,那么缩放后不是标准正态分布,只是服从均值为0,方差为1。数据缩放后在0左右分布,但不一定就在[0,1]范围内,有可能超出:

z = x i μ σ

其中, μ 为对应特征 x i 的均值, σ 为对应特征 x i 的标准差。
原始数据最好近似为正态分布,否则缩放的结果不理想。

4.scaling to unit length

x = x | | x | |

都变成了单位向量

直观感受:

# -*- coding: utf-8 -*-

import numpy as np
from functools import reduce
from math import sqrt

data_set = np.array([0.0, 1, 2, 3, 4, 5])
min_data = data_set.min()
max_data = data_set.max()
mu = data_set.mean()
sigma = sqrt(reduce(lambda x, y: x + y, map(lambda z: (z - mu) ** 2, data_set)) / len(data_set))

data_set_rescaling = list(map(lambda x: (x - min_data) / (max_data - min_data), data_set))
data_set_mean_normalization = list(map(lambda x: (x - mu) / (max_data - min_data), data_set))
data_set_standardization = list(map(lambda x: (x - mu) / sigma, data_set))
data_set_scaling_to_unit_length = list(map(lambda x: x/x if x != 0 else 0.0, data_set))

print(data_set)
print(data_set_rescaling)
print(data_set_mean_normalization)
data_set_standardization = [float('%.2f' % data) for data in data_set_standardization]
print(data_set_standardization)
print(data_set_scaling_to_unit_length)
[0. 1. 2. 3. 4. 5.]
[0.0, 0.2, 0.4, 0.6, 0.8, 1.0]
[-0.5, -0.3, -0.1, 0.1, 0.3, 0.5]
[-1.46, -0.88, -0.29, 0.29, 0.88, 1.46]
[0.0, 1.0, 1.0, 1.0, 1.0, 1.0]

scikit learn的API

1. rescaling

使用MinMaxScaler或者MaxAbsScaler

MinMaxScaler

将数据按照比例缩放到[0,1]区间。
保留比例关系。
如果给出参数feature_range=(min, max)的值,可以缩放到任意区间。
运算公式是:
x_std = (x - x.min(axis=0)) / (x.max(axis=0) - x.min(axis=0))
x_scaled = x_std * (max - min) + min
其中,minmaxfeature_range=(min, max)传入的参数,默认为(0,1)

# coding:utf-8

from sklearn import preprocessing
import numpy as np

x_train = np.array([[1., 3, 5],
                    [2, 3, 3],
                    [4, 5, 3], ])
x_test = [[-1., 1., 0.]]

min_max_scaler = preprocessing.MinMaxScaler()  # 按照列
x_train_min_max = min_max_scaler.fit_transform(x_train)  # 也可以fit(x_train).transform(x_train)
x_test_min_max = min_max_scaler.transform(x_test)

print('最小最大值缩放:\n训练集:\n{}'.format(x_train_min_max))
print('测试集:\n{}'.format(x_test_min_max))
# 即:x * (1\(max-min))- min,也就是,x * scale_ - min_
print(min_max_scaler.scale_)  # 数据的缩放比例,即1/(max - min)
print(min_max_scaler.min_)  # -min的min

输出:

最小最大值缩放:
训练集:
[[0.         0.         1.        ]
 [0.33333333 0.         0.        ]
 [1.         1.         0.        ]]
[0.33333333 0.5        0.5       ]
[-0.33333333 -1.5        -1.5       ]

MaxAbsScale

将数据缩放到[-1, 1]区间。
通过除以最大值的绝对值实现,能够保留原矩阵中的0元素的位置。
可以使用到已经分布在0左右的数据集中。
也可以使用到稀疏矩阵中。

# coding:utf-8

from sklearn import preprocessing
import numpy as np

x_train = np.array([[1., 3, 5],
                    [2, 3, 3],
                    [4, 5, 3], ])
x_test = [[-1., 1., 0.]]

max_abs_scaler = preprocessing.MaxAbsScaler().fit(x_train)
x_train_max_abs = max_abs_scaler.transform(x_train)
x_test_max_abs = max_abs_scaler.transform(x_test)
print('最大值绝对值缩放:\n训练集:\n{}\n测试集:\n{}'.format(x_train_max_abs, x_test_max_abs))

输出:

最大值绝对值缩放:
训练集:
[[0.25 0.6  1.  ]
 [0.5  0.6  0.6 ]
 [1.   1.   0.6 ]]
测试集:
[[-0.25  0.2   0.  ]]

3. standardization

使用scale或者兼顾测试集的StandardScaler(测试集数据用训练集的 μ σ 缩放)
如果数据需要预处理为均值为0,标准差为1的数据,使用该方法。

# coding:utf-8

from sklearn import preprocessing
import numpy as np

x_train = np.array([[1., 3, 5],
                    [2, 3, 3],
                    [4, 5, 3], ])
x_test = [[-1., 1., 0.]]

print('训练集均值:{}'.format(x_train.mean(axis=0)))  # axis=0, columns, axis=1, row
print('训练集标准差:{}'.format(x_train.std(axis=0)))

# 特征缩放,矩阵的每一个列向量的均值缩放为0,标准差为1
# 即,每一个列向量看成是是一个特征。
# (x - mu) / sigma
print('\n特征缩放:\n缩放为均值为0,标准差为1:')

x_scaled = preprocessing.scale(x_train)

print(x_scaled)
print('\n缩放后的均值:{}'.format(x_scaled.mean(axis=0)))  # 均值为0
print('缩放后的标准差:{}'.format(x_scaled.std(axis=0)))  # 标准差为1


# 标准缩放类
# 可以让测试集有和训练集一样的特征缩放
print('\n特征缩放:\n缩放为均值为0,标准差为1,且测试集和训练集同缩放变换:')

scaler = preprocessing.StandardScaler(with_mean=False,).fit(x_train)

print('训练集均值:{}'.format(scaler.mean_))
print('训练集标准差:{}'.format(scaler.scale_))
print('\n缩放后的训练集:\n{}'.format(scaler.transform(x_train)))
print('\n缩放后的测试集:\n{}'.format(scaler.transform(x_test)))

输出:

训练集均值:[2.33333333 3.66666667 3.66666667]
训练集标准差:[1.24721913 0.94280904 0.94280904]

特征缩放:
缩放为均值为0,标准差为1:
[[-1.06904497 -0.70710678  1.41421356]
 [-0.26726124 -0.70710678 -0.70710678]
 [ 1.33630621  1.41421356 -0.70710678]]

缩放后的均值:[-1.48029737e-16  1.48029737e-16  1.48029737e-16]
缩放后的标准差:[1. 1. 1.]

特征缩放:
缩放为均值为0,标准差为1,且测试集和训练集同缩放变换:
训练集均值:[2.33333333 3.66666667 3.66666667]
训练集标准差:[1.24721913 0.94280904 0.94280904]

缩放后的训练集:
[[-1.06904497 -0.70710678  1.41421356]
 [-0.26726124 -0.70710678 -0.70710678]
 [ 1.33630621  1.41421356 -0.70710678]]

缩放后的测试集:
[[-2.67261242 -2.82842712 -3.8890873 ]]

Process finished with exit code 0

pandas & numpy

原始数据:

# coding:utf-8

import numpy as np
import pandas as pd

data = pd.DataFrame(np.arange(16).reshape(4, 4))
print(data)
'''
    0   1   2   3
0   0   1   2   3
1   4   5   6   7
2   8   9  10  11
3  12  13  14  15
'''

min max normalization:

# min max normalization
# method one
data_min_max = (data - data.min()) / (data.max() - data.min())
print(data_min_max)
'''
          0         1         2         3
0  0.000000  0.000000  0.000000  0.000000
1  0.333333  0.333333  0.333333  0.333333
2  0.666667  0.666667  0.666667  0.666667
3  1.000000  1.000000  1.000000  1.000000
'''

# method two
data_min_max_02 = data.apply(lambda x: (x - np.min(x)) / (np.max(x) - np.min(x)))
print(data_min_max_02)
'''
结果同上
'''

mean normalization:

# mean normalization
# (x - mean)/(max - min)
# method one
data_mean_normalization = (data - data.mean()) / (data.max() - data.min())
print(data_mean_normalization)
'''
          0         1         2         3
0 -0.500000 -0.500000 -0.500000 -0.500000
1 -0.166667 -0.166667 -0.166667 -0.166667
2  0.166667  0.166667  0.166667  0.166667
3  0.500000  0.500000  0.500000  0.500000
'''

# method two
data_mean_normalization_02 = data.apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))
print(data_mean_normalization_02)
'''
结果同上
'''

standardization:

# z score normalization, standardization
# method one
data_standardization = (data - data.mean()) / data.std()
print(data_standardization)
'''
          0         1         2         3
0 -1.161895 -1.161895 -1.161895 -1.161895
1 -0.387298 -0.387298 -0.387298 -0.387298
2  0.387298  0.387298  0.387298  0.387298
3  1.161895  1.161895  1.161895  1.161895
'''

# method two
data_standardization_02 = data.apply(lambda x: (x - np.mean(x)) / np.std(x))
print(data_standardization_02)
'''
          0         1         2         3
0 -1.341641 -1.341641 -1.341641 -1.341641
1 -0.447214 -0.447214 -0.447214 -0.447214
2  0.447214  0.447214  0.447214  0.447214
3  1.341641  1.341641  1.341641  1.341641
'''
# fixme 结果不一样

pandas 的mean()和numpy的mean()结果是一样的。
pandas的std()和numpy的std()结果不同。
可能是涉及到了对数据的标准差的计算公式不同。
样本标准差:

S = 1 N 1 i = 1 N ( X i X ¯ )

其中, X ¯ 是样本 X 1 , . . . , X i , . . . , X N 的样本均值。N为样本数量。
总体标准差:
σ = 1 N i = 1 N ( X i μ )

其中, μ 为总体数据的均值。N为总体数量。

data_pd = pd.DataFrame([1, 2, 3])  # 样本标准差:1, 总体标准差:0.81
std_pd = data_pd.std()
std_np = data_pd.apply(lambda x: np.std(x))
print(std_pd)
print(std_np)
'''
0    1.0
dtype: float64
0    0.816497
dtype: float64
'''

也就是,pandas的std()默认将数据当做样本数据计算,采用无偏估计。(N-1)
numpy的std()默认将数据视为整体数据,而不是抽样的样本,计算的是总体标准差。(N)

  • ddof=0总体标准差,ddof=1样本标准差。
  • numpy的std()ddof默认为0。计算无偏估计标准差的参数是np.std(x, ddof=1)
  • pandas的std()ddof默认为1。若x.std(ddof=0),计算的就是总体标准差。

猜你喜欢

转载自blog.csdn.net/cluster1893/article/details/80759738