机器学习本科课程 实验6 聚类实验

news/2024/5/20 8:46:47 标签: 机器学习, 聚类, 人工智能

第一题:使用sklearn的DBSCAN和AgglomerativeClustering完成聚类

实验内容:

  1. 使用sklearn的DBSCAN和AgglomerativeClustering在两个数据集上完成聚类任务
  2. 聚类结果可视化
  3. 对比外部指标FMI和NMI

1. 导入模块

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

import warnings
warnings.filterwarnings('ignore')

2. 生成数据集

from sklearn import datasets
X1, y1 = datasets.make_circles(n_samples = 1500, factor = 0.5, noise = 0.05, random_state = 32)
X2, y2 = datasets.make_moons(n_samples = 1500, noise = 0.05, random_state = 32)
colors = np.array(['#377eb8', '#ff7f00', '#4daf4a', '#f781bf', '#a65628', '#984ea3', '#999999', '#e41a1c', '#dede00'])
plt.title('dataset1')
plt.scatter(X1[:, 0], X1[:, 1], s = 10, c = colors[y1])
plt.title('dataset2')
plt.scatter(X2[:, 0], X2[:, 1], s = 10, c = colors[y2])

3. 导入模型

我们导入密度聚类和层次聚类两个模型

from sklearn.cluster import DBSCAN, AgglomerativeClustering

4. 训练模型

dbscan = DBSCAN(eps = 0.1)
dbscan.fit(X1)

密度聚类模型使用模型的labels_属性就可以获得聚类后的类标记

dbscan.labels_

层次聚类linkage参数表示我们要用哪种距离(最小、最大、平均)进行聚类。这里我们选择single,表示最小距离。complete表示最大距离,average表示平均距离。

注意:single参数是在sklearn 0.20版本才加入的!

agg = AgglomerativeClustering(n_clusters = 2, linkage="single")
agg.fit(X1)

5. 聚类结果可视化

plt.figure(figsize = (8, 4))
plt.subplot(121)
plt.title('DBSCAN dataset1')
plt.scatter(X1[:, 0], X1[:, 1], s = 10, c = colors[dbscan.labels_])

plt.subplot(122)
plt.title('AGG dataset1')
plt.scatter(X1[:, 0], X1[:, 1], s = 10, c = colors[agg.labels_])

6. 指标计算

我们这里选用两个外部指标,FMI和NMI。

互信息(mutual information)表示了两个分布的一致程度。归一化的互信息(NMI)将互信息值映射到0到1的空间内。值越高,说明两个分布的一致性越高。

FMI是Fowlkes-Mallows index,使用precision和recall计算得到,其值域也是0到1,越大说明聚类效果越和参考模型相近。

from sklearn.metrics import normalized_mutual_info_score
from sklearn.metrics import fowlkes_mallows_score
normalized_mutual_info_score(y1, dbscan.labels_)
normalized_mutual_info_score(y1, agg.labels_)
fowlkes_mallows_score(y1, dbscan.labels_)
fowlkes_mallows_score(y1, agg.labels_)

Test

请你使用密度聚类和高斯混合模型在数据集X2上进行聚类,绘制聚类后的效果。计算FMI和NMI值,填入下标

双击此处填写

()

算法FMINMI
密度聚类0.99870.9934
高斯混合模型0.74750.3952
from sklearn.mixture import GaussianMixture
# 密度聚类 (DBSCAN)
dbscan = DBSCAN(eps=0.1) 
dbscan_labels = dbscan.fit_predict(X2)

# 高斯混合模型 (Gaussian Mixture Model)
gmm = GaussianMixture(n_components=2, random_state=32)
gmm_labels = gmm.fit_predict(X2)

# 绘制密度聚类效果
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.scatter(X2[:, 0], X2[:, 1], c=colors[dbscan_labels], cmap='viridis', s=50)
plt.title('DBSCAN Clustering')

# 绘制高斯混合模型效果
plt.subplot(1, 2, 2)
plt.scatter(X2[:, 0], X2[:, 1], c=colors[gmm_labels], cmap='viridis', s=50)
plt.title('Gaussian Mixture Model Clustering')

plt.show()

# 计算 FMI 和 NMI 值
fmi_dbscan = fowlkes_mallows_score(y2, dbscan_labels)
nmi_dbscan = normalized_mutual_info_score(y2, dbscan_labels)

