K-means聚类的基本原理就不多阐述了,这里直接讲解如何实现。
效果图(红色节点代表聚类中心,蓝色节点和绿色节点代表不同的两类):
可以看到,初始时绿色节点很少且大多聚集于左下方,随着聚类中心的移动,绿色节点区域越来越大,直到最后会稳定下来。
一、建节点类
由于该聚类算法是基于二维的,因此基本元素就是节点,这里就将每个节点作为一个类Node。
其中nearest_node是一个list,其含义是:
①如果该节点是普通节点,则存储其归属的聚类中心;
②如果该节点是聚类中心,则存储对应的普通节点。
class Node:
x = 0
y = 0
distance = 0
nearest_node = []
def __init__(self):
self.x = random.uniform(0, 1)
self.y = random.uniform(0, 1)
self.nearest_node = []
def distance(self, Node):
x1 = (self.x - Node.x) * (self.x - Node.x)
y1 = (self.y - Node.y) * (self.y - Node.y)
distance = math.sqrt(x1 + y1)
return distance
二、计算节点归于哪个聚类中心
利用Node类中的distance方法计算每个普通节点归属于哪个聚类中心。
for i in range(0, len(node)):
min = 999
index = 0
for j in range(0, len(center)):
if node[i].distance(center[j]) < min:
min = node[i].distance(center[j])
index = j
center[index].nearest_node.append(node[i])
node[i].nearest_node.append(center[index])
对每一个聚类中心而已,找到其对应的所有普通节点,求出它们的平均位置(即x坐标和y坐标的位置)。
接着就以这个平均位置作为自身新的位置。
for i in range(0, len(center)):
x_total = 0
y_total = 0
x_new = 0
y_new = 0
for item in center[i].nearest_node:
x_total += item.x
y_total += item.y
print x_total
print y_total
x_new = x_total / len(center[i].nearest_node)
y_new = y_total / len(center[i].nearest_node)
center[i].x = x_new
center[i].y = y_new
四、画出拓扑图,标记聚类中心
如果是聚类中心,则用红色节点表示;
如果是第一类普通节点,则用蓝色节点表示;
如果是第二类普通节点,则用绿色节点表示。
for item in node:
if item.nearest_node[0] == center[0]:
plt.plot(item.x, item.y, 'bo')
if item.nearest_node[0] == center[1]:
plt.plot(item.x, item.y, 'go')
item.nearest_node = []
for item in center:
plt.plot(item.x, item.y, 'ro')
item.nearest_node = []
plt.show()