ML聚类-KMeasn 谱聚类 幂迭代聚类PIC

1. 常用聚类算法

聚类算法是机器学习中非常重要的算法,聚类是将大量数据以相似度为基础形成若干类,使得类内之间的数据最为相似,各类之间的数据相似度差别尽可能大。聚类分析就是以相似性为基础,对数据集进行聚类划分,属于无监督学习。聚类分析可以直接比较各事物之间的性质,将性质相近的归为一类,将性质差别较大的归入不同的类。

聚类具有广泛的应用领域,对于网络流量的监控和数据挖掘,可以实现舆情分析,获知出现的前所未有的热点事件。在商业上,市场消费数据的聚类,可以使企业相关人员获知新的消费趋势和市场需求。而在城市规划领域,对于市政交通或者人口分布的聚类,可以帮助市政规划人员更好地进行城市分区和道路建设。

2. K均值聚类

2.1. 特性

  • 未标记的数据集聚类成不同的组

  • 迭代移动簇中心和簇成员

  • 簇内相似度高,簇间相似度低

  • 局部最优,并非全局最优

2.2. 步骤:

  1. 随机选择K个聚类中心
  2. 寻找每个数据点{x}距离最近的中心点,将两者关联,最后所有与同一中心点关联的点都聚成一类。
  3. 确定每组关联的中心点,并计算其均值。
  4. 反复操作2~3步,当中心点不发生变化时停止操作。

2.3. 实现

2.3.1. 自定义实现


# %%

import numpy as np
import pandas as pd

from numpy import *


# %%
def kmeans(data, k):
    n, dim = data.shape
    result = np.mat(np.zeros((n, 2)))  # 存储每个点所属的中心点以及到中心点的距离
    clusterstop = True
    center = zeros((k, dim))  # 初始化质心点存储器

    for i in range(k):  # 随机选择k个质心点的位置
        index = int(random.uniform(0, n))
        center[i, :] = data[index, :]

    while clusterstop:
        clusterstop = False

        for i in range(n):  # 遍历点
            dmin = 10000.0
            Imin = 0
            for j in range(k):  # 计算当前点到某个质心点的距离,将其分配到距离最小的质心
                distance = sqrt(sum(pow((center[j, :] - data[i, :]), 2)))
                if distance < dmin:  # 如果距离小于阈值,则将阈值降低,并记录最小距离点的索引
                    dmin = distance
                    Imin = j
            if result[i, 0] != Imin:  # 如果该点不属于该点群,则仍然继续参与下一轮聚类
                clusterstop = True
                result[i, :] = Imin, dim ** 2

        # 更新各个质心的坐标
        for j in range(k):
            pointsInCluster = data[nonzero(result[:, 0].A == j)[0]]
            center[j, :] = mean(pointsInCluster, axis=0)
    return center, result


# %%
from sklearn.datasets import load_iris
from sklearn.utils import shuffle

iris = load_iris()

X = iris.data
y = iris.target
names = iris.feature_names

X = X[0:100]
y = y[0:100]

data_x = pd.DataFrame(X, columns=['f1', 'f2', 'f3', 'f4'])
data_y = pd.DataFrame(y, columns=['label'])
data = pd.concat([data_x, data_y], axis=1)
data

# %%
centers, results = kmeans(X, 3)
centers, results

# %%

cluster_result = []
idx = 0

from tqdm import tqdm, trange

pbar = tqdm(total=len(data))
for index, row in data.iterrows():
    row['center_index'] = results.__array__()[idx][0]
    row['distance'] = results.__array__()[idx][1]
    # row['center_loc'] = centers[row['center_index']]
    cluster_result.append(row)
    idx += 1
    pbar.update()
cluster_result = pd.DataFrame(cluster_result)
# %%

import seaborn as sns
import matplotlib.pyplot as plt

sns.scatterplot(x=cluster_result['f1'], y=cluster_result['f2'], hue=cluster_result['label'])
# plt.show()

sns.scatterplot(x=cluster_result['f1'], y=cluster_result['f2'], hue=cluster_result['center_index'])

plt.show()

2.3.2. 调用库实现

# %%
from sklearn.cluster import KMeans
from sklearn.datasets import load_iris

iris = load_iris()
X = iris.data[0:100]
y = iris.target[0:100]

import pandas as pd

