学习目标
七月的最后一次更新(1/2),坚持!学会无监督学习中的聚类。
笔记
1 K-means算法
主要思想:在给定K值和K个初始类簇中心点的情况下,把每个点(亦即数据记录)分到离其最近的类簇中心点所代表的类簇中,所有点分配完毕之后,根据一个类簇内的所有点重新计算该类簇的中心点(取平均值),然后再迭代的进行分配点和更新类簇中心点的步骤,直至类簇中心点的变化很小,或者达到指定的迭代次数。
参考: Kmeans聚类-K值以及簇中心点的选取
1.1 步骤
- 随机初始化K个聚类簇心 μ 1 \mu_{1} μ1、 μ 2 \mu_{2} μ2… μ k \mu_{k} μk;
- 重复以下两个步骤:
(1)将所有数据点分配给最近的簇心(遍历m个数据点,建立一个列表,储存每个数据点的最近簇心索引);
(2)移动簇心(遍历k个簇心,更新每个簇心的数值:分配的点的均值)。
1.2 优化目标
J
(
c
(
1
)
,
.
.
.
,
c
(
m
)
,
μ
1
,
.
.
.
,
μ
k
)
=
1
m
∑
i
=
1
m
∣
∣
x
(
i
)
−
μ
c
(
i
)
∣
∣
2
J(c^{(1)},...,c^{(m)},\mu_{1},...,\mu_{k}) = \frac{1}{m}\sum_{i=1}^{m}{||x^{(i)}-\mu_{c(i) }||^2}
J(c(1),...,c(m),μ1,...,μk)=m1i=1∑m∣∣x(i)−μc(i)∣∣2
其中,
c
(
i
)
c^{(i)}
c(i)是
x
(
i
)
x^{(i)}
x(i)对应的最近簇心的索引列表,
μ
k
\mu_{k}
μk是类k的均值点。
1.3 选择聚类数量K
选择能使损失函数最小的K不是一个好方法(K倾向于取最大值)。在实践中选择K,要结合实际需求,评估是否符合后续业务的开展。
注:有一种不太推荐的方法是:肘子法(elbow method)。建立K和损失函数的关系图,找到使得损失由陡峭到平坦的转折点,对应的K值就是我们想要的结果。
1.4 随机初始化簇心
K-Means算法对初始簇心的选择很敏感,不同的随机种子点得到的聚类结果完全不同。
选择簇心往往遵照下面的方法:
def kMeans_init_centroids(X, K):
# 对X随机重排序,得到索引
randidx = np.random.permutation(X.shape[0])
# 取前K个当作簇心
centroids = X[randidx[:K]]
return centroids
将上述随机初始化过程重复50到1000次,将每一次随机初始化的簇心组合代入k-means中进行运算,并计算损失,选择使得损失最小的一组簇心作为最终结果。
1.5 K-means算法的python实现
# 计算每个X的最近簇心
def find_closest_centroids(X, centroids):
K = centroids.shape[0]
idx = np.zeros(X.shape[0], dtype=int)
for i in range(X.shape[0]):
distance = []
for j in range(centroids.shape[0]):
norm_ij = np.linalg.norm(X[i] - centroids[j])
distance.append(norm_ij)
idx[i] = np.argmin(distance)
return idx
# 计算每个簇心对应的数据点的均值
def compute_centroids(X, idx, K):
m, n = X.shape
centroids = np.zeros((K, n))
for k in range(K):
points = X[idx == k]
centroids[k] = np.mean(points,axis=0)
return centroids
# 调用上面两个函数,运行K-means
def run_kMeans(X, initial_centroids, max_iters=10, plot_progress=False):
# 初始化值
m, n = X.shape
K = initial_centroids.shape[0]
centroids = initial_centroids
previous_centroids = centroids
idx = np.zeros(m)
# 运行K-Means
for i in range(max_iters):
print("K-Means iteration %d/%d" % (i, max_iters-1))
idx = find_closest_centroids(X, centroids)
# 绘制过程
if plot_progress:
plot_progress_kMeans(X, centroids, previous_centroids, idx, K, i)
previous_centroids = centroids
# 计算新簇心
centroids = compute_centroids(X, idx, K)
plt.show()
return centroids, idx
2 K-means 应用
2.1 K-means用于图像压缩
总结
- K值需要预先给定,结合实际需求,设定合理的K值很困难;
- K-Means算法对初始簇心的选择很敏感;
- K均值算法并不是很所有的数据类型。它不能处理非球形簇、不同尺寸和不同密度的簇;
- 不适合直接对含有离群点的数据进行聚类;这种情况下,离群点检测和删除有很大的帮助。
参考:
链接: k-means基础
需要注意的地方
- 优化目标的视频部分还是不太懂;
- 聚类还有很多种变体,本文介绍的是常规的简单方法,之后再加以补充。