尝试了一下深夜模式, 感觉非常好,外界温度降低使得脑子不容易过载,就是有点饿。
OK,回归正题,花了一点时间实现了 K-Means 算法,以及改良版的 K-Means++
原理和算法都比较简单,这里不再过多赘述。
如果有不太懂的右转中文 wiki :K-Means算法
这里主要讲一下使用 K-Means 时遇到的一些问题。
这是本周作业的 Github :https://github.com/hachiri/ML_Seminar/tree/master/2019.10.19
对于首次选取聚点时,K-Means 我使用了这种算法:
这是一个选取了随机中间值的简易方法。
def creat_random_centP(dataset, k):
'''Take k random centers of mass'''
dim = np.shape(dataset)[1]
centP = np.zeros([k, dim])
for i in range(dim):
data_min = np.min(dataset[:,i])
data_max = np.max(dataset[:,i])
# Create random values between the maximum and minimum in each dimension
centP[:,i] = (np.random.rand(k, 1).dot(data_max - data_min) + data_min)[:,0]
return centP
在实测过程中,这种方法有一定的概率出现误差,最终会导致聚点无法收敛,产生 NA 值
于是有了改进版的 K-Means++
def creat_plusplusrandom_centP(dataset, k, calcu_dist=calculate_Euclidist):
'''Take k random centers of mass from the existing data'''
m = np.shape(dataset)[0]
cent_numbers = []
cent_numbers.append(np.random.randint(0, m-1))
distance_M = np.zeros([m, m])
for i in range(m):
for j in range(i + 1, m):
distance_M[i][j] = calcu_dist(dataset[i,:], dataset[j,:])
distance_M[j][i] = distance_M[i][j].copy()
while len(cent_numbers) < k:
prob_sum = np.cumsum(distance_M[:,cent_numbers[-1]]) / np.sum(distance_M[:,cent_numbers[-1]])
P = np.random.rand()
random_number = np.nonzero(prob_sum <= P)[-1][-1]
if random_number not in cent_numbers:
cent_numbers.append(random_number)
return dataset[cent_numbers]
相比 K-Means ,选取聚点是从已有点内通过计算概率获得,从而降低了误差
最终完成版的效果图:https://nbviewer.jupyter.org/github/hachiri/ML_Seminar/blob/master/2019.10.19/k-means.ipynb
PS:今天看到了Google Machine Learning Winter Camp 2020 Application Form,非常激动,特别激动,就想着能不能被选上。填空框起码有东西勉勉强强都能够凑进去,虽然奖项LEVEL太低了。