kmeans:
kmeans为一种简单的聚类算法,是一种无监督学习算法,主要作用是将众多无标签样本聚为指定的几个类。接下来简单介绍一下kmeans。首先,我们假设聚类中心为,每个聚类中心有一个簇,每个簇的样本个数依次为。则我们认为k-means的损失函数为,则,令可以得到。因此,最优的聚类中心应当在每个簇的均值点处。从另一个角度来看,我们假设每个簇均服从正太分布,且方差都相等,但均值不等,其均值依次为,每个簇的标准差均为。则全体样本的似然函数为,取负对数似然后不考虑常数可得,因此得出了损失函数,可见一开始给出的损失函数就是假设样本服从正太分布后使用对数似然得到的,因此kmeans适用于样本服从混合高斯分布的数据。
kmeans的具体步骤分为以下几步:
step1:随机设定初始聚类中心
step2:将距离某个聚类中心距离近的样本点归类到该聚类中心,将样本全部归类完毕后得到多个簇
step3:计算每个簇的均值作为新的聚类中心
step4:重复第二步和第三步直至聚类中心不再发生变化
kmeans++:kmeans++只是在选择聚类中心上对kmeans进行了改进,聚类过程任然采用kmeans的方法。因此,这里对于kmeans++对于聚类中心的选取进行解释。聚类中心之间的距离应当尽可能的大,正是出于这一思想,kmeans++采用如下方式进行聚类中心的选取。
step1:首先从所有样本中随机选定第一个聚类中心
step2:记录所有样本到与其最近的聚类中心的距离
step3:所有非聚类中心样本点被选取作为下一个聚类中心的概率与step2中的距离大小成正比,也就是说距离越远的样本点越有 可能成为下一个聚类中心
step4:重复step2和step3直至选出多个聚类中心
接下来给出python的kmeans++代码:
# coding: utf-8
# In[1]:
import numpy as np
from numpy import random as rd
import matplotlib.pyplot as plt
# In[2]:
def get_distance(centers, samples):
"""
centers:聚类中心列表
samples:样本点
获得所有样本点到所有聚类中心的距离,所有样本点到第一个类中心的距离放置在d_1中,到第二个聚类中心的距离防止在d_2中...,d_k为数组
选取距离样本点最近的聚类中心的距离作为当前样本点所对应的距离
"""
centers = np.array(centers)
samples = np.array(samples)
# ds=[d_1, d_2, ...]
ds = []
for i in range(centers.shape[0]):
ds.append(np.sqrt(np.sum(np.square(samples - centers[i]), axis=1)))
ds = np.array(ds)
samples_distance = np.min(ds, axis=0)
return samples_distance
# In[3]:
def roll_select(samples_distance):
"""
samples_distance:为样本当前的距离列表,get_distance的返回结果
选择下一个聚类中心,以距离远近作为概率值,距离越远则被选择概率越大,距离越近则概率越小
"""
# 依据距离计算每个样本点被选择作为下一个聚类中心点的概率
p = samples_distance / np.sum(samples_distance)
# 采用轮盘赌选择法选择下一个聚类中心
cum_p = np.cumsum(p)
select_index_lst = []
# 为确保选择聚类中心比较靠谱,做多次轮盘赌选择出现次数比较多的样本索引
for i in range(int(0.15 * len(samples_distance))):
rand_num = rd.random()
select_index = list(rand_num > cum_p).index(False)
select_index_lst.append(select_index)
count_dict = {i: select_index_lst.count(i) for i in np.unique(select_index_lst)}
select_index = sorted(count_dict, key=lambda x: count_dict[x])[-1]
return select_index
# In[4]:
# 构造样本点
cluster_1 = rd.normal(1.2, 0.1, (100, 2))
cluster_2 = rd.normal(1.5, 0.1, (100, 2))
cluster_3 = rd.normal(1.8, 0.1, (100, 2))
cluster_4 = rd.normal(0.9, 0.1, (100, 2))
cluster_4[:, 0] = cluster_4[:, 0] + rd.normal(0.9, 0.1, 100)
samples = np.concatenate([cluster_1, cluster_2, cluster_3, cluster_4], axis=0)
# In[5]:
ax = plt.subplot(1, 1, 1)
ax.scatter(samples[:, 0], samples[:, 1], label="samples")
ax.grid()
ax.legend()
plt.show()
# In[6]:
# 找n个聚类中心
n = 4
# 随机选出第一个聚类中心
centers = [samples[rd.randint(samples.shape[0])]]
for i in range(n - 1):
# 依据距离迭代选出后n-1个聚类中心
samples_distance = get_distance(centers, samples)
select_index = roll_select(samples_distance)
centers.append(samples[select_index])
# In[7]:
ax = plt.subplot(1, 1, 1)
ax.scatter(samples[:, 0], samples[:, 1], label="samples")
ax.scatter(np.array(centers)[:, 0], np.array(centers)[:, 1], s=200, marker="*", color="r", label="center", edgecolors="black")
ax.legend()
ax.set_title("samples and centers")
ax.grid()
plt.show()
# In[8]:
# kmeans聚类
# kmeans聚类进行t次迭代
t = 10
fig = plt.figure(figsize=(20, 20))
ax_lst = []
for i in range(t):
ax_lst.append(plt.subplot(int(np.sqrt(t)), int(np.sqrt(t)) + 1, i + 1))
for i in range(t):
# 1.计算所有样本到各个聚类中心的距离distances, distances[k]为第k+1个聚类中心到全部样本点的距离
distances = np.array([np.sqrt(np.sum(np.power((samples - center), 2), axis=1)) for center in centers])
# 计算每个样本属于哪个聚类中心
belong_wich_center = np.argmin(distances, axis=0)
ax = ax_lst[i]
for j in range(len(centers)):
# 第i + 1个聚类中心包含的样本点conclude_samples
conclude_samples = samples[belong_wich_center == j]
ax.scatter(conclude_samples[:, 0], conclude_samples[:, 1], label="%d" % j)
centers[j] = np.mean(conclude_samples, axis=0)
ax.scatter(np.array(centers)[:, 0], np.array(centers)[:, 1], s=200, marker="*", label="center", edgecolors="black")
ax.set_title("%d iteration" % (i + 1,))
ax.legend()
ax.grid()
plt.show()
# In[9]:
distances.shape