无监督学习与sklearn库

故事扮演 提交于 2020-03-30 22:40:19

一、无监督学习基础知识

利用无标签的数据学习数据的分布或数据与数据之间的关系被称作无监督学习

有监督学习和无监督学习的最大区别在于数据是否有标签

无监督学习最常应用的场景是聚类(Clustering)降维(Dimension Reduction)

二、聚类

聚类是根据数据的“相似性”将数据分为多类的过程。评估两个不同样本之间的“相似性”,通常使用的方法就是计算两个样本之间的“距离”。使用不同的方法计算样本间的距离会关系到聚类结果的好坏

1、欧氏距离

欧氏距离是最常用的一种距离度量方法,源于欧式空间中两点的距离

2、曼哈顿距离

曼哈顿距离也称作“城市街区距离”,类似于在城市之中驾车行驶,从一个十字路口到另一个十字路口的距离

3、马氏距离

马氏距离表示数据的协方差距离,是一种尺度无关的度量方式。马氏距离会先将样本点的各个属性标准化,再计算样本间的距离

4、夹角余弦

余弦相似度用向量空间中两个向量夹角的余弦值作为衡量两个样本差异的大小。余弦值越接近于1,说明两个向量夹角越接近0度,表明两个向量越相似

5、sklearn库

scikit-learn库(简称sklearn库)提供的常用聚类算法函数包含在sklearn.cluster这个模块中,如:k-means,近邻传播算法,DBSCAN等。以同样的数据集应用于不同的算法,可能会得到不同的结果,算法所耗费的时间也不尽相同,这是由算法的特性决定的

sklearn.cluster模块提供的各聚类算法函数可以使用不同的数据形式作为输入:

标准数据输入格式:[样本个数,特征个数]定义的矩阵形式

相似性矩阵输入格式:即由[样本数目]定义的矩阵形式,矩阵中的每一个元素为两个样本的相似度,如DBSCAN,AffinityPropagation(近邻传播算法)接收这种输入。以余弦相似度为例,对角线元素全为1,矩阵中每个元素的取值范围为[0,1]

sklearn.cluster模块

算法名称 参数   可扩展性 相似性度量
k-means 聚类个数 大规模数据 点间距离
DBSCAN 邻域大小
大规模数据 点间距离
Gaussian Mixtures 聚类个数及其他超参 复杂度较高,不适合处理大规模数据 马氏距离
Birch 分支因子,阈值等其他超参 大规模数据 两点间的欧氏距离

三、降维

降维是在保证数据所具有的特征或分布的情况下,将高维数据转化为低纬数据的过程。常用于数据可视化和精简数据

聚类和分类都是无监督学习的典型任务,任务之间存在关联,比如某些高维数据的分类可以通过降维处理更好的获得,另外学界研究也表明代表性的分类算法如k-means与降维算法如NMF之间存在等价性

降维是机器学习领域的一个重要研究内容,有很多被工业界和学术界接收的典型算法,截止到目前sklearn提供7种降维算法

降维过程也可以理解为对数据集的组成成分进行分解(decomposition)的过程,因此sklearn为降维模块命名为decomposition,在对降维算法调用需要使用sklearn.decomposition模块

sklearn.decomposition模块

算法名称 参数 可扩展性 适用任务 
PCA 所降维度及其他超参 大规模数据 信号处理等
FastICA 所降维度及其他超参 超大规模数据 图形图像特征提取
NMF 所降维度及其他超参 大规模数据 图形图像特征提取
LDA 所降维度及其他超参 大规模数据 文本数据,主题挖掘

四、算法

1k-means聚类算法

(1)基础知识

k-means算法以k为参数,把n个对象分成k个簇,使簇内具有较高的相似度,而簇间的相似度较低

(2)k-means聚类算法流程

①    随机选择k个点作为初始的聚类中心;

②    对于剩下的点,根据其与聚类中心的距离,将其归入最近的簇

