【第一周】无监督学习

2018-10-15  本文已影响38人  juriau

1、无监督学习简介

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


(1)、聚类(clustering)

聚类(clustering),就是根据数据的“相似性”将数据分为多类的过程

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

image.png

->一些常用的距离概念(4个)以及计算方法

image.png image.png image.png image.png

–>关于sklearn

sklearn中的聚类算法包含在sklearn.cluster这个模块中,如:K-Means,近邻传播算法,DBSCAN等。

以同样的数据集应用于不同的算法,可能会得到不同的结果,算法所耗费的时间也不尽相同,这是由算法的特性决定的。

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

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

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

image.png

(2)、降维

降维,就是在保证数据所具有的代表性 特性或者分布的情况下,将高维数据转化为 低维数据的过程:

–>关于sklearn

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

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

image.png

2、无监督学习-聚类

(1)K-means方法及应用

算法原理:
k-means算法以k为参数,把n个对象分成k个簇,使簇内具有较高的相似度,而簇间的相似度较低。其处理过程如下:
1.随机选择k个点作为初始的聚类中心;
2.对于剩下的点,根据其与聚类中心的距离,将其归入最近的簇
3.对每个簇,计算所有点的均值作为新的聚类中心
4.重复2、3直到聚类中心不再发生改变

image.png

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

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

技术路线:
sklearn.cluster.Kmeans

调用KMeans方法所需参数:

  • n_clusters:用于指定聚类中心的个数
  • init:初始聚类中心的初始化方法
  • max_iter:最大的迭代次数
    注:一般调用时只用给出n_clusters即可,init默认是k-means++,max_iter默认是300

其它参数:

  • data:加载的数据
  • label:聚类后各数据所属的标签
  • axis: 按行求和
  • fit_predict():计算簇中心以及为簇分配序号

数据实例

image.png
数据文件(city.txt):
城市名称、食品、 衣着、 家庭设备用品及服务、 医疗保健、 交通和通讯、 娱乐教育文化服务、 居住以及杂项商品和服务
北京,2959.19,730.79,749.41,513.34,467.87,1141.82,478.42,457.64
天津,2459.77,495.47,697.33,302.87,284.19,735.97,570.84,305.08
河北,1495.63,515.90,362.37,285.32,272.95,540.58,364.91,188.63
山西,1406.33,477.77,290.15,208.57,201.50,414.72,281.84,212.10
内蒙古,1303.97,524.29,254.83,192.17,249.81,463.09,287.87,192.96
辽宁,1730.84,553.90,246.91,279.81,239.18,445.20,330.24,163.86
吉林,1561.86,492.42,200.49,218.36,220.69,459.62,360.48,147.76
黑龙江,1410.11,510.71,211.88,277.11,224.65,376.82,317.61,152.85
上海,3712.31,550.74,893.37,346.93,527.00,1034.98,720.33,462.03
江苏,2207.58,449.37,572.40,211.92,302.09,585.23,429.77,252.54
浙江,2629.16,557.32,689.73,435.69,514.66,795.87,575.76,323.36
安徽,1844.78,430.29,271.28,126.33,250.56,513.18,314.00,151.39
福建,2709.46,428.11,334.12,160.77,405.14,461.67,535.13,232.29
江西,1563.78,303.65,233.81,107.90,209.70,393.99,509.39,160.12
山东,1675.75,613.32,550.71,219.79,272.59,599.43,371.62,211.84
河南,1427.65,431.79,288.55,208.14,217.00,337.76,421.31,165.32
湖南,1942.23,512.27,401.39,206.06,321.29,697.22,492.60,226.45
湖北,1783.43,511.88,282.84,201.01,237.60,617.74,523.52,182.52
广东,3055.17,353.23,564.56,356.27,811.88,873.06,1082.82,420.81
广西,2033.87,300.82,338.65,157.78,329.06,621.74,587.02,218.27
海南,2057.86,186.44,202.72,171.79,329.65,477.17,312.93,279.19
重庆,2303.29,589.99,516.21,236.55,403.92,730.05,438.41,225.80
四川,1974.28,507.76,344.79,203.21,240.24,575.10,430.36,223.46
贵州,1673.82,437.75,461.61,153.32,254.66,445.59,346.11,191.48
云南,2194.25,537.01,369.07,249.54,290.84,561.91,407.70,330.95
西藏,2646.61,839.70,204.44,209.11,379.30,371.04,269.59,389.33
陕西,1472.95,390.89,447.95,259.51,230.61,490.90,469.10,191.34
甘肃,1525.57,472.98,328.90,219.86,206.65,449.69,249.66,228.19
青海,1654.69,437.77,258.78,303.00,244.93,479.53,288.56,236.51
宁夏,1375.46,480.89,273.84,317.32,251.08,424.75,228.73,195.93
新疆,1608.82,536.05,432.46,235.82,250.28,541.30,344.85,214.40