data_x = pd.DataFrame(X, columns=['f1', 'f2', 'f3', 'f4'])
data_y = pd.DataFrame(y, columns=['label'])
data = pd.concat([data_x, data_y], axis=1)

import seaborn as sns
import matplotlib.pyplot as plt

sns.scatterplot(data['f1'], data['f2'], hue=data['label'])
plt.show()

# %%
kmeans = KMeans(n_clusters=3, random_state=2021)
result = kmeans.fit_transform(X)

#%%
labels = pd.DataFrame(kmeans.labels_,columns=['center_index'])
result = pd.concat([data,labels],axis=1)
result

#%%
sns.scatterplot(result['f1'],result['f2'],hue=result['center_index'])
plt.show()


  • n-clusters : K值
  • Init: 初试簇中心的获取方法

2.4. 缺陷

  • 需要事先确定K值

2.5. 如何改进

2.5.1. K-Harmonic Means(K调和均值)

  • 根据簇均值将数据分为K个簇
  • 通过目标函数和中心移动公式对簇成员和簇中心移动
  • 算法迭代至不再有点移动为止

其评价函数为所有点到所有中心的均方距离的调和平均值函数,平均值定义为 H A = P ∑ i = 1 P 1 a i H A=\frac{P}{\sum_{i=1}^{P} \frac{1}{a_{i}}} HA=i=1Pai1P

然后将过于集中的中心点,移动到数据附近没有中心点的区域上,这种算法降低了对初始点选取的依赖,提高了算法的鲁棒性

2.5.2. 其他

2.6. Kmenas 与 KNN的区别

  • KNN 有监督 || Kmenas 无监督
  • KNN对于无标注的数据,会自行统计周边k个数据,投票决定划分到哪个类,但是Kmeans本身就不需要数据有标注

3. 谱聚类

谱聚类基于谱图原理,根据数据集相似性矩阵以聚类,它具有更强的数据分布适应性. K-Means适用于区分线性可分的类别,而谱聚类在非凸模型下也可以很好的实现聚类.

3.1. 步骤

  1. 计算相似度矩阵 W = R n × n W=R^{n\times n} W=Rn×n
  2. 计算度矩阵
  3. 计算拉普拉斯矩阵$L = D-W

更多的时候, 也用拉普拉斯矩阵的另一个形式:

img
  1. 计算矩阵L的特征值,从小到大排序,通过前K个特征向量 X 1 , X 2 , X 3 , . . . , X k X_1,X_2,X_3,...,X_k X1,X2,X3,...,Xk构造新的矩阵.

X = [ X 1 , . . . , X N ] ∈ R n × K X = [X_1,...,X_N]\in R^{n\times K} X=[X1,...,XN]Rn×K

  1. 将X的行向量规范化,得到矩阵:
    Y = X i j ( ∑ j X i j 2 ) 1 2 Y = \frac{X_{ij}}{\left( \sum \limits_{j} X_{ij}^2 \right)^{\frac{1}{2}}} Y=(jXij2)21Xij

3.2. 实现

# %%
import numpy as np
import pandas as pd

from sklearn.cluster import KMeans
from sklearn.metrics.pairwise import rbf_kernel
from sklearn.preprocessing import normalize

from numpy import linalg as LA


# %%


def similarity_function(points):
    """
    相似性函数,利用径向基核函数计算相似性矩阵,对角线元素置为0
    对角线元素为什么要置为0我也不清楚,但是论文里是这么说的
    :param points:
    :return:
    """
    res = rbf_kernel(points)
    for i in range(len(res)):
        res[i, i] = 0
    return res


def spectral_clustering(points, k):
    W = similarity_function(points)

    Dn = np.diag(np.power(np.sum(W, axis=1), -0.5))

    L = np.eye(len(points)) - np.dot(np.dot(Dn, W), Dn)
    eigvals, eigvecs = LA.eig(L)
    indices = np.argsort(eigvals)[:k]

    k_smallest = normalize(eigvecs[:, indices])

    return KMeans(n_clusters=k).fit_predict(k_smallest)


# %%
from sklearn.datasets import make_blobs
import seaborn as sns
import matplotlib.pyplot as plt

X, y = make_blobs()

data = []
for x, y in zip(X, y):
    data.append((x[0], x[1], y))
data = pd.DataFrame(data, columns=['x1', 'x2', 'y'])

