机器学习【八】数据预处理、降维、特征提取及聚类

数据预处理

手工生成一些数据,用来说明数据预处理的原理和方法

#导入numpy
import numpy as np
#导入画图工具
import matplotlib.pyplot as plt
#导入数据集生成工具
from sklearn.datasets import make_blobs
X,y = make_blobs(n_samples=40,centers=2,random_state=50,cluster_std=2)
#用散点图绘制数据点
plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.cool)
plt.show()

【结果分析】

在使用make_blobs函数时,指定了样本数量n_samples=40,分类centers=2,随机状态random_state=50,标注差cluster_std=2

 

1.使用StandardScaler预处理数据

原理:

将所有数据的特征值转换为均值为0,方差为1的状态——> 确保数据的“大小”一样,更利于模型的训练

#导入StandardScaler
from sklearn.preprocessing import StandardScaler
#使用StandardScaler进行数据预处理
X_1 = StandardScaler().fit_transform(X)
#用散点图绘制预处理的数据点
plt.scatter(X_1[:,0],X_1[:,1],c=y,cmap=plt.cm.cool)
plt.show()

【结果分析】

以上两图,发现数据点的分布情况没有什么不同,但xy轴发生了变化

现在,特征1的数值在-2,3之间

特征2的数值在-3,2之间

 

 

2.使用MinMaxScaler数据预处理

#导入MinMaxScaler
from sklearn.preprocessing import MinMaxScaler
#使用MinMaxScaler进行数据预处理
X_2 = MinMaxScaler().fit_transform(X)
#用散点图绘制预处理的数据点
plt.scatter(X_2[:,0],X_2[:,1],c=y,cmap=plt.cm.cool)
plt.show()

【结果分析】

所有数据的两个特征值都被转换到0-1之间——> 训练速度更快,准确率提高

 

3.使用RobustScaler数据预处理

和StandardScaler近似

使用中位数和四分位数,直接把一些异常值踢出

#导入RobustScaler
from sklearn.preprocessing import RobustScaler
#使用RobustScaler进行数据预处理
X_3 = RobustScaler().fit_transform(X)
#用散点图绘制预处理的数据点
plt.scatter(X_3[:,0],X_3[:,1],c=y,cmap=plt.cm.cool)
plt.show()

【结果分析】

特征1控制在-1.5~2

特征2控制在-2~1.5

 

 4.使用Normalizer数据预处理

将所有样本的特征向量转化为欧几里得距离为1

即,将数据的分布变成一个半径为1的圆(或球)

通常在我们只想保留数据特征向量的方向,而忽略其数值的时候使用

#导入Normalizer
from sklearn.preprocessing import Normalizer
#使用Normalizer进行数据预处理
X_4 = Normalizer().fit_transform(X)
#用散点图绘制预处理的数据点
plt.scatter(X_4[:,0],X_4[:,1],c=y,cmap=plt.cm.cool)
plt.show()

 

 

 

通过数据预处理提高模型的准确率

#导入红酒数据集
from sklearn.datasets import load_wine
#导入MLP神经网络
from sklearn.neural_network import MLPClassifier
#导入数据集拆分工具
from sklearn.model_selection import train_test_split
#建立训练集和测试集
wine = load_wine()
X_train,X_test,y_train,y_test = train_test_split(wine.data,wine.target,random_state=62)
#打印数据形态
print(X_train.shape,X_test.shape)

【结果分析】

已成功将数据集拆分为训练集和测试集。训练集样本数量为133个,测试集样本数量为45个

 

1.用训练集训练一个MLP神经网络,看看在测试集中的得分

#设定MLP神经网络的参数
mlp = MLPClassifier(hidden_layer_sizes=[100,100],max_iter=400,random_state=62)
#使用MLP拟合数据
mlp.fit(X_train,y_train)
#打印得分
print(mlp.score(X_test,y_test))
0.9333333333333333

 2.预处理数据

#使用MinMaxScaler进行数据预处理
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train_pp = scaler.transform(X_train)
X_test_pp = scaler.transform(X_test)
#重新训练模型
mlp.fit(X_train_pp,y_train)
#得分
print(mlp.score(X_test_pp,y_test))
1.0

 【结果分析】

经过数据预处理后,神经网络进行了完美分类

 

 

 

 

