数据标准化
在深度学习/机器学习领域,数据标准化是一个应用非常广泛的手段。所谓标准化,即消除原始数据中不同特征之间的量纲差异,使得后续的训练过程更加合理有效。
StandardScaler:标准差标准化
这是应用非常广泛的一种标准化方式:根据数据的均值、方差进行标准化。
通常来说,数据的形式是一个$N\times D$的矩阵,其中$N$为样本数量,$D$为特征维度。而标准化则是在某个特征维度上,对全部的样本进行归一。
具体地,接下来,我们初始化一个$4\times 5$的矩阵作为原始数据,对其进行标准差标准化:
feature_nums = 5 # 5个特征维度
sample_nums = 4 # 4个样本
data = np.random.randint(low=-5, high=5, size=(sample_nums, feature_nums)) # 创建一个矩阵
print(data)
'''
[[-2 3 0 0 -1]
[-1 2 -1 -2 0]
[-1 3 0 -3 3]
[ 0 -1 -3 -4 3]]
'''
接下来,计算均值和标准差:
mean = np.mean(data, axis=0) # 指定轴为行轴,计算均值
std = np.std(data, axis=0) # 指定轴为列轴,计算标准差
standard_data = (data - mean) / std
print('均值: ', mean)
print('标准差: ', std)
print('标准差标准化数据: \n', standard_data)
'''
均值: [-1. 1.75 -1. -2.25 1.25]
标准差: [0.70710678 1.63935963 1.22474487 1.47901995 1.78535711]
标准差标准化数据:
[[-1.41421356 0.76249285 0.81649658 1.52127766 -1.26025208]
[ 0. 0.15249857 0. 0.16903085 -0.70014004]
[ 0. 0.76249285 0.81649658 -0.50709255 0.98019606]
[ 1.41421356 -1.67748427 -1.63299316 -1.18321596 0.98019606]]
'''
当然,也可以逆向进行还原原始数据:
recon_data = standard_data * std + mean # 还原
print('还原原始数据: \n', recon_data)
'''
还原原始数据:
[[-2. 3. 0. 0. -1.]
[-1. 2. -1. -2. 0.]
[-1. 3. 0. -3. 3.]
[ 0. -1. -3. -4. 3.]]
'''
sklearn库快捷用法
导入sklearn包之后,便可快速使用其中的标准化工具,而无需我们再手工实现这个方法。
我们通过一个简单的实例展示其用法。
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 1)归一化前,将原始数据分割
X_train, X_test, y_train, y_test = train_test_split(X, y, seed = 666)
# 2)导入均值方差归一化模块:StandardScaler
from sklearn.preprocessing import StandardScaler
# 实例化,不需要传入参数
standardScaler = StandardScaler()
# 3)fit过程:返回StandardScaler对象,对象内包含训练数据集的均值和方差
# fit过程,传入训练数据集;
standardScaler.fit(X_train)
# 输出:StandardScaler(copy=True, with_mean=True, with_std=True)
# fit后可通过standardScaler查看均值和标准差
# standardScaler.mean_:查看均值
# standardScaler.scale_:查看标准差
# 4)transform:对训练数据集和测试数据集进行归一化,分别传入对应的数据集
# 归一化并没有改变训练数据集,而是又生成一个新的矩阵,除非将新生成的数据集赋给原数据集,一般不改变原数据
X_train_standard = standardScaler.transform(X_train)
X_test_standard = standardScaler.transform(X_test)
# 接下来就是使用归一化后的数据集训练并测试模型...
自定义Scaler
上面的讨论均基于数据是二维的尺寸(即行数表示样本数量、列数表示特征数量)这一大前提。那么如果现在将数据集改为三维,该如何做标准化?这实际上就需要灵活运用numpy的两个方法
mean(),std()
。
考虑一个现实例子:今有$M$台风力涡轮机,每台风机均有$N$条数据,每条数据包含$D$项观测指标,故组成一个尺寸为$M\times N\times D$的三维张量数据集$\mathcal{D}$。我们希望对每台风力涡轮机,单独进行数据标准化(不同的风机所处环境有差异,若统一进行标准化可能带来误差、弱化数据异质性)。
于是我们需要实现一个自定义类Scaler
:
class Scaler:
def __init__(self) -> None:
pass
def fit(self, data: np.ndarray):
self.mean = data.mean(axis=1, keepdims=True) # 这里指定轴序号,非常重要,同时设定keepdims为True
self.std = data.std(axis=1, keepdims=True)
def transform(self, data: np.ndarray):
return (data - self.mean) / self.std
def inverse_transform(self, data:np.ndarray):
return data * self.std + self.mean
接下来应用一下这个自定义标准化工具:
# 初始化原始数据
turbine_nums = 2 # 简单起见,设置2台风力涡轮机
sample_nums = 4
feature_nums = 5
raw_data = np.random.randint(low=-10, high=10, size=(turbine_nums, sample_nums, feature_nums))
print('原始数据尺寸: ', raw_data.shape)
print('原始数据: \n', raw_data)
# 实例化标准化工具类
scaler = Scaler()
scaler.fit(raw_data)
print('均值: ', scaler.mean)
print('标准差: ', scaler.std)
# 标准化数据
standard_data = scaler.transform(raw_data)
print('标准化数据: \n', standard_data)
# 还原
recon_data = scaler.inverse_transform(standard_data)
print('还原数据: \n', recon_data)
'''
原始数据尺寸: (2, 4, 5)
原始数据:
[[[ 6 2 -5 4 -10]
[ -7 -10 -8 0 7]
[ -9 6 -2 -7 -2]
[ 9 0 -5 8 -10]]
[[ 8 5 7 -6 -3]
[ -1 1 -10 1 -6]
[ -2 -8 -2 2 4]
[ -7 -6 8 -7 -8]]]
均值: [[[-0.25 -0.5 -5. 1.25 -3.75]]
[[-0.5 -2. 0.75 -2.5 -3.25]]]
标准差: [[[7.85413904 5.89491306 2.12132034 5.53962995 7.01338007]]
[[5.40832691 5.24404424 7.32717544 4.03112887 4.54835135]]]
标准化数据:
[[[ 0.79575877 0.42409446 0. 0.49642305 -0.89115376]
[-0.85941947 -1.61155897 -1.41421356 -0.22564684 1.53278446]
[-1.11406227 1.10264561 1.41421356 -1.48926915 0.24952305]
[ 1.17772298 0.08481889 0. 1.21849294 -0.89115376]]
[[ 1.57165056 1.33484762 0.85298899 -0.86824314 0.05496497]
[-0.09245003 0.57207755 -1.46714107 0.86824314 -0.60461468]
[-0.2773501 -1.14415511 -0.37531516 1.11631261 1.59398416]
[-1.20185043 -0.76277007 0.98946723 -1.11631261 -1.04433445]]]
还原数据:
[[[ 6.00000000e+00 2.00000000e+00 -5.00000000e+00 4.00000000e+00
-1.00000000e+01]
[-7.00000000e+00 -1.00000000e+01 -8.00000000e+00 0.00000000e+00
7.00000000e+00]
[-9.00000000e+00 6.00000000e+00 -2.00000000e+00 -7.00000000e+00
-2.00000000e+00]
[ 9.00000000e+00 -5.55111512e-17 -5.00000000e+00 8.00000000e+00
-1.00000000e+01]]
[[ 8.00000000e+00 5.00000000e+00 7.00000000e+00 -6.00000000e+00
-3.00000000e+00]
[-1.00000000e+00 1.00000000e+00 -1.00000000e+01 1.00000000e+00
-6.00000000e+00]
[-2.00000000e+00 -8.00000000e+00 -2.00000000e+00 2.00000000e+00
4.00000000e+00]
[-7.00000000e+00 -6.00000000e+00 8.00000000e+00 -7.00000000e+00
-8.00000000e+00]]]
'''
MinMaxScaler
利用特征的最大值和最小值的绝对差,将原始的数据映射到$[0,1]$范围内。
from sklearn.preprocessing import StandardScaler, MinMaxScaler
feature_nums = 5 # 5个特征维度
sample_nums = 4 # 4个样本
data = np.random.randint(low=-5, high=5, size=(sample_nums, feature_nums)) # 创建一个矩阵
print(data)
scaler = MinMaxScaler()
scaler.fit(data)
minmax_standard_data = scaler.transform(data)
print('最值归一化数据: \n', minmax_standard_data)
'''
[[-3 2 -3 4 -1]
[ 1 -3 -2 -4 -4]
[ 1 1 2 4 0]
[-3 3 3 0 -1]]
最值归一化数据:
[[0. 0.83333333 0. 1. 0.75 ]
[1. 0. 0.16666667 0. 0. ]
[1. 0.66666667 0.83333333 1. 1. ]
[0. 1. 1. 0.5 0.75 ]]
'''