sns.scatterplot(x=data['x1'], y=data['x2'], hue=data['y'])

plt.show()

#%%
labels = spectral_clustering(X,3)

data = []
for x, y in zip(X, labels):
    data.append((x[0], x[1], y))
data = pd.DataFrame(data, columns=['x1', 'x2', 'y'])

sns.scatterplot(x=data['x1'], y=data['x2'], hue=data['y'])

plt.show()

3.3. 小结

谱聚类算法本质上是将聚类问题转化为图的最优划分问题,属于对点聚类算法. 谱聚类最重要的问题就是由于数据量太大,所以谱聚类中的很多大规模矩阵运算都无法很快完成.

4. 幂迭代算法(PIC)

参考: 幂迭代聚类 - 简书 (jianshu.com)

4.1. 幂法求特征值和特征向量

若我们求某个n阶方阵A的特征值和特征向量, 先任取一个非零初始向量v(0), 进行迭代计算 v ( k + 1 ) = A v ( k ) v^{(k+1)}=A v^{(k)} v(k+1)=Av(k), 直到收敛.

当k增大时, 序列的收敛情况与绝对值最大的特征值有密切关系, 分析这一序列的极限, 即可求出按模最大的特征值和特征向量.

假定矩阵A有n个线性无关的特征向量, n个特征值按模由大到小排列:

∣ λ 1 ∣ > = ∣ λ 2 ∣ > = … > = ∣ λ n ∣ \left|\lambda_{1}\right|>=\left|\lambda_{2}\right|>=\ldots>=\left|\lambda_{n}\right| λ1>=λ2>=>=λn

其相应的特征向量为:

e 1 , e 2 , … , e n e_{1}, e_{2}, \ldots, e_{n} e1,e2,,en

他们构成n维空间的一组正交基. 任取的初始向量 v ( 0 ) v^{(0)} v(0)当然可以由他们的线性组合给出:

v ( 0 ) = c 1 e 1 + c 2 e 2 + … + c n e n v^{(0)}=c_{1} e_{1}+c_{2} e_{2}+\ldots+c_{n} e_{n} v(0)=c1e1+c2e2++cnen

递推:
v ( 0 ) = c 1 e 1 + c 2 e 2 + … + c n e n v ( 1 ) = A v ( 0 ) = A ( c 1 e 1 + c 2 e 2 + … + c n e n ) = c 1 ( A e 1 ) + c 2 ( A e 2 ) + … + c 1 ( A e n ) = c 1 λ 1 e 1 + c 2 λ 2 e 2 + … + c n λ n e n v k = c 1 λ 1 k e 1 + c 2 λ 2 k e 2 + … + c n λ n k e n \begin{gathered} v^{(0)}=c_{1} e_{1}+c_{2} e_{2}+\ldots+c_{n} e_{n} \\ v^{(1)}=A v^{(0)}=A\left(c_{1} e_{1}+c_{2} e_{2}+\ldots+c_{n} e_{n}\right)=c_{1}\left(A e_{1}\right)+c_{2}\left(A e_{2}\right)+\ldots+c_{1}\left(A e_{n}\right) \\ \qquad=c_{1} \lambda_{1} e_{1}+c_{2} \lambda_{2} e_{2}+\ldots+c_{n} \lambda_{n} e_{n} \\ v^{k}=c_{1} \lambda_{1}^{k} e_{1}+c_{2} \lambda_{2}^{k} e_{2}+\ldots+c_{n} \lambda_{n}^{k} e_{n} \end{gathered} v(0)=c1e1+c2e2++cnenv(1)=Av(0)=A(c1e1+c2e2++cnen)=c1(Ae1)+c2(Ae2)++c1(Aen)=c1λ1e1+c2λ2e2++cnλnenvk=c1λ1ke1+c2λ2ke2++cnλnken
下面按模最大特征值 λ 1 \lambda_1 λ1是单根的情况讨论:

