k-means算法流程
从数据集中随机选择k个聚类样本作为初始的聚类中心,然后计算数据集中每个样本到这k个聚类中心的距离,并将此样本分到距离最小的聚类中心所对应的类中。将所有样本归类后,对于每个类别重新计算每个类别的聚类中心即每个类中所有样本的质心,重复以上操作直到聚类中心不变为止。
缺点
k-means存在缺点:
1)k-means是局部最优的,容易受到初始质心的影响
2)同时,k值的选取也会直接影响聚类结果,最优聚类的k值应与样本数据本身的结构信息相吻合,而这种结构信息是很难去掌握,因此选取最优k值是非常困难的。
改进
选取密度最大的作为第一个类中心,然后选取距离第一个类中心最远的作为第二个类中心,然后选取距离两个类中心都较远的作为第三个类中心,依次类推。。。
参考代码
def kmeans(k):
m, n = 100, 20 # 构造样本:100行、20列
x = 10 * np.random.random((m, n))
# 随机选择k个初始中心点
init_cent_sample = set()
while len(init_cent_sample) < k:
init_cent_sample.add(np.random.randint(0, m))
cent = x[list(init_cent_sample)]
# 记录每个样本的类归属
cluster_assessment = np.zeros((m, 2))
# 记录每个类的中心点在本次迭代后是否有过改变
cent_changed = True
while cent_changed:
cent_changed = False
for j in range(m):
# 记录每个样本距离最近的类
min_inx = -1
# 记录每个样本的最小类距
min_dist = math.inf
for i in range(k):
d = distance(x[j], cent[i])
if d < min_dist:
min_dist = d
min_inx = i
# 记录此样本的中心点是否发生变化
if min_inx != cluster_assessment[j][0]:
cluster_assessment[j] = np.array([min_inx, min_dist])
cent_changed = True
print(cluster_assessment)
# 更新每个类的中心点:均值
for i in range(k):
cent_i_samples = np.where(cluster_assessment[:, 0] == i)
if len(cent_i_samples) > 0:
print(cent_i_samples)
cent[i] = np.mean(x[cent_i_samples], axis=0)
# 计算距离
def distance(a, b):
return math.sqrt(sum(pow(a - b, 2)))