聚类算法与实践

聚类算法

聚类概念:

无监督问题:我们手里并没有每一个数据属于某一类标签了

聚类:相似的东西分到一组

难点:如何评估,如何调参

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U09AW8Rw-1642229946253)(笔记图片/image-20220115124327140.png)]

K-MEANS算法

要得到簇的个数,需要指定K值

质心:均值,即向量各维取平均即可

距离的度量:常用欧几里得距离和余弦相似度(先标准化)

优化目标: min ⁡ ∑ i = 1 K ∑ x ∈ C i dist ⁡ ( c i , x ) 2 \min \sum_{i=1}^{K} \sum_{x \in C_{i}} \operatorname{dist}\left(c_{i}, x\right)^{2} mini=1KxCidist(ci,x)2 (对于某一个簇每一个点到中心点的距离越小越好)

工作流程:随机选择两个点k=2;基于两个初始化的点,计算每一个点到初始化点的距离;更新质心;重新计算

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UrmUe0Fs-1642229946254)(笔记图片/image-20220115124920698.png)]

优势:简单,快速,适合常规数据集

劣势:K值难确定;复杂度与样本呈线性关系;很难发现任意形状的簇

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mdn8zIJp-1642229946255)(笔记图片/image-20220115125014646.png)]

使用Kmeans进行图像压缩

将彩色图变成灰度图,对像素点进行聚类

# -*- coding: utf-8 -*-

from skimage import io
from sklearn.cluster import KMeans
import numpy as np


image = io.imread('test2.jpg')
io.imshow(image)
io.show()

rows = image.shape[0]
cols = image.shape[1]

# reshape行*列;3指的是三个颜色通道
image = image.reshape(image.shape[0]*image.shape[1],3)
kmeans = KMeans(n_clusters = 128, n_init=10, max_iter=200)
kmeans.fit(image)

clusters = np.asarray(kmeans.cluster_centers_,dtype=np.uint8) 
labels = np.asarray(kmeans.labels_,dtype=np.uint8 )  
labels = labels.reshape(rows,cols);

print (clusters.shape)
np.save('codebook_test.npy',clusters)    
io.imsave('compressed_test2.jpg',labels)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gwolr3eK-1642229946255)(笔记图片/image-20220115134008606.png)]

image = io.imread('compressed_test2.jpg')
io.imshow(image)
io.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H37yb22s-1642229946256)(笔记图片/image-20220115134037210.png)]

DBSCAN算法

基本概念:(Density-Based Spatial Clustering of Applications with Noise)
核心对象:若某个点的密度达到算法设定的阈值则其为核心点。(即 r 邻域内点的数量不小于 minPts(自己设置的阈值))

ϵ-邻域的距离阈值:设定的半径r

直接密度可达:若某点p在点q的 r 邻域内,且q是核心点,则p-q直接密度可达。
密度可达:若有一个点的序列q0、q1、…qk,对任意qi-qi-1是直接密度可达的,则称从q0到qk密度可达,这实际上是直接密度可达的“传播”。

密度相连:若从某核心点p出发,点q和点k都是密度可达的,则称点q和点k是密度相连的。

边界点:属于某一个类的非核心点,不能发展下线了
噪声点:不属于任何一个类簇的点,从任何一个核心点出发都是密度不可达的

A:核心对象;B,C:边界点;N:离群点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D2lYUyXO-1642229946257)(笔记图片/image-20220115130404364.png)]

工作流程:参数D:输入数据集;参数ϵ:指定半径;MinPts:密度阈值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HhhtQNIf-1642229946257)(笔记图片/image-20220115130548197.png)]

参数选择:

半径ϵ,可以根据K距离来设定:找突变点K距离:给定数据集P={p(i); i=0,1,…n},计算点P(i)到集合D的子集S中所有点之间的距离,距离按照从小到大的顺序排序,d(k)就被称为k-距离。

MinPts: k-距离中k的值,一般取的小一些,多次尝试

可视化展示网站:https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/

优势:不需要指定簇个数;擅长找到离群点(检测任务);可以发现任意形状的簇;两个参数就够了

劣势:高维数据有些困难(可以做降维);Sklearn中效率很慢(数据削减策略);参数难以选择(参数对结果的影响非常大)

聚类实践

# beer dataset
import pandas as pd
beer = pd.read_csv('data.txt', sep=' ')
beer

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AvcRvpHN-1642229946259)(笔记图片/image-20220115143034816.png)]

# 所有的特征
X = beer[["calories","sodium","alcohol","cost"]]

K-means clustering

from sklearn.cluster import KMeans

# 3个堆聚类
km = KMeans(n_clusters=3).fit(X)
# 2个堆聚类
km2 = KMeans(n_clusters=2).fit(X)
km.labels_

array([0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 0, 0, 0, 1, 0, 0, 1, 2])

beer['cluster'] = km.labels_
beer['cluster2'] = km2.labels_
beer.sort_values('cluster')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u94bZDtG-1642229946259)(笔记图片/image-20220115143132736.png)]

from pandas.tools.plotting import scatter_matrix
%matplotlib inline

cluster_centers = km.cluster_centers_

cluster_centers_2 = km2.cluster_centers_
beer.groupby("cluster").mean()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A7lvZTho-1642229946260)(笔记图片/image-20220115143158240.png)]

beer.groupby("cluster2").mean()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QWdbJ2Wp-1642229946262)(笔记图片/image-20220115143219838.png)]

centers = beer.groupby("cluster").mean().reset_index()
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams['font.size'] = 14
import numpy as np
colors = np.array(['red', 'green', 'blue', 'yellow'])
plt.scatter(beer["calories"], beer["alcohol"],c=colors[beer["cluster"]])