③    对每个簇,计算所有点的均值作为新的聚类中心

④    重复②、③直到聚类中心不再发生改变

(3)具体应用

①数据介绍

现有1999年全国31个省份城镇居民家庭平均每人全年消费性支出的八个主要变量数据,这八个变量分别是:食品、衣着、家庭设备用品及服务、医疗 保健、交通和通讯、娱乐教育文化服务、居住以及杂项商品和服务。利用已有数据,对31个省份进行聚类

②实验目的

通过聚类,了解1999年各个省份的消费水平在国内的情况

③数据实例

④文本内容

⑤实现过程

a、 建立工程,导入sklearn相关包

b、 加载数据,创建k-means算法实例,并进行训练,获得标签

c、  输出标签,查看结果

⑥结果演示

聚成4类

聚成2类

原代码

1 ......
2 km = KMeans(n_clusters=4) #聚成4类
3 ......
4 CityCluster = [[], [], [], []] #将城市按label分成设定的簇
5 ......

修改为

1 ......
2 km = KMeans(n_clusters=2) #聚成2类
3 ......
4 CityCluster = [[], []] #将城市按label分成设定的簇
5 ......

结果为

聚成3类

原代码

1 ......
2 km = KMeans(n_clusters=4) #聚成4类
3 ......
4 CityCluster = [[], [], [], []] #将城市按label分成设定的簇
5 ......

修改为

1 ......
2 km = KMeans(n_clusters=3) #聚成3类
3 ......
4 CityCluster = [[], [], []] #将城市按label分成设定的簇
5 ......

结果为

(4)代码分析

①完整代码

 1 import numpy as np
 2 from sklearn.cluster import KMeans
 3 
 4 def loadData(filePath):
 5     fr = open(filePath, 'r+')
 6     lines = fr.readlines()
 7     retData = [] #存储城市的各项消费信息
 8     retCityName = [] #存储城市名称
 9     for line in lines:
10         items = line.strip().split(",")
11         retCityName.append(items[0])
12         retData.append([float(items[i]) for i in range(1, len(items))])
13     return retData, retCityName
14 
15 
16 if __name__ == '__main__':
17     data, cityName = loadData('city.txt') #利用loadData()方法读取数据
18     km = KMeans(n_clusters=4) #聚成4类
19     label = km.fit_predict(data) #label为聚类后各数据所属的标签,fit_predict()方法计算簇中心以及为簇分配序号
20     expenses = np.sum(km.cluster_centers_, axis=1) #expenses为聚类中心点的数值加和,也就是平均消费水平
21     # print(expenses)
22     CityCluster = [[], [], [], []] #将城市按label分成设定的簇
23     for i in range(len(cityName)):
24         CityCluster[label[i]].append(cityName[i]) #将每个簇的城市输出
25     for i in range(len(CityCluster)):
26         print("Expenses:%.2f" % expenses[i])
27         print(CityCluster[i]) #将每个簇的平均花费输出

②关于相关包的介绍

NumPy是Python语言的一个扩充程序库。支持高级大量的维度数组与矩阵运算,此外也针对数组 运算提供大量的数学函数库。

使用sklearn.cluster.KMeans可以调用K-means算法进行聚类

③调用KMeans()方法所需参数

n_clusters:用于指定聚类中心的个数

init:初始聚类中心的初始化方法

max_iter:最大的迭代次数

一般调用时只用给出n_clusters即可,init 默认是k-means++,max_iter默认是300

④loadData()方法解释

fr = open(filePath,'r+')

lines = fr.readlines()

r+:读写打开一个文本文件

.read() 每次读取整个文件,它通常用于将文件内容放到一个字符串变量中

.readlines() 一次读取整个文件(类似于 .read() )

.readline() 每次只读取一行,通常比 .readlines() 慢得多。仅当没有足够内存可以一次读取整个文件时,才应该使用.readline()

2DBSCAN密度聚类

(1)基础知识

