Affinity Propagation算法的python实现和分析

Affinity Propagation 算法更新方式很简单就是 更新 r矩阵在更新a矩阵

公式如下:

其中 s是相似度矩阵 一般直接可以采用距离来表示相似度

r 表示吸引度  a归属度

这里就用选举来进行形象讲解下

对于公式1

就好比是一个投票阶段  s(i, k)表示i 选k作为总统(聚类中心)的合适度    用r(i, k) 表示选k作为总统的意向有多大

直观来说  直接用r(i, k) =  s(i, k) -  max(s(i, k'))      k' != k     貌似更加形象,但是人是感性动物,会受别人影响,这里就是a起到的作用,比如 i 的亲人朋友都投了k'当总统,就会来问我你要不要和我们一样投k',  大家都在投k', 你也快点投k'。然后我经过深思熟虑 最终投给k的意向会受到影响(影响的大小取决于a(i, k')的大小)。所以  r(i, k) =  s(i, k) -  max{s(i, k') + a(i, k')}  最终我投给k的意向 

对于公式2

就像是一个拉票,a(i, k)表示形象理解为k对i的影响力而他的大小受k对其他i'的影响力,如果亲人朋友 i' 都投了k, 对于i来说就有很大概率也投k,这就是所谓的随波逐流。越多i'投k, a(i, k)就会也大,也就是说k对i的影响力越大,对于公式1起到的影响就越大。这里加上r(k, k)也很好理解,我自己对自己也有个投票意向,虽然大家都投了我,但是我自己这一票肯定还是要算计来的,万一比别人就差这一票不是亏大了。

迭代停止的条件就是所有的样本的聚类中心都不在变化为止,或者迭代了n次都还没有变化(n的值可以自己取)。

代码如下:

from sklearn.datasets.samples_generator import make_blobs
import matplotlib.pyplot as plt
import numpy as np

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


def calc_similarity(X):
    m, n = np.shape(X)
    X_copy = np.copy(X)
    X = X.reshape((m, 1, n))
    X_copy = X_copy.reshape(1, m, n)
    sum = np.sum(np.square(X[..., :] - X_copy[..., :]), axis=-1)
    similarity = -1 * np.sqrt(sum)
    median_value = calc_median(similarity)
    for i in range(m):
        # preference设置 非对角线元素中值
        similarity[i, i] = median_value
    return similarity


def calc_median(X):
    data = []
    for i in range(len(X)):
        x = X[i]
        x = np.delete(x, i)
        data += list(x)
    n = len(data)
    return data[n // 2]


def affinityPropagation(similarity, lamda=0.):
    # 定义吸引度矩阵和归属感矩阵
    r = np.zeros_like(similarity, dtype=np.int32)
    a = np.zeros_like(similarity, dtype=np.int32)

    m, n = np.shape(similarity)

    last_change = np.zeros((m, ), dtype=np.int32)
    while True:
        # update r matrix
        for idx in range(m):
            a_s_idx = a[idx] + similarity[idx]
            for idy in range(n):
                a_s_idx_del = np.delete(a_s_idx, idy)
                max_value = np.max(a_s_idx_del)
                r_new = similarity[idx, idy] - max_value
                r[idx][idy] = lamda * r[idx][idy] + (1 - lamda) * r_new
        # update a matrix
        for idx in range(m):
            for idy in range(n):
                r_idy = r[:, idy]
                r_idy = np.delete(r_idy, idx)
                a_new = np.sum(np.maximum(0, r_idy))
                if idx != idy:
                    a_new = min(0, r[idy, idy] + a_new)
                a[idx][idy] = lamda * a[idx][idy] + (1 - lamda) * a_new
        r_a = r + a
        # 当聚类中心不再发生变化时停止
        argmax = np.argmax(r_a, axis=1)
        current_change = argmax
        if (last_change == current_change).all():
            break
        last_change = current_change
    print('r', r)
    print('a', a)
    return r + a


def computeCluster(fitable, data):
    clusters = {}
    num = len(fitable)
    for idx in range(num):
        fit = fitable[idx]
        argmax = np.argmax(fit, axis=-1)
        if argmax not in clusters:
            clusters[argmax] = []
        clusters[argmax].append(tuple(data[idx]))
    return clusters


def plotClusters(clusters, title):
    """ 画图 """
    plt.figure(figsize=(8, 5), dpi=80)
    axes = plt.subplot(111)
    col = []
    r = lambda: np.random.randint(0, 255)
    for index in range(len(clusters)):
        col.append(('#%02X%02X%02X' % (r(), r(), r())))
    color = 0
    for key in clusters:
        cluster = clusters[key]
        for idx in range(len(cluster)):
            cluster_idx = cluster[idx]
            axes.scatter(cluster_idx[0], cluster_idx[1], s=20, c=col[color])
        color += 1
    plt.title(title)
    plt.show()


similarity = calc_similarity(X)
fitable = affinityPropagation(similarity, lamda=0.25)
clusters = computeCluster(fitable, X)
print(len(clusters))
plotClusters(clusters, "clusters by affinity propagation")

结果如下图:

与君共勉~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值