学习日记_20241126_聚类方法(Affinity Propagation)

前言

提醒:

文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。

其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。

文章目录


聚类算法

聚类算法在各种领域中有广泛的应用,主要用于发现数据中的自然分组和模式。以下是一些常见的应用场景以及每种算法的优缺点:

经典应用场景

  1. 市场细分:根据消费者的行为和特征,将他们分成不同的群体,以便进行有针对性的营销。

  2. 图像分割: 将图像划分为多个区域或对象,以便进行进一步的分析或处理。

  3. 社交网络分析:识别社交网络中的社区结构。

  4. 文档分类:自动将文档分组到不同的主题或类别中。

  5. 异常检测识别数据中的异常点或异常行为。

  6. 基因表达分析:在生物信息学中,根据基因表达模式对基因进行聚类。

Affinity Propagation(亲和力传播)

Affinity Propagation(亲和力传播)是一种用于聚类分析的方法,由Frey和Dueck在2007年提出。它不需要预先指定聚类数量,而是通过数据点之间的相似度来自动确定聚类中心。以下是Affinity Propagation聚类方法的优缺点:

优点:

  1. 无需预先指定聚类数量:Affinity Propagation能够自动确定最佳的聚类数量,这是其最大的优势之一。
  2. 聚类质量高:由于是基于数据点之间的相似度进行聚类,通常能够得到质量较高的聚类结果。
  3. 对初始条件不敏感:与其他一些聚类算法(如K-means)相比,Affinity Propagation对初始条件的设置不那么敏感。
  4. 适用于多种数据类型:可以用于处理不同类型的数据,包括数值型、分类型等。
  5. 可解释性强:聚类结果中的"exemplars"(代表点)可以提供对聚类结构的直观解释。

缺点:

  1. 计算复杂度高:Affinity Propagation的计算复杂度较高,尤其是对于大规模数据集,计算成本可能会非常大。
  2. 参数敏感:算法的性能对参数(如阻尼系数和相似度矩阵的构造方式)比较敏感,需要仔细调参。
  3. 内存消耗大:由于需要存储所有数据点之间的相似度矩阵,对于大规模数据集,内存消耗可能会成为一个问题。
  4. 对噪声和异常值敏感:噪声和异常值可能会对聚类结果产生较大影响。
  5. 不适合高维数据:在高维空间中,数据点之间的相似度计算可能会变得不够准确,影响聚类效果。
  6. 收敛速度慢 :对于某些数据集,Affinity Propagation可能需要较长时间才能收敛。
    总的来说,Affinity Propagation是一种强大的聚类方法,特别适用于那些不需要预先指定聚类数量且对聚类质量有较高要求的应用场景。然而,它的计算成本和参数敏感性也是在实际应用中需要考虑的因素。

简单实例(函数库实现)

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import AffinityPropagation

# 生成一个示例数据集
n_samples = 300
centers = [[1, 1], [5, 5], [1, 6], [6, 1], [7, 5]]
X, _ = make_blobs(n_samples=n_samples, centers=centers, cluster_std=0.6, random_state=42)

# 使用Affinity Propagation进行聚类
af = AffinityPropagation(preference=-50)  # preference值可以调整以影响聚类数量
af.fit(X)

# 获取聚类标签和聚类中心
labels = af.labels_
cluster_centers_indices = af.cluster_centers_indices_
cluster_centers = af.cluster_centers_

# 输出聚类结果
n_clusters = len(cluster_centers)
print(f"聚类数量: {n_clusters}")

# 可视化聚类结果
plt.figure(figsize=(8, 6))
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', marker='o', edgecolor='k', s=50)
plt.scatter(cluster_centers[:, 0], cluster_centers[:, 1], c='red', marker='X', s=200, label='Cluster Centers')
plt.title('Affinity Propagation Clustering Results')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.grid(True)
plt.show()

代码运行结果:

数学表达