fmi_gmm = fowlkes_mallows_score(y2, gmm_labels)
nmi_gmm = normalized_mutual_info_score(y2, gmm_labels)

print(f"密度聚类 - Fowlkes Mallows Index: {fmi_dbscan:.4f}")
print(f"密度聚类 - Normalized Mutual Info: {nmi_dbscan:.4f}")
print()
print(f"高斯混合模型 - Fowlkes Mallows Index: {fmi_gmm:.4f}")
print(f"高斯混合模型 - Normalized Mutual Info: {nmi_gmm:.4f}")

第二题:实现K-means

实验内容:

  1. 实现一个K-means聚类算法
  2. 计算外部指标FMI和NMI
  3. 聚类结果可视化
  4. 完成第二个数据集上myKmeans与层次聚类(single)算法的对比
我们要实现一个K-means算法,也称为原型聚类算法。

## 初始化

K-means在实现的时候,首先需要选取类簇中心。类簇中心的选取方法有很多,我们这里使用最简单的方法,随机选取。也就是,从给定的待聚类的样本中,随机选取 $K$ 个样本,作为 $K$ 个类簇的中心。

## 优化

选取类中心后,就需要不断的调成类中心的位置,开始优化过程,优化主要分为两步:

### 第一步

计算所有样本到 $K$ 个类中心的距离。每个样本,选择距自己最近的类中心作为自己属于的类簇。(这里的距离我们选择欧式距离)

### 第二步

针对第一步分出来的 $K$ 个类簇,计算每个类簇内样本的均值,将计算得到的 $K$ 个均值向量,作为这 $K$ 个类簇新的中心。

### 然后循环第一步和第二步,直至一定的迭代次数,或类中心无显著的位置改变为止。

1. 导入模块

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

import warnings
warnings.filterwarnings('ignore')

2. 生成数据集

from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples = 1500, random_state = 170)

这里的X和y分别代表样本和对应的真实标记。

使用plt.scatter绘制散点图,参数c是一个np.ndarray,表示类别,相同的值会有相同的颜色。

plt.scatter(X[:, 0], X[:, 1], c = y)

3. 欧式距离的实现

给定向量 x ∈ R m x \in \mathbb{R}^m xRm y ∈ R m y \in \mathbb{R}^m yRm,两个向量的欧式距离定义为:

E ( x , y ) = ∑ i = 1 m ( x i − y i ) 2 E(x, y) = \sqrt{\sum^m_{i = 1} (x_i - y_i)^2} E(x,y)=i=1m(xiyi)2

其中, i i i 表示向量的第 i i i 个分量。

我们要实现一个可以计算多个样本组成的矩阵 X X X,与某一个类中心 y y y 之间欧氏距离的函数。

给定输入矩阵 X ∈ R n × m X \in \mathbb{R}^{n \times m} XRn×m,其中 n n n 是样本数, m m m 是特征数,给定输入的类簇中心 y ∈ R m y \in \mathbb{R}^m yRm

我们要计算 n n n 个样本到某一类簇中心 y y y 的欧式距离,最后的结果是 E ∈ R n E \in \mathbb{R}^{n} ERn,每个元素表示矩阵 X X X 中的每个样本到类中心 y y y 的欧式距离。

def compute_distance(X, y):
    '''
    计算样本矩阵X与类中心y之间的欧氏距离
    
    Parameters
    ----------
    X, np.ndarray, 样本矩阵 X, 维度:(n, m)
    
    y, np.ndarray, 类中心 y,维度:(m, )
    
    Returns
    ----------
    distance, np.ndarray, 样本矩阵 X 每个样本到类中心 y 之间的欧式距离,维度:(n, )
    '''
    
    # YOUR CODE HERE
    y= np.tile(y, (X.shape[0], 1))
    distance = np.sum(((X-y)**2),axis=1)**0.5
    return distance
# 测试样例
print(compute_distance(np.array([[0, 0], [0, 1]]), np.array([0, 1]))) # [ 1.  0.]
print(compute_distance(np.array([[0, 0], [0, 1]]), np.array([1, 1]))) # [ 1.41421356  1.        ]

下面开始实现K-means聚类算法