DBSCAN算法是一种基于密度的聚类算法:

聚类的时候不需要预先指定簇的个数

最终的簇的个数不定

DBSCAN算法将数据点分为三类:

核心点:在半径Eps内含有超过MinPts数目的点

边界点:在半径Eps内点的数量小于MinPts,但是落在核心点的邻域内

噪音点:既不是核心点也不是边界点的点

 

(2)DBSCAN算法流程

①将所有点标记为核心点、边界点或噪声点

②删除噪声点

③为距离在Eps之内的所有核心点之间赋予一条边

④每组连通的核心点形成一个簇

⑤将每个边界点指派到一个与之关联的核心点的簇中(哪一个核心点的半径范围之内)

示例:

有如下13个样本点,使用DBSCAN进行聚类

取Eps=3,MinPts=3,依据DBSACN对所有点进行聚类(曼哈顿距离)

对每个点计算其邻域Eps=3内的点的集合

集合内点的个数超过 MinPts=3的点为核心点

查看剩余点是否在核心点的邻域内,若在,则为边界点,否则为噪声点

将距离不超过Eps=3的点相互连接,构成一个簇,核心点邻域内的点也会被加入到这个簇中,则形成3个簇

(3)具体应用

①数据介绍

现有大学校园网的日志数据,290条大学生的校园网使用情况数据,数据包括用户ID,设备的MAC地址,IP地址,开始上网时间,停止上网时间,上网时长,校园网套餐等。利用已有数据,分析学生上网的模式

②实验目的

通过DBSCAN聚类,分析学生上网时间的模式

③数据实例

④文本内容

⑤实现过程

a、建立工程,导入sklearn相关包

b、读入数据并进行处理

c、上网时间聚类,创建DBSCAN算法实例,并进行训练,获得标签

d、输出标签,查看结果

e、画直方图,分析实验结果

⑥结果演示

Labels为每个数据被划分的簇的分类

Noise raito为噪声数据的比例

Estimated number of clusters为簇的个数

Silhouette Coefficient为聚类效果评价指标

上网时间大多集中在22至24点

(4)代码分析

①完整代码

 1 import numpy as np
 2 import sklearn.cluster as skc
 3 from sklearn import metrics
 4 import matplotlib.pyplot as plt
 5 
 6 mac2id = dict()
 7 onlinetimes = []
 8 f = open('TestData.txt', encoding='utf-8')
 9 for line in f:
10     mac = line.split(',')[2] #读取每条数据中的mac地址
11     onlinetime = int(line.split(',')[6]) #上网时长
12     starttime = int(line.split(',')[4].split(' ')[1].split(':')[0]) #开始上网时间
13     if mac not in mac2id: #mac2id是一个字典,key是mac地址,value是对应mac地址的上网时长及开始上网时间
14         mac2id[mac] = len(onlinetimes)
15         onlinetimes.append((starttime, onlinetime))
16     else:
17         onlinetimes[mac2id[mac]] = [(starttime, onlinetime)]
18 real_X = np.array(onlinetimes).reshape((-1, 2))
19 
20 X = real_X[:, 0:1]
21 
22 db = skc.DBSCAN(eps=0.01, min_samples=20).fit(X) #调用DBSCAN方法进行训练
23 labels = db.labels_ #labels为每个数据的簇标签
24 
25 print('Labels:')
26 print(labels)
27 raito = len(labels[labels[:] == -1]) / len(labels)
28 print('Noise raito:', format(raito, '.2%')) #打印数据被记上的标签,计算标签为-1,即噪声数据的比例
29 
30 n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
31 
32 print('Estimated number of clusters: %d' % n_clusters_)
33 print("Silhouette Coefficient: %0.3f" % metrics.silhouette_score(X, labels)) #计算簇的个数并打印,评价聚类效果
34 
35 for i in range(n_clusters_): #打印各簇标号以及各簇内数据
36     print('Cluster ', i, ':')
37     print(list(X[labels == i].flatten()))
38 
39 plt.hist(X, 24)
40 plt.show() #画直方图