Affinity Propagation(亲和传播)算法是一种基于消息传递的聚类方法,主要通过数据点之间的相似度矩阵来确定聚类结构。以下是该算法的数学原理和相关公式的详细讲解。

  1. 数据表示
    给定一个由 n n n 个数据点组成的数据集 X = { x 1 , x 2 , ... , x n } X = \{ x_1, x_2, \ldots, x_n \} X={x1,x2,...,xn},这些数据点可以用特征向量表示。算法首先计算数据点之间的相似度,通常使用以下公式计算两个数据点 x i x_i xi 和 x j x_j xj 之间的相似度:
    s ( i , j ) = − ∥ x i − x j ∥ 2 s(i, j) = -\|x_i - x_j\|^2 s(i,j)=−∥xi−xj∥2
    这里, ∥ x i − x j ∥ \|x_i - x_j\| ∥xi−xj∥ 是欧几里得距离。相似度 s ( i , j ) s(i, j) s(i,j) 的值越大,表示数据点之间的相似性越高,因此使用负的平方距离来表示相似度。
  2. 责任和可用性
    Affinity Propagation 使用两个重要的变量:责任(Responsibility)和可用性(Availability)。
    • 责任 r ( i , k ) r(i, k) r(i,k):表示数据点 x i x_i xi 对于选择数据点 x k x_k xk 作为簇中心的"责任"。责任的计算公式为:
      r ( i , k ) = s ( i , k ) − max ⁡ j ≠ k ( a ( i , j ) + s ( i , j ) ) r(i, k) = s(i, k) - \max_{j \neq k} \left( a(i, j) + s(i, j) \right) r(i,k)=s(i,k)−j=kmax(a(i,j)+s(i,j))
      这里, a ( i , j ) a(i, j) a(i,j) 是可用性,表示数据点 x j x_j xj 对于选择数据点 x k x_k xk 作为簇中心的可用性。
    • 可用性 a ( i , k ) a(i, k) a(i,k):表示数据点 x k x_k xk 被数据点 x i x_i xi 作为中心的支持程度。可用性的计算公式为:
      a ( i , k ) = min ⁡ ( 0 , r ( k , k ) + ∑ j ≠ i , j ≠ k max ⁡ ( 0 , r ( j , k ) ) ) a(i, k) = \min\left(0, r(k, k) + \sum_{j \neq i, j \neq k} \max(0, r(j, k))\right) a(i,k)=min 0,r(k,k)+j=i,j=k∑max(0,r(j,k))
  3. 消息传递
    Affinity Propagation 使用迭代的方式更新责任和可用性。迭代过程如下:
    1. 初始化 责任 r ( i , k ) r(i, k) r(i,k) 和可用性 a ( i , k ) a(i, k) a(i,k):
      • 初始时,通常设置可用性为0,即 a ( i , k ) = 0 a(i, k) = 0 a(i,k)=0。
      • 责任初始化为相似度 s ( i , k ) s(i, k) s(i,k),即 r ( i , k ) = s ( i , k ) r(i, k) = s(i, k) r(i,k)=s(i,k)。
    2. 更新责任 r ( i , k ) r(i, k) r(i,k) 和可用性 a ( i , k ) a(i, k) a(i,k):
      • 在每次迭代中,使用上述公式更新责任和可用性。
    3. 收敛条件
      • 迭代过程持续进行,直到责任和可用性达到收敛条件,或者达到设定的最大迭代次数。
  4. 簇的确定
    在迭代完成后,Affinity Propagation 通过以下步骤确定最终的簇:
    1. 选择簇中心
      • 一个数据点 x k x_k xk 被选为簇中心,当 r ( k , k ) + a ( k , k ) > 0 r(k, k) + a(k, k) > 0 r(k,k)+a(k,k)>0 时,即责任和可用性的和大于0。
    2. 分配数据点到簇
      • 将数据点 x i x_i xi 分配到其对应的簇中心 x k x_k xk,当 r ( i , k ) + a ( i , k ) r(i, k) + a(i, k) r(i,k)+a(i,k) 最大时。
  5. 总结
    Affinity Propagation 通过消息传递的方法有效地在数据点之间传播信息,动态更新责任和可用性,最终确定簇的结构。该方法具有以下特点:
    • 不需要预先指定聚类的数量。
    • 可以适应任意形状的簇。
    • 利用全局信息来做出聚类决策。

