当前位置: 首页 > news >正文

机器学习实验报告5-K-means 算法

4.1 k-means算法简介

聚类分析,作为机器学习领域中的一种无监督学习方法,在数据探索与知识发现过程中扮演着举足轻重的角色。它能够在没有先验知识或标签信息的情况下,通过挖掘数据中的内在结构和规律,将数据对象自动划分为多个类别或簇。每个簇内的对象具有高度的相似性,而不同簇间的对象则表现出明显的差异性。

在众多聚类算法中,K-means算法因其简单高效而备受青睐。K-means算法的基本思想是:通过迭代的方式,将数据划分为K个不同的簇,并使得每个数据点与其所属簇的质心(或称为中心点、均值点)之间的距离之和最小。

K-means算法的优点在于其直观易懂、计算速度快且易于实现。然而,它也存在一些局限性,如对初始簇质心的选择敏感、可能陷入局部最优解以及需要预先设定聚类数K等。因此,在实际应用中,我们需要根据具体的问题和数据特点来选择合适的聚类算法,并可能需要对算法进行优化或改进以适应特定的需求。

4.2 算法的基本原理

(1)类和分类

类指的是具有相似性的集合。而分类是根据给定的已知类别的样本,训练出来一个模型,使该模型能够对未知类别的样本进行分类。故分类属于有监督学习。有监督学习是指提前由人工对训练数据做好了分类,训练样本同时包含有特征和类别信息。有监督学习类似于先学习带有标准答案的复习题,学习到知识规律以后,再去参加考试。

(2)聚类

对于一些给定的样本,不知道样本之间的关系,不知道他们是否属于同一类,也不知道到底可以分为多少类。此时,通过聚类把未知类别的数据,分为多个类别。聚类目的在于把相似的东西聚在一起,因此聚类属于无监督学习。

(3)K-均值聚类思想

K-均值(K-Means)是发现给定数据集的K个簇的算法。簇个数K是用户给定的,每一个簇通过其质心(即簇中所有点的中心)来描述。其核心思想是将数据集中的n个对象划分为K个聚类,使得每个对象到其所属聚类的中心(或称为均值点、质心)的距离之和最小。这里所说的距离通常指的是欧氏距离,但也可以是其他类型的距离度量。通过迭代的方式不断优化聚类结果,使得每个聚类内的对象尽可能紧密,而不同聚类间的对象则尽可能分开。

(4)算法步骤

K-means算法作为一种强大的无监督学习工具,具有简单易懂、计算效率高和易于实现等优点在多个领域有着广泛的应用下面我们将详细探讨K-means算法的实现步骤。K-means算法的执行过程通常包括以下个步骤

a.初始化选择K个初始聚类中心在算法开始时,需要随机选择K个数据点作为初始的聚类中心。这些初始聚类中心的选择对最终的聚类结果有一定的影响,因此在实际应用中,通常会采用一些启发式的方法来选择较好的初始聚类中心,如K-means++算法。

b.分配将每个数据点分配给最近的聚类中心对于数据集中的每个数据点,计算其与每个聚类中心的距离,并将其分配给距离最近的聚类中心。这一步通常使用欧氏距离作为距离度量,计算公式如下(1)。其中,x是数据点,ci是第i个聚类中心,d是数据的维度,xj和cij分别是x和ci在第j维上的值。

c.更新重新计算每个聚类的中心对于每个聚类,重新计算其聚类中心新的聚类中心是该聚类内所有数据点的均值,计算公式如下(2)。其中,Si是第i个聚类的数据点集合,|Si|是该集合中数据点的数量。

d.迭代,重复分配和更新步骤,直到满足终止条件。重复执行分配和更新步骤,直到满足某种终止条件。常见的终止条件包括,聚类中心不再发生显著变化:即新的聚类中心与旧的聚类中心之间的距离小于某个预设的阈值。达到最大迭代次数:为了避免算法陷入无限循环,通常会设置一个最大迭代次数作为终止条件。在迭代过程中,算法会不断优化聚类结果,使得每个聚类内的对象更加紧密,而不同聚类间的对象更加分散。最终,当满足终止条件时,算法停止迭代并输出最终的聚类结果。

4.3 算法实例

K-means算法作为一种强大的无监督学习工具,在多个领域有着广泛的应用。本实验以对俄勒冈州的波特兰地区地图上的点进行聚类为例,基于k-means算法实现将这些地方进行聚类的最佳策略,这样就可以安排交通工具抵达这些簇的质心,然后步行到每个内地址。实例操作可分为以下五个过程。

  1. 收集数据

