Jupyter Notebook使用Python做K-Means聚类分析

2021-8-31 17:20| 发布者: Fuller| 查看: 4626| 评论: 0

摘要: 《新冠肺炎疫情期间公众心理健康信息需求研究—以社会化问答平台“知乎”为例》使用了K-means聚类算法,本文将在Jupyter Notebook中用python中做K-Means聚类分析计算 ...

1,本Notebook背景介绍

此前介绍了一篇论文范例《新冠肺炎疫情期间公众心理健康信息需求研究—以社会化问答平台“知乎”为例》,该研究作者以社会化问答平台“知乎”为例,通过K-means聚类算法和LDA主题模型挖掘“知乎”平台下心理健康话题中的公众心理健康信息需求提问数据,并对这些数据进行分析和研究,探究新冠肺炎疫情期间公众心理健康信息需求特点及分布情况,为有关政府部门和相关运营商更好地了解这方面现状,提升服务水平提供参考和帮助。

该研究使用了K-means聚类算法,我们今天就在Jupyter Notebook中使用python中做K-Means聚类分析计算。

1.1,什么是K-means聚类算法?

参看 一步步教你轻松学K-means聚类算法,摘录如下:

k-平均算法(英文:k-means clustering)源于信号处理中的一种向量量化方法,现在则更多地作为一种聚类分析方法流行于数据挖掘领域。k-平均聚类的目的是:把 n个点划分到k个聚类中,使得每个点都属于离他最近的均值(此即聚类中心)对应的聚类,以之作为聚类的标准。

K-Means 是发现给定数据集的 K 个簇的聚类算法, 之所以称之为 K-均值 是因为它可以发现 K 个不同的簇, 且每个簇的中心采用簇中所含值的均值计算而成.簇个数 K 是用户指定的, 每一个簇通过其质心(centroid), 即簇中所有点的中心来描述。

聚类与分类算法的最大区别在于, 分类的目标类别已知, 而聚类的目标类别是未知的。

注意:k-平均聚类与k-近邻是两种不同的算法,我们将在另外一个Jupyter Notebook中实验KNN算法。

1.2,K-means聚类算法应用场景

参看 一步步教你轻松学K-means聚类算法,摘录如下:

k-means,用于数据集内种类属性不明晰,希望能够通过数据挖掘出或自动归类出有相似特点的对象的场景。其商业界的应用场景一般为挖掘出具有相似特点的潜在客户群体以便公司能够重点研究、对症下药。

例如,在2000年和2004年的美国总统大选中,候选人的得票数比较接近或者说非常接近。任一候选人得到的普选票数的最大百分比为50.7%而最小百分比为47.9% 如果1%的选民将手中的选票投向另外的候选人,那么选举结果就会截然不同。 实际上,如果妥善加以引导与吸引,少部分选民就会转换立场。尽管这类选举者占的比例较低,但当候选人的选票接近时,这些人的立场无疑会对选举结果产生非常大的影响。如何找出这类选民,以及如何在有限的预算下采取措施来吸引他们? 答案就是聚类(Clustering)。

那么,具体如何实施呢?首先,收集用户的信息,可以同时收集用户满意或不满意的信息,这是因为任何对用户重要的内容都可能影响用户的投票结果。然后,将这些信息输入到某个聚类算法中。接着,对聚类结果中的每一个簇(最好选择最大簇 ), 精心构造能够吸引该簇选民的消息。最后, 开展竞选活动并观察上述做法是否有效。

1.3,K-means聚类算法步骤

k-means聚类算法步骤实质是EM算法的模型优化过程,具体步骤如下:

1)随机选择k个样本作为初始簇类的均值向量;

2)将每个样本数据集划分离它距离最近的簇;

3)根据每个样本所属的簇,更新簇类的均值向量;

4)重复(2)(3)步,当达到设置的迭代次数或簇类的均值向量不再改变时,模型构建完成,输出聚类算法结果。

1.4,K-means不适合的数据集

了解哪些数据集不适合K-means是有必要的,防止揪过来这个算法就往上硬套,参看k-means聚类算法原理总结

1. 若样本数据是各向异性的,那么k-means算法的效果较差

2. 当样本数据集是非凸数据集时,k-means聚类效果较差

3. 当训练数据集各个簇类的标准差不相等时,k-means聚类效果不好

