聚类是一种无监督的学习方法,是一种观察式学习。可以用于市场分析、图像处理等。聚类分析分为两种,一种是对指标的(R型)用于降维,另一种是对样本的(Q型)进行分类。

簇:类,一簇之中为一类。

质心:一簇之中的中心,簇之中其余样本以此为中心。

距离:样本之间为各个指标组成的n维空间的距离,簇之间为各个簇的样本之间最小距离。

基本过程

1.KMeans

初始化 K 个质心 → 计算点到质心距离 → 分配点到最近簇 → 重新计算簇质心 → 判断质心是否收敛(否→返回计算距离;是→输出结果)

import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

"""
初始化:随机选择K个样本作为初始质心 
分配样本:对每个样本x,计算其到各质心的距离,将其分配给最近的质心所在的簇。
更新质心:重新计算每个簇内所有样本的均值,作为新的质心。
迭代收敛:重复步骤 2-3,直到质心不再显著变化(或达到最大迭代次数)。
"""

# 1. 读取数据
data_path = r'D:\Studying Resources\processed_data_with_topsis.xlsx'
data = pd.read_excel(data_path)

# 假设数据的最后一列是标签,前几列是输入特征
# 如果数据格式不同,你可以调整这里的列选取方式
X = data.iloc[:, :-1].values  # 输入特征(前几列)

# 2. 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 3. 使用 KMeans 聚类
n_clusters = 3 # 假设我们希望分成 3 类
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
kmeans.fit(X_scaled)

# 获取聚类标签和簇中心
labels = kmeans.labels_  # 每个点的簇标签
centroids = kmeans.cluster_centers_  # 每个簇的质心

# 将聚类结果加入到原始数据中
data['Cluster'] = labels

# 4. 可视化聚类结果
# 如果输入特征是二维的,我们可以直接进行可视化,如果是多维数据,可以使用 t-SNE 等降维工具
if X_scaled.shape[1] == 2:
    plt.figure(figsize=(10, 6))
    plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=labels, cmap='viridis', marker='o')
    plt.scatter(centroids[:, 0], centroids[:, 1], s=300, c='red', marker='x')  # 绘制簇中心
    plt.title('KMeans 聚类结果')
    plt.xlabel('特征1')
    plt.ylabel('特征2')
    plt.show()
else:
    print("输入数据维度超过二维,可以使用降维工具(如t-SNE)来可视化。")

# 5. 输出聚类结果
print("聚类结果:")
print(data.head())

# 保存聚类结果为 Excel 文件
output_path = 'kmeans_output.xlsx'
data.to_excel(output_path, index=False)
print(f"聚类结果已保存到:{output_path}")

2.DBSCAN

设置 ε 和 MinPts → 遍历点 p → 判断 p 是否为核心点(否→标记噪声;是→建新簇 C)→ 将 p 的 ε- 邻域点入队 Q → 取出点 q → 判断 q 是否已访问(是→检查 Q 是否为空;否→标记已访问)→ 判断 q 是否为核心点(否→加入簇 C;是→邻域点入队 Q)→ 循环处理 Q 直到为空 → 遍历下一点 → 所有点处理完毕→输出结果

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler

plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

"""
参数设置:确定邻域半径ε和最小点数 MinPts。
遍历所有点:若点p是核心点,创建一个新簇,并将其 ε 邻域内的所有点加入队列。
处理队列中的每个点:若点q未被访问,标记为已访问并加入当前簇:若q是核心点,将其 ε- 邻域内的点加入队列(密度可达传播)。
标记噪声点:未被访问的点标记为噪声。
"""

# 1. 生成模拟数据,包含多个簇和噪声点
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 = np.vstack([X, np.random.uniform(low=-3, high=3, size=(50, 2))])

# 2. 数据标准化
X_scaled = StandardScaler().fit_transform(X)

# 3. 使用 DBSCAN 进行聚类
db = DBSCAN(eps=0.3, min_samples=10).fit(X_scaled)
labels = db.labels_

# 获取核心点的索引
core_samples_mask = np.zeros_like(labels, dtype=bool)
core_samples_mask[db.core_sample_indices_] = True

# 获取不同的聚类标签
unique_labels = set(labels)

# 4. 可视化聚类结果
colors = [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))]
plt.figure(figsize=(10, 7))

for k, col in zip(unique_labels, colors):
    if k == -1:
        # 噪声点
        col = [0, 0, 0, 1]  # 黑色
    class_member_mask = (labels == k)

    # 绘制核心点
    xy = X_scaled[class_member_mask & core_samples_mask]
    plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col), markeredgecolor='k', markersize=14)

    # 绘制边界点
    xy = X_scaled[class_member_mask & ~core_samples_mask]
    plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col), markeredgecolor='k', markersize=6)

plt.title('DBSCAN 聚类结果(包括噪声点)')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.show()

3.均值漂移

设置带宽 h → 遍历点 x_i → 计算 h - 邻域点 → 算漂移向量 → 更新 x_i 位置 → 判断是否收敛(否→重新计算邻域;是→记录收敛点)→ 所有点处理完毕→收敛点相同的点归为一簇→输出结果

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import MeanShift, estimate_bandwidth
from sklearn.datasets import make_blobs
import matplotlib.colors as mcolors

plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

"""
对于每个样本点,计算其邻域内所有点的 “均值”,并将该点向均值方向 “漂移”;
迭代此过程,直到样本点收敛到局部密度极大值点,这些极值点即为聚类中心。
"""

# 1. 生成模拟数据,包含多个簇
centers = [[1, 1], [-1, -1], [1, -1], [2, 2]]
X, _ = make_blobs(n_samples=500, centers=centers, cluster_std=0.6)

# 2. 自动估计带宽参数
bandwidth = estimate_bandwidth(X, quantile=0.2, n_samples=500)

# 3. 使用均值漂移进行聚类
ms = MeanShift(bandwidth=bandwidth, bin_seeding=True)
ms.fit(X)
labels = ms.labels_
cluster_centers = ms.cluster_centers_

# 4. 获取簇的数量
n_clusters = len(np.unique(labels))

# 5. 可视化聚类结果
plt.figure(figsize=(8, 6))

# 绘制每个簇的数据点
colors = mcolors.ListedColormap(plt.colormaps["viridis"](np.linspace(0, 1, n_clusters)))
for k in range(n_clusters):
    members = labels == k
    plt.scatter(X[members, 0], X[members, 1], s=50, c=[colors(k)], label=f'簇 {k+1}')

# 绘制簇中心
plt.scatter(cluster_centers[:, 0], cluster_centers[:, 1], c='red', s=300, marker='x', label='簇中心')

plt.title(f'均值漂移聚类结果(簇的数量: {n_clusters})')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.legend()
plt.show()

4.传播

计算相似度矩阵 → 初始化 R 和 A 矩阵 → 设置阻尼系数 λ → 迭代更新 R 和 A → 应用阻尼系数 → 判断是否收敛(否→继续迭代;是→确定簇中心)→ 分配簇标签→输出结果

import matplotlib.colors as mcolors
import matplotlib.pyplot as plt
from sklearn.cluster import AffinityPropagation
from sklearn.datasets import make_blobs
import numpy as np

plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False

"""
计算相似度矩阵:根据输入数据计算数据点之间的相似度矩阵。
初始化矩阵:初始化责任矩阵R和可用性矩阵A,均为与相似度矩阵同形的零矩阵。
迭代更新:通过迭代不断更新责任值和可用性值。每次更新后,应用阻尼系数对矩阵进行处理,以稳定迭代过程。
判断收敛:检查是否达到收敛条件,通常是责任值和可用性值的变化小于某个阈值,或者达到最大迭代次数。
确定簇中心和簇标签:收敛后,根据责任值和可用性值之和确定簇中心,为每个数据点分配簇标签。
"""

# 1. 生成二维数据集,包含多个簇
centers = [[1, 1], [-1, -1], [1, -1]]
X, labels_true = make_blobs(n_samples=300, centers=centers, cluster_std=0.5, random_state=42)

# 2. 使用传播聚类进行聚类
ap = AffinityPropagation(random_state=42)
ap.fit(X)
labels = ap.labels_
cluster_centers_indices = ap.cluster_centers_indices_

# 获取簇的数量
n_clusters = len(cluster_centers_indices)

# 3. 可视化聚类结果
plt.figure(figsize=(8, 6))

# 绘制数据点
colors = mcolors.ListedColormap(plt.colormaps["viridis"](np.linspace(0, 1, n_clusters)))
for k, col in enumerate(colors(range(n_clusters))):
    members = labels == k
    plt.scatter(X[members, 0], X[members, 1], s=50, c=[col], label=f'簇 {k+1}')

# 绘制簇中心
cluster_centers = X[cluster_centers_indices]
plt.scatter(cluster_centers[:, 0], cluster_centers[:, 1], c='red', s=300, marker='x', label='簇中心')

plt.title(f'传播聚类结果(簇的数量: {n_clusters})')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.legend()
plt.show()

5.光谱

构建相似度矩阵 → 算度矩阵 D 和拉普拉斯矩阵 L → 求 L 的前 k 个特征向量 → 组成矩阵 V 并标准化 → 对 V 行做 K-means 聚类→输出结果

import matplotlib
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from sklearn.cluster import SpectralClustering
from sklearn.preprocessing import StandardScaler

matplotlib.rcParams["font.family"] = ["SimHei"]
matplotlib.rcParams["axes.unicode_minus"] = False

# 1. 生成非凸形状数据集(例如:月牙形数据集)
X, y = make_moons(n_samples=300, noise=0.05, random_state=42)

# 2. 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 3. 使用光谱聚类
n_clusters = 2  # 假设我们知道有两个簇
spectral = SpectralClustering(n_clusters=n_clusters, affinity='rbf', gamma=1.0, random_state=42)
labels = spectral.fit_predict(X_scaled)

# 4. 可视化聚类结果
plt.figure(figsize=(10, 6))
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=labels, cmap='viridis', marker='o')
plt.title('光谱聚类结果')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.show()

# 5. 输出聚类结果
print("聚类标签:", labels)

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