keans算法主要是将所有点与质心算距离,与每个点距离最小的质心就是它的类别,然后再从每一类中选取平均值作为新的质心
#核心算法中的数据处理示例:
#假设五个点与四个之心距离分别如下:
dist = np.array([[112,324,532,32],
[56,574,592,236],
[13,34,57,32],
[420,329,532,32],
[112,324,52,32]])
#截取每一行的最小值
c_ind=np.argmin(dist,axis=1)
print(c_ind)
#打印类别是否是3
print(c_ind==3)
#打印类别为3的点
print(dist[c_ind==3])
#打印类别为3的新的质心
prin(np.mean(dist[c_ind==3],axis=0))
[3 0 0 3 3]
[ True False False True True]
[[112 324 532 32]
[420 329 532 32]
[112 324 52 32]]
array([214.66666667, 325.66666667, 372. , 32. ])
以下是详细代码:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets._samples_generator import make_blobs
#sklearn中的一种方法,直接生成聚类数据,有些版本的_samples_generator也写作samples_generator
###数据加载
x,y = make_blobs(n_samples = 100,centers=6,random_state=1234,cluster_std=0.6)
#生成100个样本点,六个中心点,随机种子任意设置,标准差0.6
#x极为坐标,y为类别
x.shape
(100, 2)
##画图
plt.figure(figsize=(6,6))
plt.scatter(x[:,0],x[:,1],c=y)#y不同,颜色不同
plt.show()
###算法实现
from scipy.spatial.distance import cdist
##默认欧氏距离
class K_means(object):
##初始化参数n_clusters(K)、迭代次数max_iter、初始执行点centroids
def __init__(self,n_clusters=6,max_iter=300,centroids=[]):
self.n_clusters = n_clusters
self.max_iter=max_iter
self.centroids = np.array(centroids,dtype=np.float)
##训练模型方法,k-means聚类过程,传入原始数据
def fit(self,data):
#假如没有初始质心,就用data中的点做质心
if(self.centroids.shape ==(0,)):
#random.randint随机出data的n_clusters个索引值,得到原始质心
self.centroids = data[np.random.randint(0,data.shape[0],n_clusters),:]
#开始迭代
for i in range(self.max_iter):
#计算距离矩阵
distances = cdist(data,self.centroids)
#对距离按远近排序,选取最近质心点的类别,作为当前点的分类
#将distances这个(100,6)的矩阵截取为(100,1)的矩阵
c_ind= np.argmin(distances,axis=1)
#对每一类进行均值计算,更新质心点坐标
for i in range(self.n_clusters):
#排除掉没有出现在c_indt里的原始质心
if i in c_ind:
#选相互所有类别值为i的点,更新坐标值
self.centroids[i] = np.mean(data[c_ind==i],axis=0)
#预测
def predict(self,samples):
#先计算距离矩阵,在选取距离最近的那个质心的类别
distances=cdist(samples,self.centroids)
c_ind = np.argmin(distances,axis=1)
return c_ind
###测试
def plotKMeans(x,y,centroids,subplot,title):
#分配子图
plt.subplot(subplot)
plt.scatter(x[:,0],x[:,1],c='r')
#画出质心点
plt.scatter(centroids[:,0],centroids[:,1],c=np.array(range(5)),s=100)
plt.title(title)
kmeans=K_means(max_iter=300,centroids=np.array([[2,1],[2,2],[2,3],[2,4],[2,5]]))
plt.figure(figsize=(16,6))
plotKMeans(x,y,kmeans.centroids,121,'Initial State')
#开始聚类
kmeans.fit(x)
plotKMeans(x,y,kmeans.centroids,122,'Final State')
#打印当前质心
print(kmeans.centroids)
#预测新数据点类别
x_new= np.array([[0,0],[10,7]])
y_pred = kmeans.predict(x_new)
#打印两个点的分类
print(y_pred)
plt.scatter(x_new[:,0],x_new[:,1],s=100,c='black')
[[ 5.76444812 -4.67941789]
[-2.89174024 -0.22808556]
[-5.89115978 2.33887408]
[-2.8455246 5.87376915]
[ 9.20551979 7.56124841]]
[1 4]
由结果可知,[0,0],[10,7]两点分类的质心是[-2.89174024 -0.22808556]、 [ 9.20551979 7.56124841]