数据降维

数据集中,样本往往有很多特征,这些特征都是同样重要的吗?

是否有一些关键特征对预测的结果起着决定性的作用呢?

 

1.PCA主成分分析原理

经过这样的处理后,数据集从一个散点组成的面变成了一条直线,即从二维变成了以为,这就是 数据降维

这里用到的方法,即主成分分析法—— PCA

 

适用数据降维的情况:

  • 超高维度数据
  • 特征之间有非常强烈的相关性【比如,人口数据中,男性为1,女性为0,去掉其中任何一列,不会丢失任何信息,可以降维,以降低模型的复杂度】

 

 

对数据降维以便于进行可视化

#导入数据预处理工具
from sklearn.preprocessing import StandardScaler
#对红酒数据集预处理
scaler = StandardScaler()
X = wine.data
y = wine.target
X_scaled = scaler.fit_transform(X)
#打印处理后的数据集形态
print(X_scaled.shape)
(178, 13)

 接下来导入PCA模块,并对数据进行处理

注意:PCA主成分分析法属于无监督学习算法,所以这里值对X_scaled进行了拟合,而并没有涉及分类标签y

#导入PCA
from sklearn.decomposition import PCA
#设置生成分数量为2以便可视化
pca  = PCA(n_components=2)
pca.fit(X_scaled)
X_pca = pca.transform(X_scaled)
#打印主成分提取后的数据形态
print(X_pca.shape)
(178, 2)

 

#将三个分类中的主成分提取出来
X0 = X_pca[wine.target==0]
X1 = X_pca[wine.target==1]
X2 = X_pca[wine.target==2]
#绘制散点图
plt.scatter(X0[:,0],X0[:,1],c='b',s=60,edgecolor='k')
plt.scatter(X1[:,0],X1[:,1],c='g',s=60,edgecolor='k')
plt.scatter(X2[:,0],X2[:,1],c='r',s=60,edgecolor='k')
#设置图注
plt.legend(wine.target_names,loc='best')
plt.xlabel('component 1')
plt.ylabel('component 2')
plt.show()

【结果分析】

 在之前的章节中,为了进行可视化,只能选取酒数据集的前两个特征,而去掉了其余的11个特征

使用PCA将数据集的特征向量降至二维,从而轻松进行可视化处理,同时不会丢失太多信息

 

原始特征与PCA主成分之间的关系

酒的数据集中的13个原始特征与经过PCA降维处理后的两个主成分是怎样的关系?

#使用主成分绘制热度图
plt.matshow(pca.components_,cmap='plasma')
#纵轴为主成分数
plt.yticks([0,1],['component 1','component 2'])
plt.colorbar()
#横轴为原始特征数量
plt.xticks(range(len(wine.feature_names)),wine.feature_names,rotation=60,ha='left')
plt.show()

【结果分析】

本图中 ,不同的颜色表示一个位于-0.5~0.4之间的数值,分别涉及了13个特征

如果某个特征对应的数字是正数,则说明它和主成分之间是正相关的关系,如果是负数,则相反

 

特征提取

由以上,可以得到:

我们通过对数据集原来的特征进行转换,生成新的“特征”或者说“成分”,会比直接使用原始的特征效果更好

 

1.PCA主成分分析法用于特征提取

这次使用一个复杂一点的数据集——LFW人脸识别数据

#导入数据集获取工具
from sklearn.datasets import fetch_lfw_people
#载入人脸数据集
faces = fetch_lfw_people(min_faces_per_person=20,resize=0.8)
image_shape = faces.images[0].shape
#将照片打印出来
fig,axes = plt.subplots(3,4,figsize=(12,9),subplot_kw={'xticks':(),'yticks':()})
for target,image,ax in zip(faces.target,faces.images,axes.ravel()):
    ax.imshow(image,cmap=plt.cm.gray)
    ax.set_title(faces.target_names[target])
plt.show()

 

接下来,再未经处理的情况下,尝试训练一个神经网络:

#导入神经网络
from sklearn.neural_network import MLPClassifier
#对数据集拆分
X_train,X_test,y_train,y_test = train_test_split(faces.data/255,faces.target,random_state=62)
#训练神经网络
mlp=MLPClassifier(hidden_layer_sizes=[100,100],random_state=62,max_iter=400)
mlp.fit(X_train,y_train)
print(mlp.score(X_test,y_test))

 

