核心对象:若某个点的密度达到算法设定的阈值则其为核心点(即r领域内点的数量不小于minPts)
领域的距离阈值:设定的半径r
直接密度可达:若某点p在点q的r领域内,且q是核心点则p-q直接密度可达
密度可达:若有一个点的序列q0,q1,…,qk,对任意qi-qi-1是直接密度可达的,则称从q0到qk密度可达,这实际上是直接密度可达的传播
参数D:输入数据集
参数:指定半径
MinPts:密度阈值
1.标记所有对象为unvisited
2.Do
3.随机选择一个unvisited对象p
4.标记p为visited
5.If p的领域至少有MinPts个对象
6. 创建一个新簇C,并把p添加到C
7. 令N为p的领域中的对象集合
8. For N中每个点p
9. If p是unvisited
10. 标记p为visited
11. if p的领域至少有MinPts个对象,把这些对象添加到N
12. 如果p还不是任何簇的成员,把p添加到C
13. End for
14. 输出C
15.Else标记p为噪声
16.Until没有标记为unvisited的对象
半径,可以根据K距离来设定:找突变点
K距离:给定数据集P={p(i);i=0,1,…n},计算点P(i)到集合D的子集S中所有点之间的距离,距离按照从小到大的顺序排序,d(k)就被称为k距离
MinPts:k-距离中k的值,一般取小一些,多次尝试
不需要指定簇的个数
可以发现任意形状的簇
擅长找到离群点(检测任务)
两个参数就够了
高维数据有些困难(可以做降维)
参数难以选择(参数对结果的影响非常大)
Sklearn中效率很慢(数据削减策略)
In[1]: import pandas as pd
beer = pd.read_csv('data.txt', sep=' ')
# 原本的数据很密集,sep参数可以让它们分开
beer
In[2]: X = beer[['calories', 'sodium', 'alcohol', 'cost']]
# 取出所有特征列,聚类是无监督算法,没有标签
用K-means方法来做(K-means clustering)
In[3]: from sklearn.cluster import KMeans
km = KMeans(n_clusters=3).fit(X)
km2 = KMeans(n_clusters=2).fit(X)
# n_clusters参数是指定分成多少个簇
In[4]: km.labels_
# 分好类的标签
In[5]: beer['cluster'] = km.labels_
beer['cluster2'] = km2.labels_
# 增加两列标签列
beer.sort_values('cluster')
# 按cluster列进行排序
In[6]: from pandas.tools.plotting import scatter_matrix
%matplotlib inline
cluster_centers = km.cluster_centers_
cluster_centers_2 = km2.cluster_centers_
In[7]: beer.groupy('cluster').mean()
# groupy('cluster')是按cluster分类,然后求出每个类中每个特征的平均值
In[8]: beer.groupy('cluster2').mean()
In[9]: centers = beer.groupy('cluster').mean().reset_index()
# 增加索引列
In[10]: %matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams['font.size'] = 14
# 设置字体大小
In[11]: import numpy as np
colors = np.array(['red', 'green', 'blue', 'yellow'])
In[12]: plt.scatter(beer['calories'], beer['alcohol'], c=colors[beer['cluster']])
# 以calories,alcohol做散点图,以cluster列为标志选择颜色
plt.scatter(centers.calories, centers.alcohol, linewidth=3, marker='+', s=300, c='black')
# 画出每个簇的中心点,用+号标记
In[18]: scatter_matrix(beer[['calories', 'sodium', 'alcohol', 'cost']], c=colors[beer['cluster']], s=100, alpha=1, figsize=(10,6))
# 观察每两个特征之间的关系,看一下不同的图大的聚类结果
plt.suptitle('With 3 centroids initialized')
In[18]: scatter_matrix(beer[['calories', 'sodium', 'alcohol', 'cost']], c=colors[beer['cluster2']], s=100, alpha=1, figsize=(10,6))
plt.suptitle('With 2 centroids initialized')
# 聚成两类的图像
在数据预处理的情况下看一下有何不同(数据标准化)
In[20]: from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_scaled
In[21]: km = KMeans(n_clusters=3).fit(X_scaled)
# 再数据标准化后再聚类
In[22]: beer['scaled_cluster'] = km.labels_
beer.sort_values('scaled_cluster')
In[23]: scatter_matrix(X, c=colors[beer.scaled_cluster], alpha=1, s=100, figsize=(10, 10))
聚类评估:轮廓系数(Silhouette Coefficient)
计算样本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在两个簇的边界上
In[25]: from sklearn import metrics
score_scaled = metrics.silhouette_score(X, beer.scaled_cluster)
score = metrics.silhouette_score(X, beer.cluster)
# 计算出轮廓系数,传入的参数为数据集和经过KMeans分成的簇
print(score_scaled, score)
In[26]: scores = []
for k in range(2, 20):
km = KMeans(n_clusters=k).fit(X)
labels = km.labels_
score = metrics_silhouette_score(X, labels)
scores.append(score)
scores
# 测试一下分成的簇的不同所得出的轮廓系数
In[27]: plt.plot(list(range(2, 20)), scores)
plt.xlabel('Number of Clusters Initialized')
plt.ylabel('Sihouette Score')
用DBSCAN方法来做(DBSCAN clustering)
In[28]: from sklearn.cluster import DBSCAN
db = DBSCAN(eps=10, min_samples=2)
# eps是半径,min_samples是每个区域的最小点数
In[29]: labels = db.labels_
In[30]: beer['cluster_db'] = labels_
beer.sort_values('cluster_db')
# 输出按cluster_db列排序后的结果
beer
# 输出没有排序的结果
In[31]: beer.groupby('cluster_db').mean()
In[32]: scatter_matrix(X, c=colors[beer.cluster_db], figsize(10,10), s=100)
In[33]: score = metrics.silhouette_score(X, beer.cluster_db)
score
# 这里的beer也是未经排序的,若在In[30]中有beer=beer.sort_values('cluster_db')才会把排序后的结果保存下来
如果感兴趣的话,也可以进入我的个人博客观看更多的文章:https://www.fatalblow.top/