代码

import numpy as np
from sklearn.cluster import KMeans


def loadData(filePath):
    '''
    将文本文件中的数据保存到retData、retCityName这两个变量中并返回
    '''
    fr = open(filePath,'r+',encoding='utf-8')#读写打开一个文本文件
    lines = fr.readlines()
    retData = []            #用来存储城市的各项消费信息
    retCityName = []        #用来存储城市名称
    for line in lines:
        items = line.strip().split(",")
        retCityName.append(items[0])
        retData.append([float(items[i]) for i in range(1,len(items))])
    return retData,retCityName


if __name__ == '__main__':
    data,cityName = loadData('/Users/fanhaojie/Desktop/city.txt')

    # 形成4组簇以及4个聚类中心
    km = KMeans(n_clusters=4)
    # 计算聚类中心并预测每个样本的聚类索引,label为每行数据对应分配到的簇序号
    label = km.fit_predict(data)
    print('label:\n',label)
    print('\nkm.cluster_centers_:\n',km.cluster_centers_)
    
    expenses = np.sum(km.cluster_centers_,axis=1)# 按行求和
    print('\nexpenses:\n',expenses,'\n')
    
    CityCluster = [[],[],[],[]]
    #将在同一个簇的城市保存在同一个list中
    for i in range(len(cityName)):
        CityCluster[label[i]].append(cityName[i])
        
    #输出各个簇的平均消费数和对应的城市名称
    for i in range(len(CityCluster)):
        print("Expenses:%.2f" % expenses[i])
        print(CityCluster[i])

输出

label:
 [3 1 0 0 0 0 0 0 3 2 1 2 1 0 0 0 2 2 3 2 2 1 2 0 2 1 0 0 0 0 0]

km.cluster_centers_:
 [[1525.81533333  478.672       322.88266667  232.4         236.41866667
   457.53133333  344.81866667  190.21933333]
 [2549.658       582.118       488.366       268.998       397.442
   618.92        477.946       295.172     ]
 [2004.785       429.48        347.8925      190.955       287.66625
   581.16125     437.2375      233.09625   ]
 [3242.22333333  544.92        735.78        405.51333333  602.25
  1016.62        760.52333333  446.82666667]]

expenses:
 [3788.758      5678.62       4512.27375    7754.65666667] 

