J ( c ( 1 ) , c ( 2 ) , . . . , c ( m ) , μ 1 , μ 2 , . . . , μ k ) = 1 m ∑ i = 1 m ∣ ∣ x ( i ) − μ c ( i ) ∣ ∣ 2 J(c^{(1)},c^{(2)},...,c^{(m)},μ_1,μ_2,...,μ_k) = \frac 1 m \sum_{i=1}^m ||x^{(i)}-μ_{c^{(i)}}||^2 J(c(1),c(2),...,c(m),μ1,μ2,...,μk)=m1∑i=1m∣∣x(i)−μc(i)∣∣2
说明上式含义:上式为 K-means 的损失函数,其中 c ( 1 ) , . . . c ( m ) c^{(1)},...c^{(m)} c(1),...c(m) 代表着有 m 个等待分类的点; μ 1 , . . . , μ k μ_1,...,μ_k μ1,...,μk 代表着会分为 k k k 个组 Cluster。
而等式的右侧,即 ∣ ∣ x ( i ) − μ c ( i ) ∣ ∣ 2 ||x^{(i)}-μ_{c^{(i)}}||^2 ∣∣x(i)−μc(i)∣∣2,代表着第 i 个点距离 μ 1 , . . . , μ k μ_1,...,μ_k μ1,...,μk 点之间最近距离的值。当这些值的和为最小时,即每个点都得到了合理的分配,这时 损失函数 J 的值最小,且完成 K-means 聚类算法 的迭代与循环。
关于初始化 K 的值,以及初始化 K 的位置。
首先,k应该选择为多少合适?
elbow 方法:在 损失函数J-分类数量k 函数中,会有一个折点,在这点会骤减“ 通过增加分类数量k从而快速减少损失函数J” 的点。换句话说,在 elbow point 这点,会发现增大 k 的值不会给降低损失函数 J 带来很明显的影响。
很明显,J-K 函数 最终会与x轴相交,但是将m个点分成m组明显不是我们想要的。虽然我们的目的是为了尽量减少损失函数J,但是目标并不是损失函数J为零。
在 k 值的合理范围内,一般为 2-5 之间,枚举 k 带来的损失函数值,然后在更多k值带来的成本与减少的损失值之间进行权衡,选择一个合理的k值。
选定好分为几个类之后,第一步初始化k的位置应该怎么选?
假设 K=3,初始化三个 Centroid 点的位置为:
从坐标中16个待分类的点中不重复的选择三个点,然后按照 K-means 算法的步骤执行。有关 K-means 算法步骤 见博客【ML30】Basic K-means
根据初始化点的不同,最终得到的结果也是不同的。很明显,我们想要的结果(K=3时损失函数J最小)为三图中的最上面的图而非下面两个图。所以现在的问题是如何初始化K的位置可以最后得到我们想要的上图的结果?
方法为多次枚举。可能我们第一次,第二次初始化后没有得到最优解,但是我们循环10次,100次总会有达到最优解效果的一次。所以我们设置循环的方法,将10次,100次的方案的损失函数计算出来,然后找到损失函数最低的那次,作为我们的结果。
In pseudocode, the K-means algorithm is as follows:
# Initialize centroids
# K is the number of clusters
centroids = kMeans_init_centroids(X, K)
for iter in range(iterations):
# Cluster assignment step:
# Assign each data point to the closest centroid.
# idx[i] corresponds to the index of the centroid
# assigned to example i
idx = find_closest_centroids(X, centroids)
# Move centroid step:
# Compute means based on centroid assignments
centroids = compute_means(X, idx, K)
说明两个函数作用:
np.linalg.norm(a,b[0]): ( a [ 0 ] − b [ 0 ] ) 2 + ( a [ 1 ] − b [ 0 ] ) 2 + . . . + ( a [ m ] − b [ 0 ] ) 2 \sqrt {(a[0]-b[0])^2+(a[1]-b[0])^2+...+(a[m]-b[0])^2} (a[0]−b[0])2+(a[1]−b[0])2+...+(a[m]−b[0])2
np.argmin( c ): 获得数组 c 中最小值的索引值(位置) 获得数组 c 中最小值的索引值(位置) 获得数组c中最小值的索引值(位置)
from numpy import linalg as LA
def find_closest_centroids(X, centroids):
K = centroids.shape[0] # K即Centroid质心的数量
idx = np.zeros(X.shape[0], dtype=int) # 初始化一个全为零数的组,其目的是记录每个点的被分为哪个centroid
for i in range(X.shape[0]):
distance = []
for j in range(centroids.shape[0]):
norm_ij = LA.norm(X[i]-centroids[j]) # 为每个点测量其与所有质心的距离,记录在 distance 数组中。
distance.append(norm_ij)
idx[i] = np.argmin(distance) # idx数组中记录着每个点与哪个质心距离最近
return idx
说明一个函数的作用:
idx.ravel():将多维数组拉伸为一维数组
#####################################################################
STOP HERE
我想解释一下python函数含义,当然已知可以跳过直接看代码部分
X[idx.ravel() == k, :]
首先,ravel 函数的作用:
import numpy as np
a = np.array([[1,2,3],
[4,5,1],
[7,8,1]])
b = a.ravel() # 用ravel()方法将数组a拉成一维数组
print(b)
“拉伸”后结果
其次,解释 idx.ravel() == k
import numpy as np # 导入numpy模块
a = np.array([[1,2,3],
[4,5,1],
[7,8,1]])
b = a.ravel()==1 # 设置b为a拉伸成为一维数组之后值为1的索引的数组
print(b)
STOP END
#####################################################################
def compute_centroids(X, idx, K):
m, n = X.shape
centroids = np.zeros((K, n))
for k in range(K):
centroids[k, :] = np.mean(X[idx.ravel() == k, :], axis=0)
return centroids
def run_kMeans(X, initial_centroids, max_iters=10):
m, n = X.shape
K = initial_centroids.shape[0]
centroids = initial_centroids
previous_centroids = centroids
idx = np.zeros(m)
for i in range(max_iters):
print("K-Means iteration %d/%d" % (i, max_iters-1))
idx = find_closest_centroids(X, centroids) # 分配质心
centroids = compute_centroids(X, idx, K) # 重置质心位置
plt.show()
return centroids, idx
np.random.permutation(a):将a数组中所有值重新排序
#####################################################################
STOP HERE
np.random.permutation(a):将二维数组a重新随意排序,要注意重新随意排序的概念。
import numpy as np
a = np.array([[1,2],
[2,3],
[3,4],
[4,5]])
print(np.random.permutation(a))
结果:
STOP END
#####################################################################
def kMeans_init_centroids(X, K):
randidx = np.random.permutation(X.shape[0]) # 对X中所有数组的索引重新随意排序
centroids = X[randidx[:K]] # 取随意排序后前K个
return centroids
end —>