通过调用geoGrab函数来实现收集数据,geoGrab函数的作用是收集数据,通过调用雅虎地理编码 API(Yahoo Geocoding API),将输入的街道地址和城市名称转换为对应的地理坐标(经纬度等位置信息),返回 API 响应的 JSON 格式数据,包含地址对应的地理编码信息(如坐标、地址匹配度等)。

相关代码如下:

def geoGrab(stAddress, city):

    apiStem = 'http://where.yahooapis.com/geocode?'  #create a dict and constants for the goecoder

    params = {}

    params['flags'] = 'J'#JSON return type

    params['appid'] = 'aaa0VN6k'

    params['location'] = '%s %s' % (stAddress, city)

    url_params = urllib.parse.urlencode(params)

    yahooApi = apiStem + url_params      #print url_params

    print (yahooApi)

    c=urllib.parse.urlopen(yahooApi)

    return json.loads(c.read())

  1. 准备数据

准备数据中,只保留经纬度信息。我们可以通过调用massPlaceFind函数。该函数其作用是批量处理地址数据,通过调用geoGrab函数获取地理坐标(经纬度),并将结果写入文件。该函数适用于批量处理地址数据,生成带地理坐标的数据集,常用于地理信息系统(GIS)、数据分析或地图可视化等场景。

相关代码如下:

def massPlaceFind(fileName):

    fw = open('places.txt', 'w')

    for line in open(fileName).readlines():

        line = line.strip()

        lineArr = line.split('\t')

        retDict = geoGrab(lineArr[1], lineArr[2])

        if retDict['ResultSet']['Error'] == 0:

            lat = float(retDict['ResultSet']['Results'][0]['latitude'])

            lng = float(retDict['ResultSet']['Results'][0]['longitude'])

            print("%s\t%f\t%f" % (lineArr[0], lat, lng))

            fw.write('%s\t%f\t%f\n' % (line, lat, lng))

        else: print ("error fetching")

        sleep(1)

    fw.close()

  1. 分析数据

使用Matplotlib来构建一个二维数据图,其中包含簇与地图。我们通过调用clusterClubs函数来实现。clusterClubs函数,其核心功能是对地点的经纬度数据进行聚类分析,并在地图背景上可视化聚类结果。该函数适用于地理数据的聚类分析与可视化,常用于城市规划、商业选址、轨迹分析等场景,帮助快速识别数据中的空间分布模式。

图1 调用函数

图2 二维数据图

相关代码如下:

def clusterClubs(numClust=5):

    datList = []

    for line in open('places.txt').readlines():

        lineArr = line.split('\t')

        datList.append([float(lineArr[4]), float(lineArr[3])])

    datMat = matrix(datList)

    myCentroids, clustAssing = biKmeans(datMat, numClust, distMeas=distSLC)

    fig = plt.figure()

    rect=[0.1,0.1,0.8,0.8]

    scatterMarkers=['s', 'o', '^', '8', 'p', \'d', 'v', 'h', '>', '<']

    axprops = dict(xticks=[], yticks=[])

    ax0=fig.add_axes(rect, label='ax0', **axprops)

    imgP = plt.imread('Portland.png')

    ax0.imshow(imgP)

    ax1=fig.add_axes(rect, label='ax1', frameon=False)

    for i in range(numClust):

        ptsInCurrCluster = datMat[nonzero(clustAssing[:,0].A==i)[0],:]

        markerStyle = scatterMarkers[i % len(scatterMarkers)]

        ax1.scatter(ptsInCurrCluster[:,0].flatten().A[0], ptsInCurrCluster[:,1].flatten().A[0], marker=markerStyle, s=90)

    ax1.scatter(myCentroids[:,0].flatten().A[0], myCentroids[:,1].flatten().A[0], marker='+', s=300)

    plt.show()

  1. 测试算法

通过调用biKmeans()函数来测试算法。该函数实现了二分K均值算法(Bisecting K-Means),用于对数据集进行聚类分析。其核心作用是通过 “逐步分裂簇” 的策略,将数据集划分为指定数量的簇(k个)

图3 测试算法