②DBSCAN()方法主要参数

eps: 两个样本被看作邻居节点的最大距离

min_samples: 簇的样本数

metric:距离计算方式

3、PCA方法(主成分分析)

(1)基础知识

主成分分析(Principal Component Analysis,PCA)是最常用的一种降维方法,通常用于高维数据集的探索与可视化,还可以用作数据压缩和预处理等。PCA可以把具有相关性的高维变量合成为线性无关的低维变量,称为主成分,主成分能够尽可能保留原始数据的信息

在介绍PCA的原理之前需要回顾涉及到的相关术语:

①方差

方差是各个样本和样本均值的差的平方和的均值,用来度量一组数据的分散程度

②协方差

协方差用于度量两个变量之间的线性相关性程度,若两个变量的协方差为0,则可认为二者线性无关

③协方差矩阵

协方差矩阵则是由变量的协方差值构成的矩阵(对称阵)

④特征向量和特征值

矩阵的特征向量是描述数据集结构的非零向量,并满足如下公式:

A是方阵,是特征向量,是特征值

矩阵的主成分就是其协方差矩阵对应的特征向量,按照对应的特征值大小进行排序,最大的特征值就是第一主成分,其次是第二主成分,以此类推

(2)PCA算法流程

(3)具体应用

①数据介绍

鸢尾花数据集来自于Python的sklearn库

②实验目的

已知鸢尾花数据是4维的,共三类样本。使用PCA实现对鸢尾花数据进行降维,实现在二维平面上的可视化

③数据实例

④结果演示

可以看出,降维后的数据仍能够清晰地分成三类。这样不仅能削减数据的维度,降低分类任务的工作量,还能保证分类的质量

(4)完整代码

 1 import matplotlib.pyplot as plt #加载matplotlib用于数据的可视化
 2 from sklearn.decomposition import PCA #加载PCA算法包
 3 from sklearn.datasets import load_iris #加载鸢尾花数据集导入函数
 4 
 5 data = load_iris()  #以字典形式加载鸢尾花数据集
 6 y = data.target     #使用y表示数据集中的标签
 7 X = data.data       #使用X表示数据集中的属性数据
 8 pca = PCA(n_components=2) #加载PCA算法,设置降维后主成分数目为2
 9 reduced_X = pca.fit_transform(X) #对原始数据进行降维,保存在reduced_X中
10 
11 red_x, red_y = [], []       #第一类数据点
12 blue_x, blue_y = [], []     #第二类数据点
13 green_x, green_y = [], []   #第三类数据点
14 
15 for i in range(len(reduced_X)): #按照鸢尾花的类别将降维后的数据点保存在不同的列表中
16     if y[i] == 0:
17         red_x.append(reduced_X[i][0])
18         red_y.append(reduced_X[i][1])
19     elif y[i] == 1:
20         blue_x.append(reduced_X[i][0])
21         blue_y.append(reduced_X[i][1])
22     else:
23         green_x.append(reduced_X[i][0])
24         green_y.append(reduced_X[i][1])
25 
26 plt.scatter(red_x, red_y, c='r', marker='x')        #第一类数据点
27 plt.scatter(blue_x, blue_y, c='b', marker='D')      #第二类数据点
28 plt.scatter(green_x, green_y, c='g', marker='.')    #第三类数据点
29 plt.show()  #可视化

 4、NMF方法(非负矩阵分解)

(1)基础知识

非负矩阵分解(Non-negative Matrix Factorization ,NMF)是在矩阵中所有元素均为非负数约束条件之下的矩阵分解方法

基本思想:给定一个非负矩阵V,NMF能够找到一个非负矩阵W和一个非负矩阵H,使得矩阵W和H的乘积近似等于矩阵V中的值

 

 

W矩阵:基础图像矩阵,相当于从原矩阵V中抽取出来的特征