class myKmeans:
    def __init__(self, n_clusters, max_iter = 100):
        '''
        初始化,三个成员变量
        
        Parameters
        ----------
        n_clusters: int, 类簇的个数
        
        max_iter, int, default 100, 最大迭代轮数,默认为100
        
        '''
        # 表示类簇的个数
        self.n_clusters = n_clusters
        
        # 表示最大迭代次数
        self.max_iter = int(max_iter)
        
        # 类簇中心
        self.centroids = None
    
    def choose_centroid(self, X):
        '''
        选取类簇中心
        
        Parameters
        ----------
        X: np.ndarray, 样本矩阵X,维度:(n, m)
        
        Returns
        ----------
        centroids: np.ndarray, 维度:(n_clusters, m)
        
        '''
        centroids = X[np.random.choice(np.arange(len(X)), self.n_clusters, replace = False), :]
        return centroids
    
    def compute_label(self, X):
        '''
        给定样本矩阵X,结合类中心矩阵self.centroids,计算样本矩阵X内每个样本属于哪个类簇
        
        Parameters
        ----------
        X: np.ndarray, 样本矩阵X,维度:(n, m)
        
        Returns
        ----------
        labels: np.ndarray, 维度:(n, )
        
        '''
        # 将每个样本到每个类簇中心的距离存储在distances中,每行表示当前样本对于不同的类中心的距离
        distances = np.empty((len(X), self.n_clusters))
        
        # 遍历类中心,对每个类中心,计算所有的样本到这个类中心的距离
        for index in range(len(self.centroids)):
            
            # 计算样本矩阵X所有样本到当前类中心的距离,存储在distances中的第index列中
            # YOUR CODE HERE
            distances[:, index] = compute_distance(X, self.centroids[index])
            
        # 取distances每行最小值的下标,这个下标就是这个样本属于的类簇的标记
        # YOUR CODE HERE
        labels = np.argmin(distances, axis=1)
        
        # 返回每个样本属于的类簇的标记
        return labels
    
    def fit(self, X):
        '''
        聚类,包含类中心初始化,类中心优化两个部分
        
        Parameters
        ----------
        X: np.ndarray, 样本矩阵X,维度:(n, m)
        
        '''
        # 类中心随机初始化
        self.centroids = self.choose_centroid(X)
        
        # 优化self.max_iter轮
        for epoch in range(self.max_iter):
            
            # 计算当前所有样本的属于哪个类簇
            labels = self.compute_label(X)
            
            # 重新计算每个类簇的类中心
            for index in range(self.n_clusters):
                
                # 重新计算第 index 个类中心,对属于这个类簇的样本取均值
                # YOUR CODE HERE
                self.centroids[index, :] = X[labels == index].sum(axis=0) / X[labels == index].shape[0]

4. 聚类

# 初始化一个3类簇的模型
model = myKmeans(3)

# 对X进行聚类,计算类中心
model.fit(X)

# 计算X的类标记
prediction = model.compute_label(X)

5. 聚类结果可视化

# 使用我们的预测结果上色
plt.scatter(X[:, 0], X[:, 1], c = prediction)

6. 评价指标

这里,我们选用两个外部指标,FMI和NMI。

from sklearn.metrics import normalized_mutual_info_score
from sklearn.metrics import fowlkes_mallows_score
print(normalized_mutual_info_score(y, prediction))
print(fowlkes_mallows_score(y, prediction))

Test

使用下面提供的数据,完成以下实验:

  1. 使用myKmeans和层次聚类算法(AgglomerativeClustering)对该数据进行聚类
  2. 计算出两个模型的FMI和NMI值,并对聚类结果可视化。
  3. 分析为什么两个模型的聚类效果会出现如此的不同。

要求:

  1. 层次聚类的连接方式选择’single’,即使用两个类簇之间的最小距离
  2. 类簇个数设定为2

完成下表的填写:

双击此处填写
算法FMINMI
myKmeans0.49960.0003
AgglomerativeClustering1.00001.0000
from sklearn.datasets import make_circles
X, y = make_circles(n_samples = 1500, factor = .5, noise = .05, random_state = 32)
plt.scatter(X[:, 0], X[:, 1], c = y)
# 初始化一个2类簇的模型
model_test = myKmeans(2)

# 对X进行聚类,计算类中心
model_test.fit(X)

# 计算X的类标记
prediction = model_test.compute_label(X)
plt.figure(figsize=(12, 4))

plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='viridis', s=40)
plt.title("True Clusters")

