机器学习算法笔记(三):数据归一化处理

所谓数据归一化,就是将所有的数据映射到同一尺度,从而便于不同单位或量级的指标能够进行比较和加权。例如,一组数据中包含一个人的年龄与他的年薪两个属性,若我们直接运用kNN算法来建立模型,不难发现数据的变化会被年薪这个属性“主导”(因为年薪的数量级往往比一个人的年龄高很多)。所以在将数据“喂”给我们的机器学习算法之前,对属性进行归一化处理就显得尤为重要。

一、数据归一化处理的两种方式

要对数据进行归一化处理,我们通常有两种方式:

● 最值归一化(normalization),将所有数据映射到0和1之间。适用于分布有明显边界的情况(比如学生的考试成绩),受outlier(极端值)影响较大。
● 均值方差归一化(standardization),将所有数据归一到均值为0、方差为1的分布中,适用于数据分布没有明显边界(有明显边界时也可以使用)、有可能出现极端值的情况。

对于最值归一化,我们有如下的公式:

其中,Xmin和Xmax分别表示对应特征值的最小值和最大值。

对于均值方差归一化,类似地,我们的公式是:

其中,Xmean为对应特征值的均值,S为对应特征值的方差。

二、数据归一化的代码实现

首先我们来看一下对于数据归一化的简单实现:

import numpy as np

x = np.random.randint(0, 100, 100) #生成一个0到100之间含有100个元素的随机array
print(x[:10]) #打印前十个数据
x = (x - np.min(x)) / (np.max(x) - np.min(x)) #进行最值归一化
print(x[:10])

X = np.random.randint(0, 100, (50, 2)) #生成一个50x2的随机矩阵
X = np.array(X, dtype=float)
print(X[:10,:]) #打印前十行
#进行最值归一化
X[:,0] = (X[:,0] - np.min(X[:,0])) / (np.max(X[:,0]) - np.min(X[:,0]))
X[:,1] = (X[:,1] - np.min(X[:,1])) / (np.max(X[:,1]) - np.min(X[:,1]))
print(X[:10,:])
import numpy as np

X2 = np.random.randint(0, 100, (50, 2))
X2 = np.array(X2, dtype=float)
print(X2[:10,:])
#进行均值方差归一化
X2[:,0] = (X2[:,0] - np.mean(X2[:,0])) / np.std(X2[:,0])
X2[:,1] = (X2[:,1] - np.mean(X2[:,1])) / np.std(X2[:,1])
print(X2[:10,:])

#打印归一化后的均值与方差
for i in range(0,2):
    print(np.mean(X2[:,i]))
    print(np.std(X2[:,i]))

两种归一化的代码的运行结果如下:

最值归一化结果

均值方差归一化的结果,可以看到各属性值基本符合均值为0、方差为1的分布。

三、调用sklearn库实现数据的归一化

sklearn同样为我们封装好了用于的数据归一化函数,需要使用时直接调用即可。以鸢尾花数据集为例,具体实现如下:

import numpy as np
from sklearn import datasets

iris = datasets.load_iris()
X = iris.data
y = iris.target
print(X[:10,:])

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=666)

from sklearn.preprocessing import StandardScaler
standardScalar = StandardScaler() #实例化一个均值方差归一化对象
standardScalar.fit(X_train) #初始化,将数据传入均值方差归一化对象中
print(standardScalar.mean_) #打印各属性均值
print(standardScalar.scale_) #打印各属性方差

print(X_train[:10,:])
X_train = standardScalar.transform(X_train) #对训练集进行归一化处理
print(X_train[:10,:])

print(X_test[:10,:])
X_test_standard = standardScalar.transform(X_test) #对测试集进行归一化处理
print(X_test_standard[:10,:])

"""使用归一化后的数据进行kNN分类"""

from sklearn.neighbors import KNeighborsClassifier

knn_clf = KNeighborsClassifier(n_neighbors=3)
knn_clf.fit(X_train, y_train) #使用归一化后的训练集

print(knn_clf.score(X_test_standard, y_test)) #进行预测时一定要传入归一化后的测试集,否则算法是有问题的
print(knn_clf.score(X_test, y_test)) #如果传入未归一化的测试集,准确率将非常低

这里有一个陷阱,对测试数据集进行归一化处理时,不能直接对测试数据集按公式进行归一化,而是要使用训练数据集的均值和方差对测试数据集归一化,原因有三:
真实的环境中,数据会源源不断输出进模型,是无法求取均值和方差的。
训练数据集是模拟真实环境中的数据,不能直接使用(无法求出)自身的均值和方差。
在真实环境中,我们无法对单个测试数据进行归一化。

运行后算法的预测准确率如下:

需要重点注意的是,我们在预测的时候一定要在score函数中传入归一化后的数据。从上图我们不难发现,若传入归一化后的数据,算法预测的成功率为100%,而没有传入归一化数据时,算法预测的成功率只有33%,这显然是没有传入归一化数据所导致的。

由于均值方差归一化的适用范围更广,上面的代码只使用了sklearn的StandardScaler类进行数据归一化处理。若我们要使用最值归一化来处理数据,只需要调用MinMaxScaler类即可。调用的步骤是类似的,这里就不再重复了。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注