将上式变形可得:
v ( k ) = λ 1 k ( c 1 e 1 + c 2 ( λ 2 λ 1 ) k e 2 + … + c n ( λ n λ 1 ) k e n ) v^{(k)}=\lambda_{1}^{k}\left(c_{1} e_{1}+c_{2}\left(\frac{\lambda_{2}}{\lambda_{1}}\right)^{k} e_{2}+\ldots+c_{n}\left(\frac{\lambda_{n}}{\lambda_{1}}\right)^{k} e_{n}\right) v(k)=λ1k(c1e1+c2(λ1λ2)ke2++cn(λ1λn)ken)
a 1 ≠ 0 a1≠0 a1=0, 由于 0 < ∣ λ i / λ 1 ∣ < 1 ( i ≥ 2 ) 0<|λi/λ1|<1 (i≥2) 0<λi/λ1<1(i2), 考虑到 ( 0 , 1 ) (0,1) (0,1)之间的数的 k k k次方的极限为0, 因此k充分大时:
v ( k ) ≈ λ 1 k c 1 e 1 v^{(k)} \approx \lambda_{1}^{k} c_{1} e_{1} v(k)λ1kc1e1
所以, 当k充分大时:
v ( k ) ≈ λ 1 k c 1 e 1 , v ( k + 1 ) ≈ λ 1 k + 1 c 1 e 1 ⇒ λ 1 ≈ v ( k + 1 ) v k v^{(k)} \approx \lambda_{1}^{k} c_{1} e_{1}, v^{(k+1)} \approx \lambda_{1}^{k+1} c_{1} e_{1} \Rightarrow \lambda_{1} \approx \frac{v^{(k+1)}}{v^{k}} v(k)λ1kc1e1,v(k+1)λ1k+1c1e1λ1vkv(k+1)

4.2. 幂迭代聚类

在快速迭代算法中, 我们构造另外一个矩阵 W = D − 1 A W=D^{-1}A W=D1A, 同谱聚类算法做比对, 我们可以知道W的最大特征向量就是拉普拉斯矩阵L的最小特征向量. 我们知道拉普拉斯矩阵有一个特性:第二小特征向量(即第二小特征值对应的特征向量)定义了图最佳划分的一个解, 它可以近似最大化划分准则. 更一般的, k个最小的特征向量所定义的子空间很适合去划分图.

因此拉普拉斯矩阵第二小、第三小直到第k小的特征向量可以很好的将图W划分为k个部分.

注意, 矩阵L的k个最小特征向量也是矩阵W的k个最大特征向量. 计算一个矩阵的最大特征向量可以通过上述幂迭代算法. 循环公式为:
v t + 1 = c W v t v^{t+1}=c W v^{t} vt+1=cWvt

其中 c c c是标准化常量, 是为了避免 v t v^t vt产生过大的值, 这里
c = 1 ∥ W v t ∥ c=\frac{1}{\left\|W v^{t}\right\|} c=Wvt1
算法的一般步骤:

4.3. 实现

# %%
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
from sklearn.metrics.pairwise import rbf_kernel

# %%
X, y = make_blobs(centers=3)

data = []
for x, y in zip(X, y):
    data.append((x[0], x[1], y))
data = pd.DataFrame(data, columns=['x1', 'x2', 'y'])

sns.scatterplot(x=data['x1'], y=data['x2'], hue=data['y'])
plt.show()

# %%
points = X
W = rbf_kernel(X)  # 相似性矩阵

for i in range(len(W)):
    W[i, i] = 0

K = 3

v = np.random.rand(len(W), 1)
delta = 1000.0

# %%

threshold = 1e-4

while np.sum(delta) >= threshold:
    v_old = v
    v = np.matmul(W, v) / (np.linalg.norm(np.matmul(W, v), ord=1))

    delta = np.abs(v_old - v)

# %%

eigenvalue, featurevectors = np.linalg.eig(W)

# %%
from sklearn.cluster import KMeans

kmeans = KMeans(n_clusters=3)
kmeans.fit_transform(v)
labels = kmeans.labels_

# %%
idx = 0
result = []
for point, label in zip(v, labels):
    result.append((idx, X[idx][0], X[idx][1], point, label))
    idx += 1

result = pd.DataFrame(result, columns=['index', 'x1', 'x2', 'value', 'center'])

sns.scatterplot(x=result['x1'],y=result['x2'],hue=result['center'])

plt.show()

估计实现的是有问题的. 欢迎各位批评指正.

5. 总结

K-means是聚类的基础,谱聚类可以应用于非凸数据,更具有实用价值,PIC类似于谱聚类,不过拥有更高的效率,实际应用效果一般优于谱聚类.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古承风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值