K-means聚类算法原理及python实现+数据集

学习感言

前段时间学习了吴恩达机器学习的聚类算法,带着复习一下基础的实现。其中还有可以优化的地方。比如计算距离度量时,除了使用欧式距离,还可以使用曼哈顿距离、余弦相似度函数。在此先欠个账后续再把这些学习一下。

文章目录

  • 聚类算法简介
  • K-means聚类算法详解
  • python实现+代码解释
  • 完整可运行代码

数据集链接: 点击获取数据集

一、聚类算法简介

聚类算法是一种无监督学习方法,用于将数据集中的样本划分为若干个不相交的子集,即“簇”。每个簇可能对应与一些潜在的概念或类别,但这些概念或类别在聚类之前都是未知的。聚类算法的目的是将相似的对象聚集在一起,而不相似的对象则分散在不同的簇中。

二、K-means聚类算法详解

k-means聚类算法是一种常用的无监督学习算法,用于将一组数据点划分为k个不同类别。它的目标是将数据点划分到k个簇群中,使得同一簇内的点相互之间的距离最小化(本文采用欧式距离),而不同簇之间的距离最大化。

算法步骤如下:

  1. 随机选择k个初始聚类质心
  2. 将每个数据点分配到与其最近的聚类中心点所属的簇中。
  3. 对于每个簇,重新计算其簇群的质心(把簇群中的所有点取平均值)
  4. 重复步骤2和步骤3,直到聚类中心(质心)的变化量为0时停止,或者达到预期迭代的次数

距离度量:(在数据点分配过程中计算数据点与质心之间的距离策略)

将对象点分到距离聚类中心最近的那个簇中需要最近邻的度量策略,在欧式空间中采用的是欧式距离,在处理文档中采用的是余弦相似度函数,有时候也采用曼哈顿距离作为度量,不同的情况实用的度量公式是不同的。

二维平面欧式距离计算公式:

在这里插入图片描述
多维欧式空间计算公式:

在这里插入图片描述

三、python实现+代码详解

1.初始化主函数以及可视化聚类图 其中数据集以及簇群等都是以坐标形式保存 代码案例 k=4

if __name__ == '__main__':
	dataSet = createDataSet()  # 获取数据集
	centroids,cluster = kmeans(dataSet,4) # 参数4代表簇心,获取簇群以及质心
	print('质心为: %s'% centroids)
	print('集群为: %s'% cluster)
	
	for i in range(len(dataSet)):
		plt.scatter(dataSet[i][0],dataSet[i][1],marker = 'x',color = 'blue',s = 50,label='原始点')
	for i in range(len(centroids)):
		plt.scatter(centroids[j][0],centroids[j][1],marker = 'o',color ='red',s=50,label='质心')
	plt.show()

2. 创建数据集 将数据集中的数据以坐标形式保存

def createDataSet():
	t = pd.read_csv('data.csv')
	df = pd.DataFrame(t)
	df = df.values   # 获取df的值 以矩阵形式表示
	arry = []  # 用于保存坐标
	for i in range(0,79):
		arr = []
		arr.append(df[i,0])
		arr.append(df[i,1])
		arry.append(arr)
	return arry

3.使用k-means分类

def kmeans(dataSet,k):
	# 随机取k个样本作为质心
	 centroids = random.sample(dataSet,k)

	# 更新质心 直到变化量为0
	changed,newCentroids = classify(dataSet,centroids,k)
	while np.any(changed != 0):
		changed,newCentroids = classify(dataSet,centroids,k)
	centroids = sorted(newCentroids.tolist())

	# 根据质心计算每个集群
	cluster = []
	clalist = calcDis(dataSet,centroids,k) # 调用欧式距离 获得离最后质心距离最近的集群
	minDisIndics = np.argmin(clalist,axis=1)
	
	for i in range(k):
		cluster.append([])
	for i,j in enumerate(minDisIndics):
		cluster[j].append(dataSet[i]) # 将数据集各个坐标添加到对应集群中
		
	return centroids,cluster