手动实现

代码存在问题,以后再改。

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import pairwise_distances
from sklearn.datasets import make_blobs

def affinity_propagation(X, similarity_matrix=None, damping=0.9, max_iter=200, convergence_iter=15):
    """
    手动实现亲和传播(Affinity Propagation)算法
    
    Parameters:
        X: ndarray of shape (n_samples, n_features)
            输入数据集。
        similarity_matrix: ndarray of shape (n_samples, n_samples), optional
            相似度矩阵。如果不提供,将基于负欧几里得距离计算。
        damping: float, default=0.9
            抑制因子,用于稳定消息传递过程。
        max_iter: int, default=200
            最大迭代次数。
        convergence_iter: int, default=15
            收敛条件,连续多少次迭代内没有任何变化时停止。
    
    Returns:
        labels: ndarray of shape (n_samples,)
            每个样本的簇标签。
        exemplars: ndarray of shape (n_exemplars,)
            簇中心的索引。
    """
    n_samples = X.shape[0]
    
    # Step 1: 计算相似度矩阵(如果未提供)
    if similarity_matrix is None:
        similarity_matrix = -pairwise_distances(X, metric='euclidean') ** 2  # 负的欧几里得距离平方
    
    # Step 2: 初始化责任矩阵和可用性矩阵
    R = np.zeros_like(similarity_matrix)  # 责任矩阵
    A = np.zeros_like(similarity_matrix)  # 可用性矩阵
    
    # Step 3: 开始迭代过程
    for iteration in range(max_iter):
        # 计算责任矩阵R(责任值表示数据点i与数据点j的相似度差距)
        for i in range(n_samples):
            for j in range(n_samples):
                if i != j:
                    R[i, j] = similarity_matrix[i, j] - np.max(A[:, j] + similarity_matrix[i, :])
                else:
                    R[i, j] = similarity_matrix[i, j] - np.max(A[:, j])
        
        # 应用抑制因子
        R = damping * R + (1 - damping) * np.diag(np.diag(R))
        
        # 计算可用性矩阵A(表示数据点i是否适合作为数据点j的簇中心)
        for i in range(n_samples):
            for j in range(n_samples):
                if i != j:
                    A[i, j] = np.min([0, R[j, j] + np.sum(np.maximum(0, R[:, j])) - np.maximum(0, R[i, j])])
        
        # 应用抑制因子
        A = damping * A + (1 - damping) * np.diag(np.diag(A))
        
        # 检查是否收敛:在连续的 `convergence_iter` 次迭代内没有变化
        if iteration >= convergence_iter:
            if np.all(np.abs(R - A) < 1e-5):
                print(f"Converged at iteration {iteration}")
                break
    
    # Step 4: 选择簇中心,簇中心是使责任值和可用性值加和最大的点
    exemplars = np.argmax(R + A, axis=1)
    
    # Step 5: 为每个点分配簇标签
    labels = np.argmax(R + A, axis=1)
    
    return labels, exemplars

# 示例使用
if __name__ == "__main__":
    # 生成示例数据
    X, _ = make_blobs(n_samples=50, centers=3, random_state=32)
    
    # 使用亲和传播进行聚类
    labels, exemplars = affinity_propagation(X, damping=0.1, max_iter=200, convergence_iter=10)
    print(f"Cluster labels: {labels}")
    print(f"Exemplars: {exemplars}")
    # 可视化聚类结果
    plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
    plt.scatter(X[exemplars, 0], X[exemplars, 1], color='red', marker='X', s=200, label='Exemplars')
    plt.title("Affinity Propagation Clustering")
    plt.legend()
    plt.show()

数据与结果为

相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习