算法:
- 首先确定一个k值,即我们希望将数据集经过聚类得到k个集合。
- 从数据集中随机选择k个数据点作为质心。
- 对数据集中每一个点,计算其与每一个质心的距离(如欧式距离),离哪个质心近,就划分到那个质心所属的集合。
- 把所有数据归好集合后,一共有k个集合。然后重新计算每个集合的质心。
- 如果新计算出来的质心和原来的质心之间的距离小于某一个设置的阈值(表示重新计算的质心的位置变化不大,趋于稳定,或者说收敛),我们可以认为聚类已经达到期望的结果,算法终止。
- 如果新质心和原质心距离变化很大,需要迭代3~5步骤。
代码:
import numpy as np
import matplotlib.pyplot as plt
# map 100*100
high = 100
width = 100
# create random data
data = np.random.rand(100, 2)
data = data * [high, width]
data = np.hstack((data, np.zeros([100, 1])))
# count of classes
classes = 5
def distance(point1, center):
return np.sqrt((point1[0] - center[0]) ** 2 + (point1[1] - center[1]) ** 2)
def color(i):
global classes
return i * 255. / classes
if __name__ == '__main__':
plt.ion()
# select center randomly
centers = np.random.randint(0, 100, [classes])
centers_data = []
for i in range(classes):
data[i][2] = i
centers_data.append(data[i])
while True:
colors = [color(x) for x in data[:, 2]]
plt.scatter(data[:, 0], data[:, 1], c=colors)
plt.pause(0.5)
# caculate nearest center
for i in range(100):
distances = np.array([distance(data[i], center_data) for center_data in centers_data])
i_class = np.argmin(distances)
data[i][2] = i_class
# caculate new center
new_centers_data = np.zeros([classes, 2])
new_centers_count = np.zeros([classes])
for j in range(5):
for i in range(100):
if data[i][2] == j:
new_centers_count[j] += 1
new_centers_data[j] += data[i][0:2]
new_centers_data /= np.array([new_centers_count]).T
dist = np.max([distance(new_centers_data[i], centers_data[i]) for i in range(classes)])
print('max distance ', dist)
if dist < 1e-4:
break
centers_data = new_centers_data
plt.ioff()
plt.show()
print('kmeans completed.')