【机器学习】聚类代码练习

article/2025/10/1 13:54:09

本课程是中国大学慕课《机器学习》的“聚类”章节的课后代码。

课程地址:

https://www.icourse163.org/course/WZU-1464096179

课程完整代码:

https://github.com/fengdu78/WZU-machine-learning-course

代码修改并注释:黄海广,haiguang2000@wzu.edu.cn

在本练习中,我们将实现K-means聚类,并使用它来压缩图像。我们将从一个简单的2D数据集开始,以了解K-means是如何工作的,然后我们将其应用于图像压缩。我们还将对主成分分析进行实验,并了解如何使用它来找到面部图像的低维表示。

K-means 聚类

我们将实施和应用K-means到一个简单的二维数据集,以获得一些直观的工作原理。K-means是一个迭代的,无监督的聚类算法,将类似的实例组合成簇。该算法通过猜测每个簇的初始聚类中心开始,然后重复将实例分配给最近的簇,并重新计算该簇的聚类中心。我们要实现的第一部分是找到数据中每个实例最接近的聚类中心的函数。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
from scipy.io import loadmat
def find_closest_centroids(X, centroids):m = X.shape[0]k = centroids.shape[0]idx = np.zeros(m)for i in range(m):min_dist = 1000000for j in range(k):dist = np.sum((X[i, :] - centroids[j, :])**2)if dist < min_dist:min_dist = distidx[i] = jreturn idx

让我们来测试这个函数,以确保它的工作正常。我们将使用练习中提供的测试用例。

data2 = pd.read_csv('data/ex7data2.csv')
data2.head()

X1X2
01.8420804.607572
15.6585834.799964
26.3525793.290854
32.9040174.612204
43.2319794.939894
X=data2.values
initial_centroids = initial_centroids = np.array([[3, 3], [6, 2], [8, 5]])idx = find_closest_centroids(X, initial_centroids)
idx[0:3]
array([0., 2., 1.])

输出与文本中的预期值匹配(记住我们的数组是从零开始索引的,而不是从一开始索引的,所以值比练习中的值低一个)。接下来,我们需要一个函数来计算簇的聚类中心。聚类中心只是当前分配给簇的所有样本的平均值。

sb.set(context="notebook", style="white")
sb.lmplot(x='X1', y='X2', data=data2, fit_reg=False)
plt.show()
043b84d782530955f6c738d95d9679aa.png
def compute_centroids(X, idx, k):m, n = X.shapecentroids = np.zeros((k, n))for i in range(k):indices = np.where(idx == i)centroids[i, :] = (np.sum(X[indices, :], axis=1) /len(indices[0])).ravel()return centroids
compute_centroids(data2.values, idx, 3)
array([[2.42830111, 3.15792418],[5.81350331, 2.63365645],[7.11938687, 3.6166844 ]])

此输出也符合练习中的预期值。下一部分涉及实际运行该算法的一些迭代次数和可视化结果。这个步骤是由于并不复杂,我将从头开始构建它。为了运行算法,我们只需要在将样本分配给最近的簇并重新计算簇的聚类中心。

def run_k_means(X, initial_centroids, max_iters):m, n = X.shapek = initial_centroids.shape[0]idx = np.zeros(m)centroids = initial_centroidsfor i in range(max_iters):idx = find_closest_centroids(X, centroids)centroids = compute_centroids(X, idx, k)return idx, centroids
idx, centroids = run_k_means(X, initial_centroids, 10)
cluster1 = X[np.where(idx == 0)[0],:]
cluster2 = X[np.where(idx == 1)[0],:]
cluster3 = X[np.where(idx == 2)[0],:]fig, ax = plt.subplots(figsize=(15,10))
ax.scatter(cluster1[:,0], cluster1[:,1], s=30, color='r', label='Cluster 1')
ax.scatter(cluster2[:,0], cluster2[:,1], s=30, color='g', label='Cluster 2')
ax.scatter(cluster3[:,0], cluster3[:,1], s=30, color='b', label='Cluster 3')
ax.legend()
plt.show()
c5b03fe1fdd2b691e606777c13a79252.png

我们跳过的一个步骤是初始化聚类中心的过程。这可以影响算法的收敛。我们的任务是创建一个选择随机样本并将其用作初始聚类中心的函数。

def init_centroids(X, k):m, n = X.shapecentroids = np.zeros((k, n))idx = np.random.randint(0, m, k)for i in range(k):centroids[i, :] = X[idx[i], :]return centroids
init_centroids(X, 3)
array([[1.52334113, 4.87916159],[3.06192918, 1.5719211 ],[1.75164337, 0.68853536]])

k值的选择

使用“肘部法则”选取k值

from sklearn.cluster import KMeans# '利用SSE选择k'
SSE = []  # 存放每次结果的误差平方和
for k in range(1, 9):estimator = KMeans(n_clusters=k)  # 构造聚类器estimator.fit(data2)SSE.append(estimator.inertia_)
X = range(1, 9)plt.figure(figsize=(15, 10))
plt.xlabel('k')
plt.ylabel('SSE')
plt.plot(X, SSE, 'o-')
plt.show()
a17874d4260bd102b997a1f2e92b2100.png

图中可以看出,k=3的时候是肘点,所以,选择k=3.

K-means图像压缩

我们的下一个任务是将K-means应用于图像压缩。从下面的演示可以看到,我们可以使用聚类来找到最具代表性的少数颜色,并使用聚类分配将原始的24位颜色映射到较低维的颜色空间。

下面是我们要压缩的图像。

from IPython.display import Image
Image(filename='data/bird_small.png')
064db702723ed8104afba9155a6dff5a.png

The raw pixel data has been pre-loaded for us so let's pull it in.

image_data = loadmat('data/bird_small.mat')
# image_data
A = image_data['A']
A.shape
(128, 128, 3)

现在我们需要对数据应用一些预处理,并将其提供给K-means算法。

# normalize value ranges
A = A / 255.# reshape the array
X = np.reshape(A, (A.shape[0] * A.shape[1], A.shape[2]))
X.shape
(16384, 3)
# randomly initialize the centroids
initial_centroids = init_centroids(X, 16)# run the algorithm
idx, centroids = run_k_means(X, initial_centroids, 10)# get the closest centroids one last time
idx = find_closest_centroids(X, centroids)# map each pixel to the centroid value
X_recovered = centroids[idx.astype(int),:]
X_recovered.shape
(16384, 3)
# reshape to the original dimensions
X_recovered = np.reshape(X_recovered, (A.shape[0], A.shape[1], A.shape[2]))
X_recovered.shape
(128, 128, 3)
plt.imshow(X_recovered)
plt.show()
4716d070def8756b69a734ab2cc04305.png

您可以看到我们对图像进行了压缩,但图像的主要特征仍然存在。这就是K-means。下面我们来用scikit-learn来实现K-means。

from skimage import io# cast to float, you need to do this otherwise the color would be weird after clustring
pic = io.imread('data/bird_small.png') / 255.
io.imshow(pic)
plt.show()
213e381d842d8cc0788ff1d9334b0d06.png
pic.shape
(128, 128, 3)
# serialize data
data = pic.reshape(128*128, 3)
data.shape
(16384, 3)
from sklearn.cluster import KMeans#导入kmeans库model = KMeans(n_clusters=16, n_init=100)
model.fit(data)
KMeans(n_clusters=16, n_init=100)
centroids = model.cluster_centers_
print(centroids.shape)C = model.predict(data)
print(C.shape)
(16, 3)
(16384,)
centroids[C].shape
(16384, 3)
compressed_pic = centroids[C].reshape((128,128,3))
fig, ax = plt.subplots(1, 2)
ax[0].imshow(pic)
ax[1].imshow(compressed_pic)
plt.show()
1750445ca1c2bfed9f631977bd396849.png

密度聚类

DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一个比较有代表性的基于密度的聚类算法。与划分和层次聚类方法不同,它将簇定义为密度相连的点的最大集合,能够把具有足够高密度的区域划分为簇,并可在噪声的空间数据库中发现任意形状的聚类。

import numpy as np
from sklearn.cluster import DBSCAN
from sklearn import metrics
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

创建样本数据

centers = [[1, 1], [-1, -1], [1, -1]]
X, labels_true = make_blobs(n_samples=750, centers=centers, cluster_std=0.4, random_state=0
)

标准化数据

X = StandardScaler().fit_transform(X)

在DBSCAN使用两个超参数:

扫描半径 (eps)和最小包含点数(minPts)来获得簇的数量,而不是猜测簇的数目。

  • (1)扫描半径 (eps) : 用于定位点/检查任何点附近密度的距离度量,即扫描半径。

  • (2)最小包含点数(minPts) :聚集在一起的最小点数(阈值),该区域被认为是稠密的。

我们定义一个plot_dbscan(MyEps, MiniSample)函数,MyEps代表epsMiniSample代表minPts

def plot_dbscan(MyEps, MiniSample):db = DBSCAN(eps=MyEps, min_samples=MiniSample).fit(X)core_samples_mask = np.zeros_like(db.labels_, dtype=bool)core_samples_mask[db.core_sample_indices_] = Truelabels = db.labels_# 标签中的簇数,忽略噪声点(如果存在)。n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)n_noise_ = list(labels).count(-1)print("估计的簇的数量: %d" % n_clusters_)print("估计的噪声点数量: %d" % n_noise_)print("同一性(Homogeneity): %0.4f" %metrics.homogeneity_score(labels_true, labels))print("完整性(Completeness): %0.4f" %metrics.completeness_score(labels_true, labels))print("V-measure: %0.3f" % metrics.v_measure_score(labels_true, labels))print("ARI(Adjusted Rand Index): %0.4f" %metrics.adjusted_rand_score(labels_true, labels))print("AMI(Adjusted Mutual Information): %0.4f" %metrics.adjusted_mutual_info_score(labels_true, labels))print("轮廓系数(Silhouette Coefficient): %0.4f" %metrics.silhouette_score(X, labels))# ############################################################################## 画出结果# 黑色点代表噪声点unique_labels = set(labels)colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))]for k, col in zip(unique_labels, colors):if k == -1:# Black used for noise.col = [0, 0, 1, 1]class_member_mask = labels == kxy = X[class_member_mask & core_samples_mask]plt.plot(xy[:, 0],xy[:, 1],"o",markerfacecolor=tuple(col),markeredgecolor="k",markersize=14,)xy = X[class_member_mask & ~core_samples_mask]plt.plot(xy[:, 0],xy[:, 1],"o",markerfacecolor=tuple(col),markeredgecolor="k",markersize=6,)plt.title("簇的数量为: %d" % n_clusters_, fontsize=18)#     plt.savefig(str(MyEps) + str(MiniSample) + '.png')#保存图片plt.show()
plot_dbscan(0.3, 10)
估计的簇的数量: 3
估计的噪声点数量: 18
同一性(Homogeneity): 0.9530
完整性(Completeness): 0.8832
V-measure: 0.917
ARI(Adjusted Rand Index): 0.9517
AMI(Adjusted Mutual Information): 0.9165
轮廓系数(Silhouette Coefficient): 0.6255
157c50a4c1207ffac2277f7f9fcd7c9c.png
plot_dbscan(0.1, 10)
估计的簇的数量: 12
估计的噪声点数量: 516
同一性(Homogeneity): 0.3128
完整性(Completeness): 0.2489
V-measure: 0.277
ARI(Adjusted Rand Index): 0.0237
AMI(Adjusted Mutual Information): 0.2673
轮廓系数(Silhouette Coefficient): -0.3659
e7360b366b3bda1afe5145c38c8c7164.png
plot_dbscan(0.4, 10)
估计的簇的数量: 1
估计的噪声点数量: 2
同一性(Homogeneity): 0.0010
完整性(Completeness): 0.0586
V-measure: 0.002
ARI(Adjusted Rand Index): -0.0000
AMI(Adjusted Mutual Information): -0.0011
轮廓系数(Silhouette Coefficient): 0.0611
6b5c0316c989e907c8e5a9a2d48775b6.png
plot_dbscan(0.3, 6)
估计的簇的数量: 2
估计的噪声点数量: 13
同一性(Homogeneity): 0.5365
完整性(Completeness): 0.8263
V-measure: 0.651
ARI(Adjusted Rand Index): 0.5414
AMI(Adjusted Mutual Information): 0.6495
轮廓系数(Silhouette Coefficient): 0.3845
42ee02bfd5a8e3c57719a1c17b7bae6f.png

可以看到,当扫描半径 (eps)为0.3,同时最小包含点数(minPts)为10的时候,评价指标最高。

层次聚类

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
from scipy.cluster.hierarchy import dendrogram
from sklearn.datasets import load_iris
from sklearn.cluster import AgglomerativeClustering
def plot_dendrogram(model, **kwargs):# 创建链接矩阵,然后绘制树状图# 创建每个节点下的样本计数counts = np.zeros(model.children_.shape[0])n_samples = len(model.labels_)for i, merge in enumerate(model.children_):current_count = 0for child_idx in merge:if child_idx < n_samples:current_count += 1  # leaf nodeelse:current_count += counts[child_idx - n_samples]counts[i] = current_countlinkage_matrix = np.column_stack([model.children_, model.distances_, counts]).astype(float)# 绘制相应的树状图dendrogram(linkage_matrix, **kwargs)
iris = load_iris()
X = iris.data
# 设置距离阈值=0可确保计算完整的树。
model = AgglomerativeClustering(distance_threshold=0, n_clusters=None)model = model.fit(X)
plt.title("层次聚类树状图")
# 绘制树状图的前三级
plot_dendrogram(model, truncate_mode="level", p=3)
plt.xlabel("节点中的点数(如果没有括号,则为点索引)")
plt.show()
ed25e142fc080f6671513b9369c3c541.png

参考

  • Prof. Andrew Ng. Machine Learning. Stanford University

  • https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html

  • https://scikit-learn.org/stable/auto_examples/cluster

 
 
 
 
 
往期精彩回顾适合初学者入门人工智能的路线及资料下载机器学习及深度学习笔记等资料打印机器学习在线手册深度学习笔记专辑《统计学习方法》的代码复现专辑
AI基础下载黄海广老师《机器学习课程》视频课黄海广老师《机器学习课程》711页完整版课件

本站qq群955171419,加入微信群请扫码:

2fbc835b8aa9a714ebd59cc79a71d617.png


http://chatgpt.dhexx.cn/article/h1qXfTtj.shtml

相关文章

