对于无监督学习,有两类重要的应用,一个是聚类,一个是降维。我们今天主要学习聚类中的K均值聚类。
我们先看看下图,图a为原始的数据点,我们想要对图a的数据点进行分类,在图b中我们先随机的指定两个质心点(×)作为初始点。如图c所示,距离红色点(×)近的我们分到红色类中,距离蓝色点(×)近的我们分类到蓝色类中。接下来我们更新质心点,如图d所示,根据已有红色的点,求均值,得到它们中间的质心点,更新为当前红色质心点,根据已有蓝色的点,求均值,得到它们中间的质心点,更新为当前蓝色的质心点。接下来如图e所示,再进行红色和蓝色数据点的划分,如图f所示,如此不停的迭代。
K均值聚类是聚类算法中最简单,最高效的,属于无监督学习方法,核心思想是:用户初始指定K个质心,以作为聚类的类别,重复迭代直至算法收敛。
基本算法流程如下:
1-选取K个初始的质心,作为初始的类别
2-对于每个样本点,计算得到距离其最近的质心,将该样本点对应的类别标记为质心所对应的类别
3-根据当前划分的类别情况,计算并更新K个类别对应的质心
4-直到质心不再发生变化或者达到迭代上限
下面我们具体实现K均值聚类算法,代码如下:
#K均值聚类算法实现
import numpy as np
import matplotlib.pyplot as plt
#从sklearn中直接生成聚类数据
from sklearn.datasets._samples_generator import make_blobs
#数据加载和处理,100个样本点,x为100行的,2列的矩阵
x, y = make_blobs(n_samples=100, centers=6, random_state=1234, cluster_std=0.6)
#画出散点图
#plt.figure(figsize=(6,6))
plt.scatter(x[:,0],x[:,1],c=y)
plt.show()
#算法实现
#引入scipy的距离函数,默认为欧式距离
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, np.float64) #数组转矩阵
#训练模型的方法,K均值聚类过程,传入原始数据
def fit(self, data):
#假如没有指定初始质心,就随机选取data中的点作为初始质心
if(self.centroids.shape == (0,)):
#从data中随机生成0到data行数的6个整数,作为索引值
self.centroids = data[np.random.randint(0, data.shape[0], self.n_clusters), :]
#开始迭代
for i in range(self.max_iter):
#1.计算距离矩阵,得到是一个100*6的矩阵
distance = cdist(data, self.centroids)
#2.对距离按由近到远排序,选取距离质心点最近的类别,作为当点的分类
c_ind = np.argmin(distance, axis=1)
#3.对每一类进行均值计算,更新质心点坐标
for i in range(self.n_clusters):
#排除掉没有出现c_ind里面的类别
if i in c_ind:
#选出所有类别为i的点,取data里面坐标的均值,更新第i个质心
self.centroids[i] = np.mean(data[c_ind==i], axis=0)
#实现预测方法
def predict(self, samples):
#先计算距离矩阵,选取距离最近的质心类别
distance = cdist(samples, self.centroids)
c_ind = np.argmin(distance, axis=1)
return c_ind
#测试
#定义一个绘制子图的函数
def plotKMeans(x, y, centroids, subplot, title):
#分配子图,121表示第一行二列的子图的第一个
plt.subplot(subplot)
plt.scatter(x[:,0], x[:,1], c='r')
#画出质心点
plt.scatter(centroids[:,0], centroids[:,1], c=np.array(range(6)), s=100)
plt.title(title)
kmeans = K_means(max_iter=300, centroids=np.array([[2,1],[2,2],[2,3],[2,4],[2,5],[2,6]]))
plt.figure(figsize=(16, 6))
plotKMeans(x, y, kmeans.centroids, 121, 'Initial State ')
#开始聚类
kmeans.fit(x)
plotKMeans(x, y,kmeans.centroids, 122, 'Final State')
#预测新数据点的类别
x_new = np.array([[0,0], [10,7]])
y_pred = kmeans.predict(x_new)
print(kmeans.centroids)
print(y_pred)
plt.scatter(x_new[:,0],x_new[:,1], s=100, c='black')
plt.show()
这幅图是调用原始数据集画出的6个聚类的散点图。当然这个不用管,主要看下面几幅图。
这个是利用原始数据集生成的100个红色样本点和随机生成的6个初始质心点。对于每个样本点,计算得到距离其最近的质心,将该样本点对应的类别标记为质心所对应的类别