plt.scatter(centers.calories, centers.alcohol, linewidths=3, marker='+', s=300, c='black')

plt.xlabel("Calories")
plt.ylabel("Alcohol")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0lEUhEyr-1642229946262)(笔记图片/image-20220115143306910.png)]

# 观察四个维度
scatter_matrix(beer[["calories","sodium","alcohol","cost"]],s=100, alpha=1, c=colors[beer["cluster"]], figsize=(10,10))
plt.suptitle("With 3 centroids initialized")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kFdmWDlV-1642229946263)(笔记图片/1.png)]

scatter_matrix(beer[["calories","sodium","alcohol","cost"]],s=100, alpha=1, c=colors[beer["cluster2"]], figsize=(10,10))
plt.suptitle("With 2 centroids initialized")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rI6qkir8-1642229946263)(笔记图片/2.png)]

Scaled data

# 标准化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_scaled

array([[ 0.38791334, 0.00779468, 0.43380786, -0.45682969],
[ 0.6250656 , 0.63136906, 0.62241997, -0.45682969],
[ 0.82833896, 0.00779468, -3.14982226, -0.10269815],
[ 1.26876459, -1.23935408, 0.90533814, 1.66795955],
[ 0.65894449, -0.6157797 , 0.71672602, 1.95126478],
[ 0.42179223, 1.25494344, 0.3395018 , -1.5192243 ],
[ 1.43815906, 1.41083704, 1.1882563 , -0.66930861],
[ 0.55730781, 1.87851782, 0.43380786, -0.52765599],
[-1.1366369 , -0.7716733 , 0.05658363, -0.45682969],
[-0.66233238, -1.08346049, -0.5092527 , -0.66930861],
[ 0.25239776, 0.47547547, 0.3395018 , -0.38600338],
[-1.03500022, 0.00779468, -0.13202848, -0.24435076],
[ 0.08300329, -0.6157797 , -0.03772242, 0.03895447],
[ 0.59118671, 0.63136906, 0.43380786, 1.88043848],
[ 0.55730781, -1.39524768, 0.71672602, 2.0929174 ],
[-2.18688263, 0.00779468, -1.82953748, -0.81096123],
[ 0.21851887, 0.63136906, 0.15088969, -0.45682969],
[ 0.38791334, 1.41083704, 0.62241997, -0.45682969],
[-2.05136705, -1.39524768, -1.26370115, -0.24435076],
[-1.20439469, -1.23935408, -0.03772242, -0.17352445]])

km = KMeans(n_clusters=3).fit(X_scaled)
beer["scaled_cluster"] = km.labels_
beer.sort_values("scaled_cluster")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cn75JkRp-1642229946264)(笔记图片/3.png)]

What are the “characteristics” of each cluster?

beer.groupby("scaled_cluster").mean()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xEQzL6U3-1642229946265)(笔记图片/4.png)]

pd.scatter_matrix(X, c=colors[beer.scaled_cluster], alpha=1, figsize=(10,10), s=100)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U5Jvntfl-1642229946265)(笔记图片/5.png)]

聚类评估:轮廓系数(Silhouette Coefficient )

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o97vksVk-1642229946265)(笔记图片/1-16422295080281.png)]

  • 计算样本i到同簇其他样本的平均距离ai。ai 越小,说明样本i越应该被聚类到该簇。将ai 称为样本i的簇内不相似度。
  • 计算样本i到其他某簇Cj 的所有样本的平均距离bij,称为样本i与簇Cj 的不相似度。定义为样本i的簇间不相似度:bi =min{bi1, bi2, …, bik}
  • si接近1,则说明样本i聚类合理
  • si接近-1,则说明样本i更应该分类到另外的簇
  • 若si 近似为0,则说明样本i在两个簇的边界上。
from sklearn import metrics
score_scaled = metrics.silhouette_score(X,beer.scaled_cluster)
score = metrics.silhouette_score(X,beer.cluster)
print(score_scaled, score)

0.1797806808940007 0.6731775046455796

scores = []
for k in range(2,20):
    labels = KMeans(n_clusters=k).fit(X).labels_
    score = metrics.silhouette_score(X, labels)
    scores.append(score)

scores

[0.6917656034079486,
0.6731775046455796,
0.5857040721127795,
0.4355716067265819,
0.4559182167013377,
0.43776116697963124,
0.38946337473125997,
0.39746405172426014,
0.4081599013899603,
0.41282646329875183,
0.3459775237127248,
0.31221439248428434,
0.30707782144770296,
0.31834561839139497,
0.2849514001174898,
0.23498077333071996,
0.1588091017496281,
0.08423051380151177]

plt.plot(list(range(2,20)), scores)
plt.xlabel("Number of Clusters Initialized")
plt.ylabel("Sihouette Score")

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DlpiDtYe-1642229946266)(笔记图片/6.png)]

DBSCAN clustering

from sklearn.cluster import DBSCAN
db = DBSCAN(eps=10, min_samples=2).fit(X)
labels = db.labels_
beer['cluster_db'] = labels
beer.sort_values('cluster_db')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k0eWBU7S-1642229946266)(笔记图片/7.png)]

beer.groupby('cluster_db').mean()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mCe2cYDB-1642229946267)(笔记图片/8.png)]

pd.scatter_matrix(X, c=colors[beer.cluster_db], figsize=(10,10), s=100)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1H1rK0Xa-1642229946268)(笔记图片/9.png)]

问题解决

ImportError: cannot import name ‘_validate_lengths’ from 'numpy.lib.arraypad’

https://blog.csdn.net/weixin_48620718/article/details/114556717

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值