【聚类算法】10种Python聚类算法完整操作示例(建议收藏

点击上方&#xff0c;选择星标&#xff0c;每天给你送干货&#xff01; 来源&#xff1a;海豚数据科学实验室 著作权归作者所有&#xff0c;本文仅作学术分享&#xff0c;若侵权&#xff0c;请联系后台删文处理 聚类或聚类分析是无监督学习问题。它通常被用作数据分析技术&…

理论+实战,一文详解最常使用的10个聚类算法(附代码)

聚类或聚类分析是无监督学习问题。它通常被用作数据分析技术&#xff0c;用于发现数据中的有趣模式&#xff0c;例如基于其行为的客户群。有许多聚类算法可供选择&#xff0c;对于所有情况&#xff0c;没有单一的最佳聚类算法。 相反&#xff0c;最好探索一系列聚类算法以及每…

基于微信小程序的家校通系统-JAVA【数据库设计、源码、开题报告】

第一章 绪 论 1.1选题背景 随着网络时代的到来&#xff0c;互联网的优势和普及时刻影响并改变着人们的生活方式。在信息技术迅速发展的今天&#xff0c;计算机技术已经遍及全球&#xff0c;使社会发生了巨大的变革。 为了不受时间和地点的限制&#xff0c;智能手机用户可以通…

python新闻文本聚类_TextCluster:短文本聚类预处理模块 Short text cluster

推荐Github上一个NLP相关的项目&#xff1a; RandyPen/TextCluster 项目地址&#xff0c;阅读原文可以直达&#xff0c;欢迎参与和Star&#xff1a; https://github.com/RandyPen/TextCluster 这个项目的作者是AINLP交流群里的昭鸣同学&#xff0c;该项目 开源了一个短文本聚…

【组队学习】十一月微信图文索引

十一月微信图文索引 一、组队学习相关 周报&#xff1a; Datawhale组队学习周报&#xff08;第037周&#xff09;Datawhale组队学习周报&#xff08;第038周&#xff09;Datawhale组队学习周报&#xff08;第039周&#xff09;Datawhale组队学习周报&#xff08;第040周&…

k-means聚类算法从入门到精通

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶” 重磅干货&#xff0c;第一时间送达 k-means算法是非监督聚类最常用的一种方法&#xff0c;因其算法简单和很好的适用于大样本数据&#xff0c;广泛应用于不同领域&#xff0c;本文详细总结了k-means聚类算…

LaneAF | 利用Affinity Field聚类进行车道线实例分割

点击上方“计算机视觉工坊”&#xff0c;选择“星标” 干货第一时间送达 论文&#xff1a;https://arxiv.org/abs/2103.12040 开源代码&#xff1a;https://github.com/sel118/LaneAF 0 动机 车道线检测对于辅助驾驶、自动驾驶至关重要。全球范围内多种多样的车道线以及复杂的道…

机器学习 --- 聚类性能评估指标

第1关&#xff1a;外部指标 任务描述 本关任务:填写 python 代码&#xff0c;完成 calc_JC 函数、calc_FM 函数和 calc_Rand 函数分别实现计算 JC系数、FM 指数 和 Rand 指数 。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a; JC 系数&#xff1b; FM 指数&…

如何用 DBSCAN 聚类算法做数据分析?

DBSCAN属于无监督学习算法&#xff0c;无监督算法的内涵是观察无标签数据集自动发现隐藏结构和层次&#xff0c;在无标签数据中寻找隐藏规律。 聚类模型在数据分析当中的应用&#xff1a;既可以作为一个单独过程&#xff0c;用于寻找数据内在规律&#xff0c;也可以作为分类等…

激光点云的物体聚类

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶” 重磅干货&#xff0c;第一时间送达 文章导读 本文针对自动驾驶中三维点云的道路目标聚类进行讲解&#xff0c;从聚类算法的原理出发&#xff0c;介绍几种常用的点云障碍物聚类算法&#xff0c;并对比分析算…

K-means聚类算法

实训目标 本实训项目介绍无监督学习中&#xff0c;使用最广泛的 K-means 聚类算法。 先修知识 本实训项目假设&#xff0c;你已经掌握了初步的 Python 程序设计的基础知识。学习者若有一些 numpy 的使用经验&#xff0c;则可更快速地通过实训。 实训知识点 欧几里得距离 估算簇…

一文详解激光点云的物体聚类

点击上方“3D视觉工坊”&#xff0c;选择“星标” 干货第一时间送达 文章导读 本文针对自动驾驶中三维点云的道路目标聚类进行讲解&#xff0c;从聚类算法的原理出发&#xff0c;介绍几种常用的点云障碍物聚类算法&#xff0c;并对比分析算法的优劣和适用场景&#xff0c;从工程…

[计算机毕业设计]模糊聚类算法

前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着准备考研,考公,考教资或者实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科同学来说是充满挑战。为帮助大家顺利通过…

51nod-1548:欧姆诺姆和糖果

1548 欧姆诺姆和糖果 题目来源&#xff1a; CodeForces 基准时间限制&#xff1a;1 秒 空间限制&#xff1a;131072 KB 分值: 20 难度&#xff1a;3级算法题 收藏 关注 一天&#xff0c;欧姆诺诺姆来到了朋友家里&#xff0c;他发现了许多糖果。有蓝色和红色两种。他知道每颗…

android自动导入包快捷键,Android studio 自动导入(全部)包 import

http://blog.csdn.net/buaaroid/article/details/44979629 1 Android studio 只有import单个包的快捷键:Alt+Enter。没有Eclipse下的快速导入包的快捷键Ctrl+Shift+O。 2 但Android studio设置里有一项Auto Import自动导入功能。设置过程如下: Android studio --> File--&…

舍友打一把游戏的时间,我实现了一个selenium自动化测试并把数据保存到MySQL

文章目录 前言最终效果开发环境selenium元素定位方法页面分析思路分析实现步骤运行结果以下是全部代码 前言 很久没有玩selenium自动化测试了&#xff0c;近日在学习中都是在忙于学习新的知识点&#xff0c;所以呢今天就来写个selenium自动化测试的案例吧。有没有人疑惑&#…

51nod P1381 硬币游戏【数学】

题目 思路 比较简单. 参考代码 #include<iostream> #include<cstdio> using namespace std; int T,n; int main() {scanf("%d",&T);while(T--){scanf("%d",&n);printf("%d\n",2*n);}return 0; }

51nod3061 车

题目 题目链接 解题思路 提一种不需要生成树的解法。 我们将询问挂到点上&#xff0c;使用启发式合并的并查集。当询问的两边合并到一起时&#xff0c;我们就得到了答案。 整体复杂度 O ( n l o g 2 n ) O(nlog_2n) O(nlog2​n)。 代码 #include <cstdio> #include &…

51nod 1279 扔盘子

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1279 题目: 有一口井,井的高度为N,每隔1个单位它的宽度有变化。现在从井口往下面扔圆盘,如果圆盘的宽度大于井在某个高度的宽度,则圆盘被卡住(恰好等于的话会下去)。 盘子有几种命运:1、掉到…

51nod 1352:集合计数

1352 集合计数 基准时间限制&#xff1a;1 秒 空间限制&#xff1a;131072 KB 分值: 20 难度&#xff1a;3级算法题 收藏 关注 给出N个固定集合{1&#xff0c;N},{2,N-1},{3,N-2},...,{N-1,2},{N,1}.求出有多少个集合满足&#xff1a;第一个元素是A的倍数且第二个元素是B的倍数…