Python实现-Kmeans聚类算法
- 1.Kmeans聚类定义
- 2.问题描述
- 3.实现过程
1. Kmeans聚类算法
Kmeans聚类算法: k均值聚类算法(k-means clustering algorithm)是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。每分配一个样本,聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。来自 百度百科本人理解: k均值聚类算法(k-means clustering algorithm)即通过随机得到的K个聚类对象作为聚类中心,把每个对象分配给距离它最近的聚类中心。每次迭代聚类求解都是对不同的聚类中心进行聚类分组求解,直到满足某个条件,不在进行迭代。
2. 问题描述
问题描述: 随机生成100个点,分成N类(N),在100个点中随机出N个点作为初始的分类中心点,计算其他点和这N个点之间的距离,将整个点分给距离最近的点.
收敛条件: 计算新的中心点(质心):通过新生成的聚类求取想x,y平均值 。当本次的聚类中心点和上次的聚类中心点距离差小于threshold(限制条件)时,迭代结束。
3. 代码实现
import random
import matplotlib.pyplot as plt
class Kmeans():
def __init__(self, k):
'''
初始化
:param k:代表聚类中心的个数
'''
self.__k = k
self.__data = [] #存放原始数据,初次生成的100个点
self.__pointCenter = [] #存放聚类中心点
self.__result = [] #存放最后的聚类结果
for i in range(k): #默认有5个聚类,即生成[[],[],[],[],[]]
self.__result.append([]) #五个子列表,存放分类的点
pass
pass
def calDistance(self,points1,points2):
'''
欧式距离:sprt((x1-x2)^2+(y1-y2)^2)
:param points1: 一维列表
:param points2: 一维列表
:return: 两个点之间的直线距离
'''
distance=(sum([(x1-x2)**2 for x1,x2 in zip(points1,points2)]))**0.5 #开平方等于乘以1/2次方
return distance
pass
def randomCenter(self):
'''
生成self.__pointCenter:初次聚类中心点列表
:return:
'''
while len(self.__pointCenter)<self.__k:
index=random.randint(0,len(self.__data)) #得到0-len(self.__data)-1之间的索引
if self.__data[index] not in self.__pointCenter: #用索引值得到列表的值
self.__pointCenter.append(self.__data[index])
pass
pass
def calPointToCenterDistance(self,data,center):
'''
计算每个点和聚类中心点之间的距离
:param data: 原始数据,初次生成的100个点
:param center: 中心聚类点
:return: 距离
'''
distance=[]
for i in data:
distance.append([self.calDistance(i,centerpoint) for centerpoint in center])
pass
return distance
pass
# def sortPoint(self,distance):
# '''
# 对原始数据进行分类,将每个点分到离他最近的聚类中心点
# :param distance: 得到的距离值
# :return: 返回最终的分类结果
# '''
# for i in distance:
# index=i.index(min(i)) #得到五个距离值中的最小值的索引
# self.__result[index].append(self.__data[i]) #通过索引进行分类
# pass
# return self.__result
# pass
def calNewCenterPoint(self,result):
'''
计算新的中心点:生成方式:通过生成的新的聚类求取新的平均值
:param result: 分类结果
:return: 返回新的聚类中心点
'''
newCenterPoint1=[]
for temp in result:
#进行转置,即将N*M转为M*N形式,即将所有point.x值和point.y值装置到一个列表中
#例如:[[x1,y1],[x2,y2]] 装置后: [[x1,x2],[y1,y2]]。便于求取新的平均值
temps=[[temp[x][i] for x in range(len(temp))] for i in range(len(temp[0]))]
point=[]
for i in temps:
point.append(sum(i)/len(i))#求和在除以数组长度,求取平均值
pass
newCenterPoint1.append(point)
pass
return newCenterPoint1
pass
def calCenterToCenterDistance(self,old,new):
'''
迭代结束条件:
计算新旧中心点之间的距离:
:param old:
:param new:
:return:
'''
total=0
for point1,point2 in zip(old,new):
total += self.calDistance(point1,point2)
pass
return total/len(old)
pass
def fit(self,data,threshold,times=50000):
self.__data = data
self.randomCenter()
print(self.__pointCenter)
centerDistance = self.calPointToCenterDistance(self.__data, self.__pointCenter)
# 对原始数据进行分类,将每个点分到离它最近的中心点
i = 0
for temp in centerDistance:
index = temp.index(min(temp))
self.__result[index].append(self.__data[i])
i += 1
pass
# 打印分类结果
# print(self.__result)
oldCenterPoint = self.__pointCenter
newCenterPoint = self.calNewCenterPoint(self.__result)
while self.calCenterToCenterDistance(oldCenterPoint, newCenterPoint) > threshold:
times -= 1
result = []
for i in range(self.__k):
result.append([])
pass
# 保存上次的中心点
oldCenterPoint = newCenterPoint
centerDistance = self.calPointToCenterDistance(self.__data,newCenterPoint)
# 对原始数据进行分类,将每个点分到离它最近的中心点
i = 0
for temp in centerDistance:
index = temp.index(min(temp))
result[index].append(self.__data[i]) # result = [[[10,20]]]
i += 1
pass
newCenterPoint = self.calNewCenterPoint(result)
print(self.calCenterToCenterDistance(oldCenterPoint, newCenterPoint))
self.__result = result
pass
self.__pointCenter = newCenterPoint
return newCenterPoint, self.__result
pass
pass
if __name__ == "__main__":
data = [[random.randint(1, 100), random.randint(1, 100)] for i in range(1000)]
for i in range(100):
kmeans = Kmeans(k=5)
centerPoint, result = kmeans.fit(data, 0.0001)
print(centerPoint)
plt.plot()
plt.title("KMeans Classification")
i = 0
tempx = []
tempy = []
color = []
for temp in result:
temps = [[temp[x][i] for x in range(len(temp))] for i in range(len(temp[0]))]
color += [i] * len(temps[0])
tempx += temps[0]
tempy += temps[1]
i += 2
pass
plt.scatter(tempx, tempy, c=color, s=30)
plt.show()
pass
pass
如图所示为聚类分组图片