4. 若各簇类的样本数相差比较大,聚类性能较差

5. 若数据维度很大时,运行时间很长,可以考虑先用pca降维

该文好几个场景使用了散点图对数据进行观察,在执行聚类算法前这是必要的,还可以用一些描述性统计方法,对数据特点进行观察,也可以使用pca,通过变换,获得好的观察角度,看到有代表性的特征,才进行计算。

2,测试数据

本算法所用的数据集为 uci 上的聚类算法数据集 3D Road Network

为缩短每次实验运行的时间,取原始数据集的前1万行作为测试数据,数据文件为:data/raw/network2.txt

文件中的数据格式为如下(部分数据,用于示例):

144552912,9.3498486,56.7408757,17.0527715677876

144552912,9.3501884,56.7406785,17.614840244389

144552912,9.3505485,56.7405445,18.08353563951

144552912,9.3508058,56.7404845,18.2794652530352

144552912,9.3510534,56.7404863,18.4229736146099

144552912,9.3514747,56.7405022,19.1248885940143

144552912,9.3521273,56.7405585,19.5905926656897

144552912,9.3524201,56.7405974,19.6217636955693

144552912,9.3525839,56.740629,19.6599309194984

144552912,9.3527255,56.7406626,19.4906695590218

3,本notebook所做聚类计算

基于测试数据,在Jupyter Notebook中使用Python做K-Means聚类分析计算。

代码参考文献:K-means算法的python实现及可视化

4,第三方库

运行本Notebook,需安装numpy和matplotlib。如果没有安装,则需要打开一个Python的COMMAND窗口,运行如下的安装命令:

$ pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple/

$ pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple/

5,引入numpy库

NumPy是Python中科学计算的基础包。它是一个Python库,提供多维数组对象,各种派生对象(如掩码数组和矩阵),以及用于数组快速操作的各种例程,包括数学,逻辑,形状操作,排序,选择,I / O离散傅立叶变换,基本线性代数,基本统计运算,随机模拟等等。

NumPy包的核心是ndarray对象。这封装了同构数据类型的n维数组,许多操作在编译代码中执行以提高性能。

# coding:utf-8    

import numpy

from numpy import *


6,引入matplotlib库

matplotlib是一款命令式、较底层、可定制性强、图表资源丰富、简单易用、出版质量级别的python 2D绘图库。

matplotlib算是python绘图的元老级库,类似编程语言里的C语言。很多其它的python绘图库是基于matplotlib开发的,比如seaborn、ggplot、plotnine、holoviews、basemap等。

matplotlib可用于python脚本、python shell、jupyter notebook、web等。

最适合来运行matplotlib绘图的工具是jupyter notebook,本Notebook也是基于该工具做可视化实验:交互式操作,在浏览器上运行代码,能直接显示运行结果和图表,

import matplotlib.pyplot as plt


7,引入OS库

用于定位和读取data/raw/network2.txt测试数据集文件

import os


8,定义读取测试数据集文件的函数loadDataSet

后面会调用这个函数

def loadDataSet(fileName):    

    dataSet = []    

    f = open(os.path.join(os.getcwd(), '..\\..\\data\\raw\\',fileName))    

    for line in f.readlines():        

        curLine = line.strip().split(',')   # 这里","表示以文件中数据之间的分隔符","分割字符串        

        row = []        

        for item in curLine:            

            row.append(float(item))        

        dataSet.append(row)     

    return numpy.mat(dataSet) 


9,定义求向量距离的函数distEclud

后面会调用这个函数

# 求向量距离

def distEclud(vecA, vecB):    

    return sqrt(sum(power(vecA - vecB, 2)))


10,定义选前k个点作为初始质心的函数initCent

K-Means聚类算法,需要在运行开始时选取k个点作为初始的质心

# 选前k个点作为初始质心

def initCent(dataSet, k):    

    data = []    

    for i in range(k):        

        data.append(dataSet[i].tolist())    

    a = array(data)    

    centroids = numpy.mat(a)    

    return centroids 


11,定义K均值聚类算法实现的函数KMeans

# K均值聚类算法实现

def KMeans(dataSet, k, distMeas=distEclud):    

    m = numpy.shape(dataSet)[0] #数据集的行    

    clusterAssment = numpy.mat(numpy.zeros((m, 2)))    

    centroids = initCent(dataSet, k)    

    clusterChanged = True    

    while clusterChanged:        

        clusterChanged = False        

        for i in range(m): #遍历数据集中的每一行数据            

            minDist = inf            

            minIndex = -1            

            for j in range(k): #寻找最近质心                

                distJI = distMeas(centroids[j, :], dataSet[i, :])                

                if distJI < minDist: #更新最小距离和质心下标                    

                    minDist = distJI                    

                    minIndex = j            

            if clusterAssment[i, 0] != minIndex:                

                clusterChanged = True            

            clusterAssment[i, :] = minIndex, minDist**2 #记录最小距离质心下标,最小距离的平方        

        for cent in range(k): #更新质心位置            

            ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]] #获得距离同一个质心最近的所有点的下标,即同一簇的坐标            

            centroids[cent,:] = mean(ptsInClust, axis=0) #求同一簇的坐标平均值,axis=0表示按列求均值     

    return centroids, clusterAssment


12,定义取坐标的函数getXY

取数据的前两维特征作为该条数据的x , y 坐标

def getXY(dataSet):    

    import numpy as np    

    m = numpy.shape(dataSet)[0]  # 数据集的行    

    X = []    

    Y = []    

    for i in range(m):        

        X.append(dataSet[i,0])        

        Y.append(dataSet[i,1])    

    return np.array(X), np.array(Y)


13,定义数据可视化函数showCluster

该函数调用matplotlib.pyplot来画图

# 数据可视化

def showCluster(dataSet, k, clusterAssment, centroids):    

    fig = plt.figure(figsize=(15,5))   

    plt.title("K-means")    

    ax = fig.add_subplot(111)    

    data = []     

    for cent in range(k): #提取出每个簇的数据        

        ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]] #获得属于cent簇的数据        

        data.append(ptsInClust)     

    for cent, c, marker in zip( range(k), ['r', 'g', 'b', 'y'], ['^', 'o', '*', 's'] ): #画出数据点散点图        

        X, Y = getXY(data[cent])        

        ax.scatter(X, Y, s=80, c=c, marker=marker)     

    centroidsX, centroidsY = getXY(centroids)    

    ax.scatter(centroidsX, centroidsY, s=1000, c='black', marker='+', alpha=1)  # 画出质心点    

    ax.set_xlabel('X Label')    

    ax.set_ylabel('Y Label')

    plt.show() 


14,K-Means聚类分析实验一

指定k=2, 也就是聚类分析的结果得到2个类

cluster_Num = 2    

data = loadDataSet("network2.txt")    

centroids, clusterAssment = KMeans(data, cluster_Num)    

showCluster(data, cluster_Num, clusterAssment, centroids)


15,K-Means聚类分析实验二

指定k=3, 也就是聚类分析的结果得到3个类

cluster_Num = 3      

data = loadDataSet("network2.txt")    

centroids, clusterAssment = KMeans(data, cluster_Num)    

showCluster(data, cluster_Num, clusterAssment, centroids)

16,怎样选择K的大小?

上面我们分别实验了K=2和K=3的情况,那么怎样选择K的大小呢? 一般使用“手肘法”。

K-means怎么选K?一文中有描述:

手肘法本质上也是一种间接的观察法。这里需要一点K-Means的背景知识。当K-Means算法完成后,我们将得到K个聚类的中心点Mi, i=1,2,⋯,K。以及每个原始点所对应的聚类Ci,i=1,2,⋯,K。我们通常采用所有样本点到它所在的聚类的中心点的距离的和作为模型的度量,记为DK。

很显然K越大,距离和越小。但是我们注意到K=3是一个拐点,就像是我们的肘部一样,K=1到3下降很快,K=3之后趋于平稳。手肘法认为这个拐点就是最佳的K。

手肘法是一个经验方法,而且肉眼观察也因人而异,特别是遇到模棱两可的时候。相比于直接观察法,手肘法的一个优点是,适用于高维的样本数据。有时候人们也会把手肘法用于不同的度量上,如组内方差组间方差比。

具体的算法这里不在测试了, 有兴趣的同学可以自行进行实验, 有很多文章可以参考,比如这篇:Python:K-Means聚类分析

17,下载本Jupyter Notebook

下载源代码请进:使用Python做K-Means文本聚类分析


鲜花

握手

雷人

路过

鸡蛋

最新评论

GMT+8, 2024-11-18 16:36