Python实现聚类K-means算法详解


Posted in Python onJuly 15, 2022

K-means(K均值)算法是最简单的一种聚类算法,它期望最小化平方误差

Python实现聚类K-means算法详解

:为避免运行时间过长,通常设置一个最大运行轮数或最小调整幅度阈值,若到达最大轮数或调整幅度小于阈值,则停止运行。

下面我们用python来实现一下K-means算法:我们先尝试手动实现这个算法,再用sklearn库中的KMeans类来实现。数据我们采用《机器学习》的西瓜数据(P202表9.1):

# 下面的内容保存在 melons.txt 中
# 第一列为西瓜的密度;第二列为西瓜的含糖率。我们要把这30个西瓜分为3类
0.697 0.460
0.774 0.376
0.634 0.264
0.608 0.318
0.556 0.215
0.403 0.237
0.481 0.149
0.437 0.211
0.666 0.091
0.243 0.267
0.245 0.057
0.343 0.099
0.639 0.161
0.657 0.198
0.360 0.370
0.593 0.042
0.719 0.103
0.359 0.188
0.339 0.241
0.282 0.257
0.748 0.232
0.714 0.346
0.483 0.312
0.478 0.437
0.525 0.369
0.751 0.489
0.532 0.472
0.473 0.376
0.725 0.445
0.446 0.459

手动实现

我们用到的库有matplotlibnumpy,如果没有需要先用pip安装一下。

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

下面定义一些数据:

k = 3 # 要分的簇数
rnd = 0 # 轮次,用于控制迭代次数(见上文)
ROUND_LIMIT = 100 # 轮次的上限
THRESHOLD = 1e-10 # 单轮改变距离的阈值,若改变幅度小于该阈值,算法终止
melons = [] # 西瓜的列表
clusters = [] # 簇的列表,clusters[i]表示第i簇包含的西瓜

从melons.txt读取数据,保存在列表中:

f = open('melons.txt', 'r')
for line in f:
	# 把字符串转化为numpy中的float64类型
    melons.append(np.array(line.split(' '), dtype = np.string_).astype(np.float64))

从 m m m个数据中随机挑选出 k k k个,对应上面算法的第 1 1 1行:

# random的sample函数从列表中随机挑选出k个样本(不重复)。我们在这里把这些样本作为均值向量
mean_vectors = random.sample(melons, k)

下面是算法的主要部分。

# 这个while对应上面算法的2-17行
while True:
    rnd += 1 # 轮次增加
    change = 0 # 把改变幅度重置为0

	# 清空对簇的划分,对应上面算法的第3行
    clusters = []
    for i in range(k):
        clusters.append([])
    # 这个for对应上面算法的4-8行
    for melon in melons:
    	'''
    	argmin 函数找出容器中最小的下标,在这里这个目标容器是
    	list(map(lambda vec: np.linalg.norm(melon - vec, ord = 2), mean_vectors)),
    	它表示melon与mean_vectors中所有向量的距离列表。
    	(numpy.linalg.norm计算向量的范数,ord = 2即欧几里得范数,或模长)
    	'''
        c = np.argmin(
            list(map( lambda vec: np.linalg.norm(melon - vec, ord = 2), mean_vectors))
        )
        clusters[c].append(melon)
	# 这个for对应上面算法的9-16行
    for i in range(k):
    	# 求每个簇的新均值向量
        new_vector = np.zeros((1,2))
        for melon in clusters[i]:
            new_vector += melon
        new_vector /= len(clusters[i])

        # 累加改变幅度并更新均值向量
        change += np.linalg.norm(mean_vectors[i] - new_vector, ord = 2)
        mean_vectors[i] = new_vector
	# 若超过设定的轮次或者变化幅度<预先设定的阈值,结束算法
    if rnd > ROUND_LIMIT or change < THRESHOLD:
        break
print('最终迭代%d轮'%rnd)

最后我们绘图来观察一下划分的结果:

colors = ['red', 'green', 'blue']

# 每个簇换一下颜色,同时迭代簇和颜色两个列表
for i, col in zip(range(k), colors):
    for melon in clusters[i]:
    	# 绘制散点图
        plt.scatter(melon[0], melon[1], color = col)
plt.show()

划分结果(由于最开始的 k k k个均值向量随机选取,每次划分的结果可能会不同):

Python实现聚类K-means算法详解

完整代码:

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

k = 3
rnd = 0
ROUND_LIMIT = 10
THRESHOLD = 1e-10
melons = []
clusters = []
f = open('melons.txt', 'r')
for line in f:
    melons.append(np.array(line.split(' '), dtype = np.string_).astype(np.float64))
mean_vectors = random.sample(melons, k)

while True:
    rnd += 1
    change = 0
    clusters = []
    for i in range(k):
        clusters.append([])
    for melon in melons:
        c = np.argmin(
            list(map( lambda vec: np.linalg.norm(melon - vec, ord = 2), mean_vectors))
        )
        clusters[c].append(melon)
    for i in range(k):
        new_vector = np.zeros((1,2))
        for melon in clusters[i]:
            new_vector += melon
        new_vector /= len(clusters[i])

        change += np.linalg.norm(mean_vectors[i] - new_vector, ord = 2)
        mean_vectors[i] = new_vector

    if rnd > ROUND_LIMIT or change < THRESHOLD:
        break
print('最终迭代%d轮'%rnd)
colors = ['red', 'green', 'blue']
for i, col in zip(range(k), colors):
    for melon in clusters[i]:
        plt.scatter(melon[0], melon[1], color = col)
plt.show()

sklearn库中的KMeans

这种经典算法显然不需要我们反复地造轮子,被广泛使用的python机器学习库sklearn已经提供了该算法的实现。sklearn的官方文档中给了我们一个示例:

>>> from sklearn.cluster import KMeans
>>> import numpy as np
>>> X = np.array([[1, 2], [1, 4], [1, 0],
...               [10, 2], [10, 4], [10, 0]])
>>> kmeans = KMeans(n_clusters=2, random_state=0).fit(X)
>>> kmeans.labels_
array([1, 1, 1, 0, 0, 0], dtype=int32)
>>> kmeans.predict([[0, 0], [12, 3]])
array([1, 0], dtype=int32)
>>> kmeans.cluster_centers_
array([[10.,  2.],
       [ 1.,  2.]])

可以看出,X即要聚类的数据(1,2),(1,4),(1,0)等。
KMeans类的初始化参数n_clusters即簇数 k k k;
random_state是用于初始化选取 k k k个向量的随机数种子;
kmeans.labels_即每个点所属的簇;
kmeans.predict方法预测新的数据属于哪个簇;
kmeans.cluster_centers_返回每个簇的中心。
我们就改造一下这个简单的示例,完成对上面西瓜的聚类。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

X = []
f = open('melons.txt', 'r')
for line in f:
    X.append(np.array(line.split(' '), dtype = np.string_).astype(np.float64))
kmeans = KMeans(n_clusters = 3, random_state = 0).fit(X)
colors = ['red', 'green', 'blue']
for i, cluster in enumerate(kmeans.labels_):
    plt.scatter(X[i][0], X[i][1], color = colors[cluster])
plt.show()

运行结果如下,可以看到和我们手写的聚类结果基本一致:

Python实现聚类K-means算法详解

到此这篇关于Python实现聚类K-means算法详解的文章就介绍到这了,更多相关Python K-means算法内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python实现批量将word转html并将html内容发布至网站的方法
Jul 14 Python
Using Django with GAE Python 后台抓取多个网站的页面全文
Feb 17 Python
详解python的数字类型变量与其方法
Nov 20 Python
python编程实现归并排序
Apr 14 Python
Python程序运行原理图文解析
Feb 10 Python
python3调用R的示例代码
Feb 23 Python
PyQt5每天必学之布局管理
Apr 19 Python
Python Numpy 实现交换两行和两列的方法
Jun 26 Python
Django 对象关系映射(ORM)源码详解
Aug 06 Python
pytorch使用 to 进行类型转换方式
Jan 08 Python
Python unittest单元测试框架实现参数化
Apr 29 Python
matplotlib交互式数据光标mpldatacursor的实现
Feb 03 Python
python自动获取微信公众号最新文章的实现代码
Jul 15 #Python
pytorch实现加载保存查看checkpoint文件
Jul 15 #Python
pytest实现多进程与多线程运行超好用的插件
Jul 15 #Python
python如何将mat文件转为png
Jul 15 #Python
python读取mat文件生成h5文件的实现
Jul 15 #Python
全网非常详细的pytest配置文件
Jul 15 #Python
Python如何加载模型并查看网络
Jul 15 #Python
You might like
Apache服务器无法使用的解决方法
2013/05/08 PHP
php curl获取https页面内容,不直接输出返回结果的设置方法
2019/01/15 PHP
OfflineSave离线保存代码再次发布使用说明
2007/05/23 Javascript
JavaScript随机排序(随即出牌)
2010/09/17 Javascript
js substr支持中文截取函数代码(中文是双字节)
2013/04/17 Javascript
在jquery中的ajax方法怎样通过JSONP进行远程调用
2014/04/04 Javascript
struts2+jquery组合验证注册用户是否存在
2014/04/30 Javascript
Javascript实现的Map集合工具类完整实例
2015/07/31 Javascript
Javascript动画效果(3)
2016/10/11 Javascript
去掉vue 中的代码规范检测两种方法(Eslint验证)
2018/03/21 Javascript
jQuery实现获取及设置CSS样式操作详解
2018/09/05 jQuery
Vue中使用 setTimeout() setInterval()函数的问题
2018/09/13 Javascript
vue+echarts实现动态绘制图表及异步加载数据的方法
2018/10/17 Javascript
JavaScript:ES2019 的新特性(译)
2019/08/08 Javascript
Vue状态模式实现窗口停靠功能(灵动、自由, 管理后台Admin界面)
2020/03/06 Javascript
ES2020 已定稿,真实场景案例分析
2020/05/25 Javascript
jQuery实现带进度条的轮播图
2020/09/13 jQuery
Python描述器descriptor详解
2015/02/03 Python
Python cookbook(数据结构与算法)通过公共键对字典列表排序算法示例
2018/03/15 Python
windows10下python3.5 pip3安装图文教程
2018/04/02 Python
python中的不可变数据类型与可变数据类型详解
2018/09/16 Python
python实现根据文件关键字进行切分为多个文件的示例
2018/12/10 Python
浅谈python3.x pool.map()方法的实质
2019/01/16 Python
安装Pycharm2019以及配置anconda教程的方法步骤
2019/11/11 Python
DJango的创建和使用详解(默认数据库sqlite3)
2019/11/18 Python
Python 私有属性和私有方法应用场景分析
2020/06/19 Python
Python中Selenium模块的使用详解
2020/10/09 Python
Selenium环境变量配置(火狐浏览器)及验证实现
2020/12/07 Python
Python urlopen()参数代码示例解析
2020/12/10 Python
Scotch Porter官方网站:男士美容产品
2020/08/31 全球购物
描述RIP和OSPF区别以及特点
2015/01/17 面试题
中药专业大学生医药工作求职信
2013/10/25 职场文书
初三班主任寄语大全
2014/04/04 职场文书
分公司负责人任命书
2014/06/04 职场文书
餐饮周年庆活动方案
2014/08/14 职场文书
士兵突击观后感
2015/06/16 职场文书