4 经典非监督学习算法—K-Means聚类 机器学习基础理论入门

4 经典非监督学习算法—K-Means聚类 机器学习基础理论入门

4.1 高斯混合模型

本节内容主要是介绍单变量高斯混合模型的数学表示和集合表示,虽然在K均值聚类中没有很多用武之地,但是在期望最大算法中,五年会更深入的了解一般意义上的高斯混合模型以及高斯混合聚类。

单高斯模型(gaussian single model)

在这里插入图片描述
在这里插入图片描述
中间多,两边少时高斯模型的典型特征

高斯混合模型(gaussian mixed model)

随机变量X属于k个单高斯模型中的某一个,那么:

在这里插入图片描述
在这里插入图片描述

4.2 度量距离的几种方法

这里的距离特指两个特征向量之间的距离,是描述特征向量关系的重要指标。一般来说,距离越小,关系越接近。除了距离,还有余弦相似度衡量两个特征向量的关系。

什么是距离

(1) 距离度量了两个特征向量xi, yj的远近程度(或相似程度,距离越近,相似度越高)
(2) 记xi, yj之间的距离为dist(xi, yj)

距离的性质

在这里插入图片描述
在这里插入图片描述

闵可夫斯基距离(Minkowski distance)

在这里插入图片描述
欧式距离
当p=2时,闵可夫斯基距离成为欧氏距离(eculidean distance)
在这里插入图片描述
曼哈顿距离
当p=1时,闵可夫斯基距离成为曼哈顿距离(manhattan distance),也叫街道距离
在这里插入图片描述
局限性
只能处理连续实数值和有序值,无法处理无序离散值。

VDM(value difference metric)

在这里插入图片描述
VDM距离与闵可夫斯基距离结合
假设有nc个有序属性,n-nc个无序属性,并且假设有序属性排在无序属性之前,那么:
在这里插入图片描述

加权距离

在这里插入图片描述

4.3 评价聚类效果的几种方法

什么是聚类

聚类:非监督学习算法。把相似的对象通过静态分类的方法分成不同的组别或更多的子集,这样让在同一个子集中的成员对象都有相似的一些属性。

簇的概念(cluster)

簇;一个簇表示由多个距离相近的对象所组成的集合(聚类就是把原始混乱的数据集划分为多个簇的过程)

外部指标和内部指标

在这里插入图片描述

外部指标

假设
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Jaccard系数(Jaccard coeddicient, 简称JC)
在这里插入图片描述
大小在0-1之间,且越大越好

FM指数(fowlkes and mallows index)
在这里插入图片描述
大小在0-1之间,且越大越好

Rand指数(Rand index)
在这里插入图片描述
大小在0-1之间,且越大越好

内部指标

假设
在这里插入图片描述
DB指数(davies-bouldin index)
在这里插入图片描述
DB指数越小越好

Dunn指数(Dunn index)
在这里插入图片描述
Dunn指数越大越好

4.4 K均值算法

原型聚类

聚类中的某个簇可以使用一个原型进行描述(就好像由一群金毛犬,其中或多或少都会混有其他犬种的基因,其中我们选出金毛特征最为明显的那只作为原型)

K-Means的损失函数

不正确的越多,损失越大。
给定数据集,聚类所得的簇划分,则最小化平方误差
在这里插入图片描述

如何损失最小化

(1) 损失函数没有解析解(明确写成公式的解),即无法通过令导数=0来求解,此公式无法写出解的公式来求最小值。
(2) 使用贪婪策略来迭代的求解,详见基本流程。

K-Means的基本流程

输入
数据集D={x1, x2, …, x,m}
聚类簇数k
迭代过程(第一阶段)
在这里插入图片描述
迭代过程(第二阶段)
在这里插入图片描述
更新簇的均值向量之后,返回第一阶段进行迭代。
循环结束条件:当前所有簇的均值向量趋于稳定。

K-Means的注意点

(1)最后的聚类结果高度依赖于初始均值向量的选择。
(2)比较适合连续属性的特征特征向量聚类,不太适合离散向量。
针对上面两个问题,一般解决办法如下:
1)初始均值向量的选择
(1) 简单的选取k个样本
(2) 计算所有数据的均值,将一些小的随机向量加到均值上,得到初始的k个均值向量。
2)离散属性的处理
(1)K-Modes算法:处理离散属性的聚类方法
(2)K-Prototype算法:处理混合属性(连续属性和离散数学混合)的方法

4.5 编程实现

from math import sqrt
from random import randint