相关代码如下:

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

    m = shape(dataSet)[0]

    clusterAssment = matrix(zeros((m,2)))

    centroid0 = mean(dataSet, axis=0).tolist()[0]

    centList =[centroid0] #create a list with one centroid

    for j in range(m):#calc initial Error

        clusterAssment[j,1] = distMeas(matrix(centroid0), dataSet[j,:])**2

    while (len(centList) < k):

        lowestSSE = inf

        for i in range(len(centList)):

            ptsInCurrCluster = dataSet[nonzero(clusterAssment[:,0].A==i)[0],:]#get the data points currently in cluster i

            centroidMat, splitClustAss = kMeans(ptsInCurrCluster, 2, distMeas)

            sseSplit = sum(splitClustAss[:,1])#compare the SSE to the currrent minimum

            sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])

            print("sseSplit, and notSplit: ",sseSplit,sseNotSplit)

            if (sseSplit + sseNotSplit) < lowestSSE:

                bestCentToSplit = i

                bestNewCents = centroidMat

                bestClustAss = splitClustAss.copy()

                lowestSSE = sseSplit + sseNotSplit

        bestClustAss[nonzero(bestClustAss[:,0].A == 1)[0],0] = len(centList) #change 1 to 3,4, or whatever

        bestClustAss[nonzero(bestClustAss[:,0].A == 0)[0],0] = bestCentToSplit

        print ('the bestCentToSplit is: ',bestCentToSplit)

        print ('the len of bestClustAss is: ', len(bestClustAss))

        centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0]#replace a centroid with two best centroids

        centList.append(bestNewCents[1,:].tolist()[0])

        clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:]= bestClustAss#reassign new clusters, and SSE

    return matrix(centList), clusterAssment

  1. 使用算法

我们通过使用clusterClubs函数来输出包含簇及簇中心的地图。clusterClubs函数,其核心功能是对地点的经纬度数据进行聚类分析,并在地图背景上可视化聚类结果。操作过程与(3)分析数据相同。

图4 簇及簇中心图

相关代码如下:

def clusterClubs(numClust=5):

    datList = []

    for line in open('places.txt').readlines():

        lineArr = line.split('\t')

        datList.append([float(lineArr[4]), float(lineArr[3])])

    datMat = matrix(datList)

    myCentroids, clustAssing = biKmeans(datMat, numClust, distMeas=distSLC)

    fig = plt.figure()

    rect=[0.1,0.1,0.8,0.8]

    scatterMarkers=['s', 'o', '^', '8', 'p', \

                    'd', 'v', 'h', '>', '<']

    axprops = dict(xticks=[], yticks=[])

    ax0=fig.add_axes(rect, label='ax0', **axprops)

    imgP = plt.imread('Portland.png')

    ax0.imshow(imgP)

    ax1=fig.add_axes(rect, label='ax1', frameon=False)

    for i in range(numClust):

        ptsInCurrCluster = datMat[nonzero(clustAssing[:,0].A==i)[0],:]

        markerStyle = scatterMarkers[i % len(scatterMarkers)]

        ax1.scatter(ptsInCurrCluster[:,0].flatten().A[0], ptsInCurrCluster[:,1].flatten().A[0], marker=markerStyle, s=90)

    ax1.scatter(myCentroids[:,0].flatten().A[0], myCentroids[:,1].flatten().A[0], marker='+', s=300)

    plt.show()

相关文章:

  • Linux--存储系统探秘:从块设备到inode
  • 影视剧学经典系列-梁祝-陶渊明《感士不遇赋并序》
  • Appium+python自动化(二十三)- Monkeyrunner与Monkey
  • React forwardRef 与 useImperativeHandle 深度解析
  • selenium点击元素出现的obscure问题
  • 设计模式精讲 Day 2:工厂方法模式(Factory Method Pattern)
  • 什么是敏捷中的迭代(Iteration)和 Sprint?
  • 计算机硬件——主板
  • 【旧题新解】第 9 集 带余除法
  • Java 常用类 Arrays:从零到实战的数组操作指南
  • ArkUI-X框架LogInterface使用指南
  • 安卓9.0系统修改定制化____深入解析安卓 9.0 各手机分区:功能、作用与差异 基础篇二
  • Java的DI依赖注入
  • 易采集EasySpider v0.6.3 便携版
  • HTML5+JS实现一个简单的SVG 贝塞尔曲线可视化设计器,通过几个点移动位置,控制曲线的方向
  • Arcgis中,toolbox工具箱中工具莫名报错的解决方法
  • 大模型RAG系统面试题及参考答案
  • 职场灵活性与家庭状态对职业倦怠影响的可视化分析:从数据到洞见的深度解读
  • 2.7 获取激光雷达数据与避障
  • 【Linux】Linux 信号驱动I/O
  • 现在允许做网站吗/有产品怎么找销售渠道
  • 培训web网站开发/如何建立电商平台
  • 企业做网站价钱/长尾关键词网站
  • 怎么做电影流量网站/sem是什么设备
  • frontpage网站模板下载/seo技术是什么
  • 政府网站建设由哪个部门负责/高端网站建设专业公司