0.7477064220183486

【结果分析】 

 在使用2个节点数为100的隐藏层时,神经网络的识别准确率只有0.74

 

2.使用一些方法来提升模型的表现

A.PCA中的数据白化功能

 虽然每个人的面部特征由很大差异,但从像素级别观察图像,差异并不大

且相邻的像素之间有很大的相关性,这样一来,基本特征的输入就是冗余的了,白化的目的就是未了降低冗余性

所以,白化的过程会让样本特征之间的相关度降低,且所有特征具有相同的方差

 

#使用白化功能处理人脸数据
pca = PCA(whiten=True,n_components=0.9,random_state=62).fit(X_train)
X_train_whiten = pca.transform(X_train)
X_test_whiten = pca.transform(X_test)
#打印白化后数据形态
print(X_train_whiten.shape)
(1306, 99)

 【结果分析】

 这里我们要求保留原始特征中90%的信息,所以n_components=0.9

 可见,经过PCA白化处理后的数据成分为99个,远远小于原始特征数量

 

#使用白化后的数据训练神经网络
mlp.fit(X_train_whiten,y_train)
print(mlp.score(X_test_whiten,y_test))
0.7293577981651376

 【结果分析】

书上的得分分别是:神经网络:0.52    PCA 0.57 ——> PCA的数据白化功能对于提高神经网络的准确率是有一定帮助的

 

B.非负矩阵分解用于特征提取

NMF, 也是一种无监督学习算法

矩阵分解就是一个把矩阵拆解为n个矩阵的乘积

非负矩阵分解,就是原始的矩阵中所有的数值必须大于或等于0,当然分解之后的矩阵中数据也是大于或等于0的

#导入NMF
from sklearn.decomposition import NMF
nmf = NMF(n_components=105,random_state=62).fit(X_train)
X_train_nmf = nmf.transform(X_train)
X_test_nmf = nmf.transform(X_test)
#打印NMF处理后的数据形态
print(X_train_nmf.shape)
(1306, 105)

 【结果分析】

 NMF的n_components参数不支持使用浮点数,只能设置为正的整型数

#使用NMF处理后的数据训练神经网络
mlp.fit(X_train_nmf,y_train)
print(mlp.score(X_test_nmf,y_test))
0.7591743119266054

 

 聚类算法

有监督学习——主要用于——> 分类和回归

无监督学习——主要用于——> 聚类

 

分类是算法基于已有标签的数据进行学习并对新数据进行分类

聚类是在完全没有现有标签的情况下,由算法“猜测”哪些数据像是应该“堆”在一起的,并且让算法给不同“堆”里的数据贴上一个数字标签

 

1.K均值算法

#导入数据集生成工具
from sklearn.datasets import make_blobs
#生成分类数为1的数据集
blobs = make_blobs(random_state=1,centers=1)
X_blobs = blobs[0]
#绘制散点图
plt.scatter(X_blobs[:,0],X_blobs[:,1],c='r',edgecolor='k')
plt.show()

【结果分析】

 这段代码,主要是生成一坨没有类别的数据点

make_blobs的centers参数为1,因此这些数据都属于1类

 

使用K均值帮助这些数据进行聚类:

#导入KMeans工具
from sklearn.cluster import KMeans
#要求KMeans将数据聚为3类
kmeans = KMeans(n_clusters=3)
#拟合数据
kmeans.fit(X_blobs)
#画图
x_min,x_max =  X_blobs[:,0].min() -0.5,X_blobs[:,0].max() +0.5
y_min,y_max =  X_blobs[:,1].min() -0.5,X_blobs[:,1].max() +0.5
xx,yy = np.meshgrid(np.arange(x_min,x_max,.02),np.arange(y_min,y_max,.02))
Z = kmeans.predict(np.c_[(xx.ravel(),yy.ravel())])
#将每个分类中的样本分配不同的颜色
Z = Z.reshape(xx.shape)
plt.figure(1)
plt.imshow(Z,interpolation='nearest',extent=(xx.min(),xx.max(),yy.min(),yy.max()),cmap=plt.cm.summer,aspect='auto',origin='lower')
plt.plot(X_blobs[:,0],X_blobs[:,1],'r.',markersize=5)
#用蓝色叉号表示聚类的中心
centroids = kmeans.cluster_centers_
plt.scatter(centroids[:,0],centroids[:,1],marker='x',s=150,linewidth=3,color='b',zorder=10)
plt.xlim(x_min,x_max)
plt.ylim(y_min,y_max)
plt.xticks(())
plt.yticks(())
plt.show()