H矩阵:系数矩阵

NMF能够广泛应用于图像分析、文本挖掘和语音处理等领域

上图摘自NMF作者的论文,左侧为W矩阵,可以看出从原始图像中抽取出来的特征,中间的是H矩阵。可以发现乘积结果与原结果是很像的

矩阵分解优化目标:最小化W矩阵H矩阵的乘积和原始矩阵之间的差别

目标函数如下:

基于KL散度的优化目标,损失函数如下:

(2)具体应用

①数据介绍

Olivetti人脸数据共 400个,每个数据是64*64大小

②实验目的

由于NMF分解得到的W矩阵相当于从原始矩阵中提取的特征,那么就可以使用NMF对400个Olivetti人脸数据进行特征提取

③数据实例

④实验方法

通过设置k的大小,设置提取的特征的数目。在本实验中设置k=6,随后将提取的特征以图像的形式展示出来

⑤结果演示

(3)代码分析

①完整代码

 1 from numpy.random import RandomState #加载RandomState用于创建随机种子
 2 import matplotlib.pyplot as plt #加载matplotlib用于数据的可视化
 3 from sklearn.datasets import fetch_olivetti_faces #加载Olivetti人脸数据集导入函数
 4 from sklearn import decomposition #加载PCA算法包
 5 
 6 n_row, n_col = 2, 3 #设置图像展示时的排列情况
 7 n_components = n_row * n_col #设置提取的特征的数目
 8 image_shape = (64, 64) #设置人脸数据图片的大小
 9 
10 ###############################################################################
11 # Load faces data
12 dataset = fetch_olivetti_faces(shuffle=True, random_state=RandomState(0))
13 faces = dataset.data #加载数据,并打乱顺序
14 
15 
16 ###############################################################################
17 def plot_gallery(title, images, n_col=n_col, n_row=n_row):
18     plt.figure(figsize=(2. * n_col, 2.26 * n_row)) #创建图片并指定图片大小
19     plt.suptitle(title, size=16) #设置标题及字号大小
20 
21     for i, comp in enumerate(images):
22         plt.subplot(n_row, n_col, i + 1) #选择画制的子图
23         vmax = max(comp.max(), -comp.min())
24 
25         plt.imshow(comp.reshape(image_shape), cmap=plt.cm.gray,
26                    interpolation='nearest', vmin=-vmax, vmax=vmax) #对数值归一化,并以灰度图形式显示
27         plt.xticks(())
28         plt.yticks(()) #去除子图的坐标轴标签
29     plt.subplots_adjust(0.01, 0.05, 0.99, 0.94, 0.04, 0.) #对子图位置及间隔调整
30 
31 
32 plot_gallery("First centered Olivetti faces", faces[:n_components])
33 ###############################################################################
34 
35 estimators = [
36     ('Eigenfaces - PCA using randomized SVD',
37      decomposition.PCA(n_components=6, whiten=True)), #PCA实例
38 
39     ('Non-negative components - NMF',
40      decomposition.NMF(n_components=6, init='nndsvda', tol=5e-3)) #NMF实例
41 ] #将它们存放在一个列表中
42 
43 ###############################################################################
44 
45 for name, estimator in estimators:
46     print("Extracting the top %d %s..." % (n_components, name))
47     print(faces.shape) #分别调用PCA和NMF
48     estimator.fit(faces) #调用PCA或NMF提取特征
49     components_ = estimator.components_ #获取提取的特征
50     plot_gallery(name, components_[:n_components]) #按固定格式进行排列
51 
52 plt.show() #可视化

②NMF()方法参数

在sklearn库中,可以使用sklearn.decomposition.NMF加载NMF算法,主要参数有:

n_components:用于指定分解后矩阵的单个维度k

init:W矩阵和H矩阵的初始化方式,默认为‘nndsvdar’

资料来源:《Python机器学习应用》——礼欣,嵩天北京理工大学,MOOC

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!