Expenses:3788.76
['河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '江西', '山东', '河南', '贵州', '陕西', '甘肃', '青海', '宁夏', '新疆']
Expenses:5678.62
['天津', '浙江', '福建', '重庆', '西藏']
Expenses:4512.27
['江苏', '安徽', '湖南', '湖北', '广西', '海南', '四川', '云南']
Expenses:7754.66
['北京', '上海', '广东']

从结果可以看出消费水平相近的省市聚集在了一类,例如消费最高的“北京”“上海”“广东” 聚集在了消费最高的类别。聚4类时,结果可以比较明显的看出消费层级。

注:KMeans的官方API地址:http://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans

注:文件的read、readlines、readline三个方法的区别


image.png

Sklearn中KMeans算法的改进

计算两条数据相似性时,Sklearn 的K-Means默认用的是欧式距离。 虽然还有余弦相似度,马氏距离等多种方法,但没有设定计算距离方法的参数。

阅读k_means_.py源码,可以发现在计算向量和簇中心的距离时,使用的是欧式距离(euclidean_distances)。


image.png

可以考虑修改euclidean_distances这个函数为 scipy.spatial.distance.cdist 函数。

scipy.spatial.distance.cdist函数使用方法:


image.png

该函数中的metric参数可供选择不同的距离计算方法。

(1)DBSCAN方法及应用

->基本介绍

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

->算法原理

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

DBSCAN算法流程:

1.将所有点标记为核心点、边界点或噪声点;

2.删除噪声点;

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

4.每组连通的核心点形成一个簇;

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

->算法举例

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


image.png

step1:


image.png

step2:


image.png

step3:


image.png

->应用

数据介绍:

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

实验目的:

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

技术路线:

sklearn.cluster.DBSCAN

调用DBSCAN方法所需参数:

eps: 两个样本被看作邻居节点的最大距离
min_samples: 簇的样本数
metric:距离计算方式

例:sklearn.cluster.DBSCAN(eps=0.5, min_samples=5, metric=’euclidean’)

数据实例:

image.png

实现过程:

image.png

实现代码:

->对上网开始时间进行聚类

import numpy as np
from sklearn.cluster import DBSCAN
from sklearn import metrics#计算方法
import matplotlib.pyplot as plt


mac2id=dict()
onlinetimes=[]
f=open('TestData.txt',encoding='utf-8')
for line in f:
    items = line.strip().split(",")
    #mac地址
    mac=items[2]
    #上网时长
    onlinetime=int(items[6])
    #时间格式举例:2014-07-20 22:44:18.540000000
    starttime=int(items[4].split(' ')[1].split(':')[0])#只保留时间的小时位

    #保证onlinetime中对应一个mac地址有一个唯一的记录
    if mac not in mac2id:
        mac2id[mac]=len(onlinetimes)
        onlinetimes.append((starttime,onlinetime))
    else:
        onlinetimes[mac2id[mac]]=(starttime,onlinetime)

real_X=np.array(onlinetimes).reshape((-1,2)) #-1代表行数由程序自行根据列数和总数据信息推算出

X=real_X[:,0:1]#只得到上网(开始)时间

#调用DBSCAN方法进行训练,labels为每个数据的簇标签
db=DBSCAN(eps=0.01,min_samples=20).fit(X)
labels = db.labels_#返回的数据的簇标签,噪声数据标签为-1
print('Labels:\n',labels)

#计算标签为-1的数据(即噪声数据)的比例
raito=len(labels[labels[:] == -1]) / len(labels)
print('Noise raito:',format(raito, '.2%'))

#计算簇的个数
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
print('Estimated number of clusters: %d' % n_clusters_)

#评价聚类效果:轮廓系数si,原理可参考:http://blog.csdn.net/xueyingxue001/article/details/51966932
'''
            si接近1,则说明样本i聚类合理;
            si接近-1,则说明样本i更应该分类到另外的簇;
            若si 近似为0,则说明样本i在两个簇的边界上。
'''
print("Silhouette Coefficient: %0.3f"% metrics.silhouette_score(X, labels))#聚类效果评价指标

#打印各簇标号以及各簇内数据
for i in range(n_clusters_):
    print('number of data in Cluster %s is : %s'%(i,len(X[labels==i])))
    #print(list(X[labels == i].flatten()))

#绘制直方图分析
plt.hist(X,24)

输出:

Labels:
 [ 0 -1  0  1 -1  1  0  1  2 -1  1  0  1  1  3 -1 -1  3 -1  1  1 -1  1  3  4
 -1  1  1  2  0  2  2 -1  0  1  0  0  0  1  3 -1  0  1  1  0  0  2 -1  1  3
  1 -1  3 -1  3  0  1  1  2  3  3 -1 -1 -1  0  1  2  1 -1  3  1  1  2  3  0
  1 -1  2  0  0  3  2  0  1 -1  1  3 -1  4  2 -1 -1  0 -1  3 -1  0  2  1 -1
 -1  2  1  1  2  0  2  1  1  3  3  0  1  2  0  1  0 -1  1  1  3 -1  2  1  3
  1  1  1  2 -1  5 -1  1  3 -1  0  1  0  0  1 -1 -1 -1  2  2  0  1  1  3  0
  0  0  1  4  4 -1 -1 -1 -1  4 -1  4  4 -1  4 -1  1  2  2  3  0  1  0 -1  1
  0  0  1 -1 -1  0  2  1  0  2 -1  1  1 -1 -1  0  1  1 -1  3  1  1 -1  1  1
  0  0 -1  0 -1  0  0  2 -1  1 -1  1  0 -1  2  1  3  1  1 -1  1  0  0 -1  0
  0  3  2  0  0  5 -1  3  2 -1  5  4  4  4 -1  5  5 -1  4  0  4  4  4  5  4
  4  5  5  0  5  4 -1  4  5  5  5  1  5  5  0  5  4  4 -1  4  4  5  4  0  5
  4 -1  0  5  5  5 -1  4  5  5  5  5  4  4]
Noise raito: 22.15%
Estimated number of clusters: 6
Silhouette Coefficient: 0.710
number of data in Cluster 0 is : 55
number of data in Cluster 1 is : 65
number of data in Cluster 2 is : 28
number of data in Cluster 3 is : 25
number of data in Cluster 4 is : 28
number of data in Cluster 5 is : 24
image.png

可观察到:上网时间大多聚集在22:00和23:00

->对上网时长进行聚类(这一部分因为没有数据进行实验,请同时参考最上面的博文地址)

数据分布 vs 聚类

这里就是机器学习的一个小技巧了,左边的数据分布不适用于聚类分析的,如果我们想对这类数据进行聚类分析,需要对这些数据进行一些数学变换,通常我们采用取对数的变换方法,将这种数据变换之后,变换后的数据就比较适合用于聚类分析了;


image.png

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

image.png

输出标签,查看结果

image.png

3、无监督学习-降维

(1)PCA方法及其应用

->介绍

->基本前提概念

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

矩阵的特征向量是描述数据集结构的非零向量,并满足如下公式:,A是方阵, v->是特征向量,lamda是特征值。

->算法原理

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

上一篇 下一篇

猜你喜欢

热点阅读