4.计算质心

def classify(dataSet,centroids,k):
	# 计算样本到质心的距离 (欧式距离)根据上述公式
	clalist = calcDis(dataSet,centroids,k)
	# 分组计算新的质心
	minDisIndics = np.argmin(clalist,axis=1) # 求出每行最小值的下标
	# DataFrame(dataSet)表按照groupby(min)进行坐标分组 然后计算分类后坐标群的平均值
	newCentroids = pd.DataFrame(dataSet).groupby(minDisIndics).mean()
	newCentroids = newCentroids.values
	# 计算坐标变化量
	changed = newCentroids - centroids
	return changed,newCentroids

5.计算欧拉距离 根据文章第一部分公式代入坐标

def calcDis(dataSet, centroids, k):
	clalist = []
	for data in dataSet:
		diff = np.tile(data, (k,1)) - centroids  # 将坐标复制k份 分别计算到各个质心的距离
		squaredDiff = diff**2
		squareDist = np.sum(squaredDiff,axis=1)
		distance = squareDist**0.5   # 开方
		clalist.append(distance)
	clalist = np.array(clalist)
	return clalist

6.运行结果展示

在这里插入图片描述

四、完整可运行代码

import random
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


# 计算欧拉距离
def calcDis(dataSet, centroids,k):
    clalist = []
    for data in dataSet:
        diff = np.tile(data,(k,1))-centroids
        squaredDiff = diff**2
        squaredDist = np.sum(squaredDiff,axis=1)
        distance = squaredDist**0.5
        clalist.append(distance)
    clalist = np.array(clalist)
    return clalist


# 计算质心
def classify(dataSet,centroids,k):
    # 计算样本到质心的距离
    clalist = calcDis(dataSet,centroids,k)
    # 分组计算新的质心
    minDisIndics = np.argmin(clalist,axis=1) # 求出每行最小值的下标
    # DataFramte(dataSet)对DataSet分组,groupby(min)按照min进行统计分类,mean()对分类结果求均值
    newCentroids = pd.DataFrame(dataSet).groupby(minDisIndics).mean()
    newCentroids =newCentroids.values
    # 计算变化量
    changed = newCentroids - centroids

    return changed,newCentroids


#使用k-means分类
def kmeans(dataSet,k):
    # 随机取质心
    centroids = random.sample(dataSet,k)

    #更新质心 直到变化量为0
    changed, newCentroids = classify(dataSet,centroids,k)
    while np.any(changed != 0):
        changed,newCentroids = classify(dataSet,newCentroids,k)

    centroids = sorted(newCentroids.tolist())

    #根据质心计算每个集群
    cluster = []
    clalist = calcDis(dataSet,centroids,k)  #调用欧拉距离
    minDisIndics = np.argmin(clalist,axis=1)

    for i in range(k):
        cluster.append([])
    for i, j in enumerate(minDisIndics):
        cluster[j].append(dataSet[i])

    return centroids,cluster


# 创建数据集
def createDataSet():
    t = pd.read_csv('data.csv')
    df = pd.DataFrame(t)
    df = df.values
    arry = []
    for i in range(0,79):
        arr = []
        arr.append(df[i,0])
        arr.append(df[i,1])
        arry.append(arr)
    return arry

if __name__ == '__main__':
    dataSet = createDataSet()
    centroids,cluster = kmeans(dataSet,4)
    print('质心为: %s'% centroids)
    print('集群为: %s'% cluster)

    for i in range(len(dataSet)):
        plt.scatter(dataSet[i][0],dataSet[i][1],marker = 'x',color = 'blue',s=50,label='原始点')
    for j in range(len(centroids)):
        plt.scatter(centroids[j][0], centroids[j][1], marker='o', color='red', s=50, label='质心')

    plt.show()
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值