总体说明:
这篇文章是想简单的让大家理解一下k_means聚类的本质,和过程实现,方便后面能看懂复杂工程上的应用。要是这篇文章看懂了的话可以看看下面链接的工程应用代码实现。
K-means 聚类算法及其代码实现_Jim_Liu-CSDN博客_k-means代码
1、定义:
上图的数据可以分成两个分开的点集(称为簇),一个能够找到这些点集的算法,就被称为聚类算法。
原理:设法定出不同类别的核心或初始内核,然后依据样本与核心之间的相似性度量将样本聚集成不同的类别。
2、聚类算法的一般步骤:
S1:先定义总共有多少个类/簇(cluster)
S2:将每个簇心(cluster centers)随机定在一个点上
S3:将每个数据点关联到最近簇中心所属的簇上
S4:对于每一个簇找到其所有关联点的中心点(取每一个点坐标的平均值)
S5:将上述点变为新的簇心
S6:不停重复,直到每个簇所拥有的点不变
3、聚类算法的应用:
在商务上,聚类能帮助市场分析人员从客户基本库中发现不同的客户群,并且用购买模式来刻画不同的客户群的特征。在生物学上,聚类能用于推导植物和动物的分类,对基因进行分类,获得对种群中固有结构的认识。聚类在地球观测数据库中相似地区的确定,汽车保险单持有者的分组,及根据房子的类型、价值和地理位置对一个城市中房屋的分组上也可以发挥作用。聚类也能用于对Web上的文档进行分类,以发现信息。诸如此类,聚类有着广泛的实际应用。
4、聚类算法的代码实现:
#题目:一共有6个点,坐标如下。将其分为两个簇,起始时,随机选两个点作为两个簇的簇心,问最后簇的所属情况
'''
A0(1,2)
A1(1,4)
A2(3,1)
A3(3,5)
A4(5,2)
A5(5,4)
'''
import random
import numpy as np
import torch
import math
import numpy as np
import matplotlib.pyplot as plt
COOEDINATE = [(1,2),(1,4),(3,1),(3,5),(5,2),(5,4)]
#1、随机选取一个坐标,作为簇心
# 从给定列表中生成了 n 个随机样本。
init_seed = 0
#GPU
#torch.cuda.manual_seed(init_seed)
#torch.cuda.manual_seed_all(init_seed)
torch.manual_seed(init_seed)
random.seed(init_seed)
X1,X2 =random.sample(COOEDINATE,2)
#print(X1,X2) #(3, 5) (5, 4)
#2、将其余四个点按距离聚类
#3、计算平均值,从新选择簇心
sum0=0
sum1=0
data1 = []
data2 = []
X3 = (0,0)
X4 = (0,0)
k=0
while(1): #当簇心不再变化时说明聚类完成
i=0
class1 = []
class2 = []
#计算距离,聚类
for x in COOEDINATE:
data1.append(list(x)[0])
data1.append(list(x)[1])
data1.append(list(X1)[0])
data1.append(list(X1)[1])
result1 = math.sqrt(
math.pow(
data1[0+i] -
data1[2],
2) +
math.pow(
data1[1+i] -
data1[3],
2))
data2.append(list(x)[0])
data2.append(list(x)[1])
data2.append(list(X2)[0])
data2.append(list(X2)[1])
result2 = math.sqrt(
math.pow(
data2[0+i] -
data2[2],
2) +
math.pow(
data2[1+i] -
data2[3],
2))
#print('result1,result2:',result1,result2)
if result1<=result2:
class1.append(x)
else:
class2.append(x)
i+=4
for j in class1:
sum0 += j[0]
sum1 += j[1]
X3 = (sum0/len(class1),sum1/len(class1))
print('x1,x',int(list(X1)[0]),int(list(X3)[0]))
print('y1,y',int(list(X1)[1]),int(list(X3)[1]))
if X1 != X3:
X1 = X3
sum0 = 0
sum1 = 0
for j in class2:
sum0 += j[0]
sum1 += j[1]
X4 = (sum0/len(class2),sum1/len(class2))
print('x2,x',int(list(X2)[0]),int(list(X4)[0]))
print('y2,y',int(list(X2)[1]),int(list(X4)[1]))
if X2 != X4:
X2 = X4
elif int(list(X1)[0] == list(X3)[0]) & int(list(X1)[1] == list(X3)[1]) & int(list(X2)[0] == list(X4)[0]) & int(list(X2)[1] == list(X4)[1]):
print("聚类完成,簇心为:",X2)
break
k+=1
if k >= 60:
break
print(class1)
print(class2)
#4、可视化
#!/usr/bin/env python3
from matplotlib import pyplot as plt
from matplotlib.font_manager import FontProperties #显示中文
x_a = []
y_a = []
for i in class1:
x_a.append(list(i)[0])
y_a.append(list(i)[1])
x_b = []
y_b = []
for i in class2:
x_b.append(list(i)[0])
y_b.append(list(i)[1])
# _xticks_a=["{}类".format(i) for i in x_a]
# _xticks_b=["{}类".format(i) for i in x_b]
_xticks_a=x_a
_xticks_b=x_b
# 设置图片大小
plt.figure(figsize=(10,8),dpi=80)
# 画散点图
plt.scatter(x_a, y_a)
plt.scatter(x_b, y_b)
# x轴刻度
_xticks = _xticks_a + _xticks_b
_x = list(x_a) + list(x_b)
plt.xticks(_x,_xticks,rotation=0) # rotation:旋转显示x轴文字信息
plt.savefig("kmeans.jpg")
plt.show() #顺序一定不能弄反,不然保存会出问题(空白)
实验结果: