模式识别(1)协方差矩阵相关和K-means聚类算法实现(含源码)

模式识别实验一

实验一、协方差矩阵和矩阵特征值、特征向量的计算

题目简介:给定一组数据,实现该组数据的协方差矩阵的计算。并用代码实现计算一个方阵的特征值和特征向量。

一、协方差部分

1.协方差的定义

协方差在概率论和统计学中用于衡量两个变量的总体误差。而方差是协方差的一种特殊情况,即当两个变量是相同的情况。 协方差表示的是两个变量的总体的误差,这与只表示一个变量误差的方差不同。
协方差计算公式的定义:
由一组数据 X = ( X 1 , X 2 , … , X n ) T \mathbf{X}=\left(X_{1}, X_{2}, \ldots, X_{n}\right)^{T} X=(X1,X2,,Xn)T,其中该数据表示X中有n个变量。其中每两个变量之间就可以计算一次协方差。任意两个向量之间的协方差计算公式
cov ⁡ [ X i , X j ] = E [ ( X i − E [ X i ] ) ( X j − E [ X j ] ) ] \operatorname{cov}\left[X_{i}, X_{j}\right]=E\left[\left(X_{i}-E\left[X_{i}\right]\right)\left(X_{j}-E\left[X_{j}\right]\right)\right] cov[Xi,Xj]=E[(XiE[Xi])(XjE[Xj])]

2.协方差矩阵

协方差矩阵是指在X这个数据集当中,任意两个变量之间就可以计算一次协方差,X共有n维数据,所以就可以计算出nn个协方差数据,因为每一维度的数据都可以和自身进行一次协方差的计算。所以共有nn个数据。将这些协方差数据用矩阵的形式表示就是协方差矩阵
cov ⁡ [ X , X ] = [ cov ⁡ [ X 1 , X 1 ] cov ⁡ [ X 1 , X 2 ] ⋯ cov ⁡ [ X 1 , X n ] cov ⁡ [ X 2 , X 1 ] cov ⁡ [ X 2 , X 2 ] ⋯ cov ⁡ [ X 2 , X n ] ⋮ ⋮ ⋱ ⋮ cov ⁡ [ X n , X 1 ] cov ⁡ [ X n , X 2 ] ⋯ cov ⁡ [ X n , X n ] ] \operatorname{cov}[\mathbf{X}, \mathbf{X}]=\left[\begin{array}{cccc} \operatorname{cov}\left[X_{1}, X_{1}\right] & \operatorname{cov}\left[X_{1}, X_{2}\right] & \cdots & \operatorname{cov}\left[X_{1}, X_{n}\right] \\ \operatorname{cov}\left[X_{2}, X_{1}\right] & \operatorname{cov}\left[X_{2}, X_{2}\right] & \cdots & \operatorname{cov}\left[X_{2}, X_{n}\right] \\ \vdots & \vdots & \ddots & \vdots \\ \operatorname{cov}\left[X_{n}, X_{1}\right] & \operatorname{cov}\left[X_{n}, X_{2}\right] & \cdots & \operatorname{cov}\left[X_{n}, X_{n}\right] \end{array}\right] cov[X,X]=cov[X1,X1]cov[X2,X1]cov[Xn,X1]cov[X1,X2]cov[X2,X2]cov[Xn,X2]cov[X1,Xn]cov[X2,Xn]cov[Xn,Xn]

3.个人理解
  • 协方差表示两个随机变量之间的线性相关性
  • 协方差矩阵中的每个元素代表了两个随机变量之间的协方差
  • 协方差矩阵表示一组随机变量之间的两两线性相关性
4.特征值和特征向量
4.代码实现

4.1 包的导入
这里导入numpy和random包,用来处理数据和随机数的生成

import numpy as np
import random

4.2 类的封装和函数实现
将所有要实现的功能函数进行封装,封装在一个work类下面。
函数介绍:

  1. 函数cov用来计算两向量之间的协方差
  2. 函数ccovmat(self)用来计算样本的协方差矩阵
  3. 函数feature(self)用来计算矩阵样本的特征值和特征向量
class work(object):
    def __init__(self, samples):
        self.samples = samples
        self.covmat1 = []
        self.ccovmat()
    def cov(self, X, Y):
        n = np.shape(X)[0] #特诊个数
        X, Y = np.array(X), np.array(Y)
        meanX, meanY = np.mean(X), np.mean(Y)
        cov = sum(np.multiply(X - meanX, Y - meanY)) / (n - 1)
        return cov
    def ccovmat(self):
        S = self.samples  # 样本集
        na = np.shape(S)[1]  # 特征attr总数
        self.covmat1 = np.full((na, na), fill_value=0.)
        for i in range(na):
            for j in range(na):
                self.covmat1[i, j] = self.cov(S[:, i], S[:, j])
        return self.covmat1
    def feature(self):
        b,c = np.linalg.eig(samples)
        return b,c

4.3 数据集生成和函数调用
这里调用random模块生成随机数,生成一个4*4的方阵。数据集的维度可以选择,因为要计算特征值需要固定类型为方阵。计算协方差并不需要为方阵,这里为了方便使用同一个数据集,原理是一样的。

if __name__ == '__main__':
    image= [[random.randint(1, 20) for j in range(1, 5)] for i in range(1, 5)]
    samples = np.array(image)
    print(image)
    print('数据集\n', samples)
    wk = work(samples)
    b,c = wk.feature()
    print("矩阵特征值为: {}".format(b))
    print("矩阵特征向量为: \n{}".format(c))
    print('协方差矩阵:\n', wk.ccovmat())
5. 运行结果

在这里插入图片描述

实验二、K-means聚类算法实现

K-means算法是机器学习中常见的无监督学习算法,K-means算法是最常用的一种聚类算法。算法的输入为一个样本集(或者称为点集),通过该算法可以将样本进行聚类,具有相似特征的样本聚为一类。
针对每个点,计算这个点距离所有中心点最近的那个中心点,然后将这个点归为这个中心点代表的簇。一次迭代结束之后,针对每个簇类,重新计算中心点,然后针对每个点,重新寻找距离自己最近的中心点。如此循环,直到前后两次迭代的簇类没有变化。
本次实验将实现K-means聚类算法,基于python语言实现。

2.1 算法理论部分

step1、K值的选择

k 的选择一般是按照实际需求进行决定,或在实现算法时直接给定 k 值。
说明:

  • A.质心数量由用户给出,记为k,k-means最终得到的簇数量也是k
  • B.后来每次更新的质心的个数都和初始k值相等
  • C.k-means最后聚类的簇个数和用户指定的质心个数相等,一个质心对应一个簇,每个样本只聚类到一个簇里面
  • D.初始簇为空
step2、距离度量

将对象点分到距离聚类中心最近的那个簇中需要最近邻的度量策略,在欧式空间中采用的是欧式距离,在处理文档中采用的是余弦相似度函数,有时候也采用曼哈顿距离作为度量,不同的情况实用的度量公式是不同的。这里使用欧氏空间的距离

step3、新质心的计算

对于分类后的产生的k个簇,分别计算到簇内其他点距离均值最小的点作为质心(对于拥有坐标的簇可以计算每个簇坐标的均值作为质心)

step4、是否停止K-means

质心不再改变,或给定loop最大次数loopLimit
说明:

  • A当每个簇的质心,不再改变时就可以停止k-menas
  • B.当loop次数超过looLimit时,停止k-means
  • C.只需要满足两者的其中一个条件,就可以停止k-means
  • C.如果Step4没有结束k-means,就再执行step2-step3-step4
  • D.如果Step4结束了k-means,则就打印(或绘制)簇以及质心

2.2 代码实现

由于sklearn中内置了K均值聚类算法的函数和模块,这里将使用两种方法实现本次实验。方法一为聚类原理自己理解并实现,方案二为调用现有模块和API

方案一代码

这部分代码基于原理实现K均值聚类算法,计算距离,寻找新的质心……

import random
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 计算欧拉距离
def calcDis(dataSet, centroids, k):
    clalist=[]
    for data in dataSet:
        diff = np.tile(data, (k, 1)) - centroids  
        squaredDiff = diff ** 2     #平方
        squaredDist = np.sum(squaredDiff, axis=1)   #和  (axis=1表示行)
        distance = squaredDist ** 0.5  #开根号
        clalist.append(distance) 
    clalist = np.array(clalist)  #返回一个每个点到质点的距离len(dateSet)*k的数组
    return clalist
# 计算质心
def classify(dataSet, centroids, k):
    # 计算样本到质心的距离
    clalist = calcDis(dataSet, centroids, k)
    # 分组并计算新的质心
    minDistIndices = np.argmin(clalist, axis=1)    #axis=1 表示求出每行的最小值的下标
    newCentroids = pd.DataFrame(dataSet).groupby(minDistIndices).mean() #DataFramte(dataSet)对DataSet分组,groupby(min)按照min进行统计分类,mean()对分类结果求均值
    newCentroids = newCentroids.values
    # 计算变化量
    changed = newCentroids - centroids
 
    return changed, newCentroids
# 使用k-means分类
def kmeans(dataSet, k):
    centroids = random.sample(dataSet, k)
    changed, newCentroids = classify(dataSet, centroids, k)
    while np.any(changed != 0):
        changed, newCentroids = classify(dataSet, newCentroids, k)
    centroids = sorted(newCentroids.tolist())   #tolist()将矩阵转换成列表 sorted()排序
    # 根据质心计算每个集群
    cluster = []
    clalist = calcDis(dataSet, centroids, k) #调用欧拉距离
    minDistIndices = np.argmin(clalist, axis=1)  
    for i in range(k):
        cluster.append([])
    for i, j in enumerate(minDistIndices):   #enymerate()可同时遍历索引和遍历元素
        cluster[j].append(dataSet[i])
    return centroids, cluster

#函数主体部分
if __name__ == '__main__':
    dataset = [[1,1],[1.2,1.2],[1,1.6],[1,2],[2,2],[2,1],[6.5,6],[7.7,7],[6,7],[7,6],[6.6,7],[7,6.6],[7,6.5],[7.2,6.9]]
    centroids, cluster = kmeans(dataset, 2)
    print('质心为:%s' % centroids)
    print('集群为:%s' % cluster)
    for j in range(len(centroids)):#用来画出最后的质心位置,用X表示
        plt.scatter(centroids[j][0], centroids[j][1], marker='x', color='red', s=50, label='质心')
    #用两种不同颜色的点来表示最后分成的两簇点
    for i in range(len(cluster[0])):
        plt.scatter(cluster[0][i][0], cluster[0][i][1], marker='o', color='green', s=40,label='原始点')
    for i in range(len(cluster[1])):
        plt.scatter(cluster[1][i][0], cluster[1][i][1], marker='o', color='blue', s=40,label='原始点')
    plt.show()

运行结果
在这里插入图片描述

方案二代码

方案二主要是基于机器学习库当中内置的函数来实现K-means聚类算法。具体调用代码如下:

import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import load_iris
iris = load_iris()
X=np.array([[1,1],[1.2,1.2],[1,1.6],[1,2],[2,2],[2,1],[6.5,6],[7.7,7],[6,7],[7,6],[6.6,7],[7,6.6],[7,6.5],[7.2,6.9]])
plt.scatter(X[:, 0], X[:, 1], c = "red", marker='o', label='see')
plt.xlabel('petal length')
plt.ylabel('petal width')
plt.legend(loc=2)
plt.show()

estimator = KMeans(n_clusters=2)#构造聚类器
estimator.fit(X)#聚类
label_pred = estimator.labels_ #获取聚类标签
x0 = X[label_pred == 0]
x1 = X[label_pred == 1]
plt.scatter(x0[:, 0], x0[:, 1], c = "red", marker='o', label='label0')
plt.scatter(x1[:, 0], x1[:, 1], c = "green", marker='*', label='label1')
plt.xlabel('petal length')
plt.ylabel('petal width')
plt.legend(loc=2)
plt.show()

运行结果

  1. 原始点的图像:
    在这里插入图片描述
  2. 聚类后点的图像
    在这里插入图片描述
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值