class Cluster(object):
    def __init__(self):
        self._fcs=[]#簇的所有特征向量
        self._center=None#簇的中心点
    
    def set_center(self,new_center):
        """
        初始化簇的中心点
        params:
            new_center->
        returns:
        
        """
        self._center=new_center
        
    def get_center(self):
        return self._center
    
    def add_fc(self,fc):
        """
        簇中添加特征向量
        """
        self._fcs.qppend(fc)
        
    def update_center(self):
        """
        更新中心点
        """
        feature_num = len(self._fcs[0])#特征向量中特征的数量
        fc_num = len(self._fcs)#特征向量的数量
        for i in range(feature_num):
            #开始计算当前特征所在特征向量上的总和
            current_sum = 0
            for fc in self._fcs:
                current_sum += fc[i]
            #将中心点对应的特征向量的值更新为均值(总和/特征向量个数)
            self._center[i] = current_sum/fc_num
            
    def distance(self,fc):
        """
        计算中心点和特征向量之间的距离
        """
        length = len(fc)
        distance =0
        for i in range(length):
            distance += (self._center[i]-fc[i])**2
        return sqrt(distance)
    
class KMeans(object):
    def __init__(self,k):
        self._k = k
        self._clusters = [cluster() for i in range(self._k)]
    
    def _select_k_indexes(self,total_num):
        """
        选择k个所有,选出来的所有用于从数据集中随机挑选k个簇的中心点
        """
        k_indexes = []
        while len(k_indexes)<self._k:
            index = randint(0,total_num-1)#生成一个随机的索引
            #如果当前的索引不在索引list中,把它加到k_indexes中
            if index not in k_indexes:
                k_indexes.append(index)
                #循环结束的条件为k_indexes中已经有了k个随机且不重复的索引
        return k_indexes
    
    def _init_clusters(self,dataset):
        """
        初始化K个簇的中心点
        """
        k_indexes = self._select_k_indexes(self._k,len(dataset))
        for i in range(self._k):
            self._clusters[i].set_center(dataset[k_indexes[i]])
            
    def train(self,dataset,iter_times):
        """
        """
        self._init_clusters(dataset)#初始化k个簇
        fc_num = len(dataset)#特征向量的个数
        #进行iter_times次迭代
        for i in range(iter_times):
            for j in range(fc_num):#开始循环数据集中的数据
                current_fc = dataset[j]#当前特征向量
                #记当前特征向量的归属cluster的索引为0,最小距离为和第一个簇的距离
                cluster_index = 0
                min_dist = self._clusters[0].distance(current_fc)
                #计算当前特征向量和所有簇的距离
                for k in range(1,self._k):
                    current_dist = self._clusters[0].distance(current_fc)
                    #这里使用了打擂台算法,求得最小距离,节省了求出所有距离之和进行排序的过程
                    if current_dist<min_dist:
                        cluster_index = k
                        min_dist = current_dist
                #所有k个距离计算完之后把当前的特征向量加入到指定的簇中
                self._clusters[cluster_index].add_dc(current_fc)
            #数据集中所有数据都迭代之后开始更新每个簇的中心点
            for cluster in self._clusters:
                cluster.update_center()
    def get_cluster(self):
        return self._clusters
                    
            

4.6 实际应用(图像压缩)

背景分析

(1) 图像有三个颜色通道R,G,B
(2) 每个通道的值都在0-255之间(28,所以一个通道8位,1比特的数据)
(3) 减少颜色总数(16种颜色,24,0.5比特)

使用K-Means

(1)K-Means生成k个颜色簇
(2)图片种在一个颜色簇中的像素都使用该簇的中心点表示
(3)K值越小图片越失真,图片体积越小,训练实际越短

效果展示
#通过K均值聚类进行图像压缩
from cv2 import imread, imwrite
from skimage import io
from sklearn.cluster import KMeans
import numpy as np

def compress_image():
    image = imread('12christma-png-10.png')
    
    rows = image.shape[0]
    cols = image.shape[1]
    
    image = image.reshape(image.shape[0]*image.shape[1],3)
    kmeans = KMeans(n_clusters=2,n_init=10,max_iter=200)
    kmeans.fit(image)
    
    clusters = np.asarray(kmeans.cluster_centers_,dtype=np.uint8)
    labels = np.asarray(kmeans.labels_,dtype=np.uint8)
    labels = labels.reshape(rows,cols)
    
    np.save('codebook_img.npy',clusters)
    imwrite('compressed_img.png',labels)
    
def reconstruct_image():
    centers = np.load('codebook_img.npy')
    
    c_image = io.imread('compressed_img.png')
    
    image = np.zeros((c_image.shape[0],c_image.shape[1],3),dtype=np.uint8)
    for i in range(c_image.shape[0]):
        for j in range(c_image.shape[1]):
            image[i,j,:] = centers[c_image[i,j],:]
    imwrite('reconstructed_img.png',image)
    
compress_image()
reconstruct_image()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值