plt.subplot(1, 2, 2)
plt.scatter(X[:, 0], X[:, 1], c=prediction, cmap='viridis', s=40)
plt.title("Agglomerative Clustering")

plt.show()

# 计算评估指标
fmi1 = fowlkes_mallows_score(y, prediction)
nmi1 = normalized_mutual_info_score(y, prediction)
print(f"K-means - Fowlkes Mallows Index: {fmi1:.4f}")
print(f"K-means - Normalized Mutual Info: {nmi1:.4f}")
# YOUR CODE HERE
agg2 = AgglomerativeClustering(n_clusters=2, linkage='single')
labels2 = agg2.fit_predict(X)
plt.figure(figsize=(12, 4))

plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='viridis', s=40)
plt.title("True Clusters")

plt.subplot(1, 2, 2)
plt.scatter(X[:, 0], X[:, 1], c=labels2, cmap='viridis', s=40)
plt.title("Agglomerative Clustering")

plt.show()

# 计算评估指标
fmi2 = fowlkes_mallows_score(y, labels2)
nmi2 = normalized_mutual_info_score(y, labels2)
print(f"层次聚类 - Fowlkes Mallows Index: {nmi2:.4f}")
print(f"层次聚类 - Normalized Mutual Info: {nmi2:.4f}")

http://www.niftyadmin.cn/n/5364641.html

相关文章

重写Sylar基于协程的服务器(7、TcpServer HttpServer的设计与实现)

重写Sylar基于协程的服务器(7、TcpServer & HttpServer的设计与实现) 重写Sylar基于协程的服务器系列: 重写Sylar基于协程的服务器(0、搭建开发环境以及项目框架 || 下载编译简化版Sylar) 重写Sylar基于协程的服务…

Vue3动态CSS

Vue3动态CSS 动态css值动态css对象module模式 动态css值 <template><div class"div">动态css</div> </template><script setup langts> import {ref} from vueconst style ref(blue) </script><style scoped> .div{colo…

day19 初始HTML

什么是HTML HTML&#xff08;Hyper Text Markup Language&#xff09;超文本标记语言 超文本包括&#xff1a;文字、图片、音频、视频、动画等 HTML5&#xff0c;提供了一些新的元素和一些有趣的新特性&#xff0c;同时也建立了一些新的规则。这些元素、特性和规则的建立&…

MySQL-进阶-MySQL管理

一、系统数据库 二、常用工具 1、MySQL 2、mysqladmin 3、mysqlbinlog 4、mysqlshow 5、mysqldump 6、mysqlimport/source

【axios报错异常】: Uncaught ReferenceError: axios is not defined

问题描述: 当前代码在vivo手机和小米手机运行是正常的,点击分享按钮调出相关弹框,发送接口进行分享,但是现在oppo手机出现了问题: 点击分享按钮没有反应. 问题解析: 安卓同事经过查询后,发现打印了错误: 但是不清楚这个问题是安卓端造成的还是前端造成的,大家都不清楚. 问题…

Spark 依赖包加载方式

1 Spark 依赖包来源 我们知道Spark application运行加载依赖有三个地方&#xff1a; systemClasspath&#xff1a;Spark安装时候提供的依赖包&#xff0c;${SPARK_HOME}/jars下的包。spark-submit --jars 提交的依赖包spark-submit --config "spark.{driver/executor}.e…

Vue中跨域问题的解决

目录 1 跨域的概念 2 解决办法 2.1 修改请求实例的公共前缀 2.2 修改vite.config.js文件 1 跨域的概念 由于浏览器的同源策略限制&#xff0c;向不同源(不同协议、不同域名、不同端口)发送ajax请求会失败 2 解决办法 原理&#xff1a;使得浏览器向两个端口发送请求和接手…

微服务入门篇:Nacos注册中心(Nacos安装,快速入门,多级存储,负载均衡,环境隔离,配置管理,热更新,集群搭建,nginx反向代理)

目录 1.Nacos安装1.官网下载2.解压到本地3.启动nacos 2.Nacos快速入门1.在父工程中导入nacos依赖2.给子项目添加客户端依赖3.修改对应服务的配置文件4.启动服务&#xff0c;查看nacos发现情况 3.Nacos服务多级存储模型4.NacosRule负载均衡5. 服务实例的权重设置6.环境隔离&…