【结果分析】

 n_clusters=3,所以K均值将数据点聚为3类

图中的3个蓝色X,代表了K均值对数据进行聚类的3个中心

 

那么K均值怎样来表示这些聚类?

#打印KMeans进行聚类的标签
print(kmeans.labels_)

【结果分析】

 K均值对数据进行的聚类和分类有些类似,是用0、1、2三个数字来代表数据的类,并且存储在 .labels_ 属性中

局限性:

认为每个数据点到聚类中心的方向都是同等重要的——> 对于形状复杂的数据集,K均值算法就不能很好工作

 

 

2.凝聚聚类算法

 

用图像对凝聚算法的工作机制说明:

#导入dendrogram和ward工具
from scipy.cluster.hierarchy import dendrogram,ward
#使用连线的方式可视化
linkage = ward(X_blobs)
dendrogram(linkage)
ax = plt.gca()
plt.xlabel("sample index")
plt.ylabel("cluster distance")
plt.show()

 【结果分析】

 凝聚聚类算法是自下而上,不断合并相似的聚类中心,以便让类别变少

同时,每个聚类中心的距离也就越来越远

这种逐级生成的聚类方法为:Hierarchy clustering

但,凝聚聚类算法也无法对“形状复杂的数据进行正确的聚类

 

 

3.DBSCAN算法

 基于密度的有噪声应用空间聚类

通过对特征空间内的密度进行检测,密度大的地方,它会认为是一个类,而密度较小的地方,它会认为是一个分界线

 

再用之前生成的数据集来展示一下DBSCAN的工作机制:

#导入DBSCAN
from sklearn.cluster import DBSCAN
db = DBSCAN()
#使用DBSCAN拟合数据
clusters = db.fit_predict(X_blobs)
#绘制散点图
plt.scatter(X_blobs[:,0],X_blobs[:,1],c=clusters,cmap=plt.cm.cool,s=60,edgecolor='k')
plt.xlabel("feature 0")
plt.ylabel("feature 1")
plt.show()

#打印聚类个数
print(clusters)

【结果分析】

 -1 代表该数据是噪声

中间深色的数据点密度相对较大,所以DBSCAN把它归为一坨

而外围的浅色数据点,DBSCAN认为根本不属于任何一类,所以放在“噪声”一类

 

eps参数,指考虑化入同一“坨”的样本距离多远

默认0.5

#设置DBSCAN参数eps=2
db_1 = DBSCAN(eps=2)
#使用DBSCAN拟合数据
clusters_1 = db_1.fit_predict(X_blobs)
#绘制散点图
plt.scatter(X_blobs[:,0],X_blobs[:,1],c=clusters_1,cmap=plt.cm.cool,s=60,edgecolor='k')
plt.xlabel("feature 0")
plt.ylabel("feature 1")
plt.show()

min_samples参数,指定再某个数据点周围,被看成是聚类核心点的个数。越大,则核心数据点越少,噪声就越多

默认是2

#设置DBSCAN的最小样本数为20
db_2 = DBSCAN(min_samples=20)
#使用DBSCAN拟合数据
clusters_2 = db_2.fit_predict(X_blobs)
#绘制散点图
plt.scatter(X_blobs[:,0],X_blobs[:,1],c=clusters_2,cmap=plt.cm.cool,s=60,edgecolor='k')
plt.xlabel("feature 0")
plt.ylabel("feature 1")
plt.show()

 【结果分析】

浅色的数据,也就是噪声变多了

深色的数据,也就是聚类中被划为类别1的数据点少了

 

 

对于机器学习来说,合理有效地对数据进行表达是至关重要的

对于没有分类标签的数据来说,无监督学习的聚类算法可以帮助我们更好的理解数据集,并且为进一步训练模型打好基础

 

posted @ 2019-05-06 19:48  远征i  阅读(4198)  评论(0编辑  收藏