K-Mean聚类、DBSCAN聚类原理与实现

聚类问题是一种无监督问题,聚类问题的目的是将相似的对象分在一组,这类算法的难点在:1.如何评估聚类的结果 2.如何调参

K-Means聚类算法

基本概念:
要得到的簇的个数:需要指定k值
质心:均值,即向量各维度的平均值
距离的度量:通常采用欧式距离和余弦相似度(均需要先对数据做标准化处理)

优化目标:

工作流程:
1.指定k
2.随机选取k个点作为质心
3.计算每一个点到质心的距离并将该点分入距离最近的质心的那一类
4.计算新的类质心
5.再次计算每一个点到每一个质心的距离并分类
6.计算新的类质心
7.直至质心基本不再变化

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

劣势:
1.k值难以确定
2.复杂度与样本数呈线性关系
3.很难发现任意形状的簇(最大的问题)
4.初始质心的选择对结果的影响很大(针对这种问题需要做多次取平均)


DBSCAN算法

基本概念:
DBSCAN:基于密度的,带有噪音的聚类(Density-Based Spatial Clustering of Applications with Noise)
核心对象:若某个点的密度达到算法设定的阈值则其为核心点(即r领域内点的数量不少于minPts)
ξ领域的距离阈值:设定的半径r
直接密度可达:若某点p在点q的领域内,且q是核心点,则p-q是直接密度可达的(不对称关系)
密度可达:有一个点的序列a,b,c,d,e,任意相邻点是直接密度可达的,则称从a到e是密度可达的,这实际上是直接密度可达的传播(不对称关系)
密度相连:若从某核心q出发,点p和点k都是密度可达的,则称点q和k是密度相连的(对称关系)
边界点:属于某一类的非核心点,不能发展下线了
噪音点:不属于任何一个类簇的点,从任何一个核心出发都是密度不可达的

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

流程:

标记所有对象为unvisited
随即标记一个对象p为visited
if p的ξ邻域内有多于MinPts个对象:
	创建一个新簇C,并把p添加到C
	令N为P邻域中所有对象的集合
	for N中的每个点q:
		if q是unvisited:
			标记为visited
				如果q的ξ邻域至少有MinPts个对象,则将这些对象添加到N
				将q添加到C
输出C的集合作为聚类结果
输出所有visited且不属于任何簇的点作为噪音点序列

参数选择:
半径ξ:可以根据k距离来设定(找突变点)
k距离:给定数据集 P = { p ( i ) ; i = 0 , 1 , … n } P=\{p(i) ; i=0,1, \dots n\} P={p(i);i=0,1,n},计算 p ( i ) p(i) p(i)到集合D的子集S中所有点之间的距离,距离按照从小到大的顺序排列, d ( k ) d(k) d(k)就被称为k距离
MinPts:k距离中k的值,一般取小一些

优势:
不需指定簇个数
可以发现任意形状的簇
擅长找到离群点(利用DBSCN算法做数据的离群点检测,也可以有较好的效果)
只需要指定两个参数

劣势
高维数据有些困难(可以做降维)
参数难以选择(参数对结果的影响非常大)
sklearn中执行效率很低(可以做数据消减)

聚类效果评估
通过轮廓系 s ( i ) s(i) s(i)数评估聚类效果

步骤:
1.计算样本i到同簇其他样本的平均距离ai,ai越小说明样本i越应该被聚到该簇,将 a ( i ) a(i) a(i)称为样本i的簇内不相似度
2.计算样本i到其他簇Cj的所有样本平局距离bij,称为样本i与簇Cj的不相似度,定义为样本i的簇间不相似度; b i = min ⁡ { b i 1 , b i 2 , … , b i k } bi =\min \{\mathrm{bi} 1, \mathrm{bi} 2, \ldots, \mathrm{bik}\} bi=min{bi1,bi2,,bik} s ( i ) = { 1 − a ( i ) b ( i ) , a ( i ) < b ( i ) 0 , a ( i ) = b ( i ) b ( i ) a ( i ) − 1 , a ( i ) > b ( i ) s(i)=\left\{\begin{array}{cc}{1-\frac{a(i)}{b(i)},} & {a(i)b(i)}\end{array}\right. s(i)=1b(i)a(i),0,a(i)b(i)1,a(i)<b(i)a(i)=b(i)a(i)>b(i)

s ( i ) s(i) s(i)接近1,则说明样本i聚类合理
s ( i ) s(i) s(i)接近-1,则说明样本i更应该分到别的簇
s ( i ) s(i) s(i)接近0,则说明样本i在两个簇的边界上

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans


#读取数据-----------------------------------------------------------------------------------------------------------
data = pd.read_csv("data.txt", sep=" ")
print(data.head())
X = data[["calories", "sodium", "alcohol", "cost"]]



#利用sklearn实现KMean聚类-----------------------------------------------------------------------------------------------------------
km = KMeans(n_clusters=3).fit(X)
km2 = KMeans(n_clusters=2).fit(X)

data["cluster"] = km.labels_
data["cluster2"] = km2.labels_

data = data.sort_values("cluster").reset_index()  # 按照cluster的大小排序并重新分配索引






#标准化后再次实现-----------------------------------------------------------------------------------------------------------
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
km = KMeans(n_clusters=3).fit(X_scaled)

data["scaled_cluster"] = km.labels_
data = data.sort_values("scaled_cluster").reset_index()





#绘图-----------------------------------------------------------------------------------------------------------
centers1 = data.groupby("cluster2").mean()
centers2 = data.groupby("cluster").mean()
centers3 = data.groupby("scaled_cluster").mean()

fig = plt.figure()
ax1 = fig.add_subplot(2, 2, 1)
ax2 = fig.add_subplot(2, 2, 2)
ax3 = fig.add_subplot(2, 2, 3)
plt.rcParams['font.size'] = 14
colors = np.array(['red', 'green', 'blue', 'yellow'])

ax1.scatter(data['calories'], data['alcohol'], c=colors[data['cluster2']])  # 注意这种写法
ax2.scatter(data['calories'], data['alcohol'], c=colors[data['cluster']])
ax3.scatter(data['calories'], data['alcohol'], c=colors[data['scaled_cluster']])

ax1.scatter(centers1.calories, centers1.alcohol, linewidth=3, marker='+', s=300, c='black')
ax2.scatter(centers2.calories, centers2.alcohol, linewidth=3, marker='+', s=300, c='black')
ax3.scatter(centers3.calories, centers3.alcohol, linewidth=3, marker='+', s=300, c='black')

plt.show()






#绘制散点图矩阵-----------------------------------------------------------------------------------------------------------
from pandas.plotting import scatter_matrix

cluster_centers = km.cluster_centers_
cluster_centers_2 = km2.cluster_centers_

print(cluster_centers)
print(cluster_centers_2)

scatter_matrix(data[["calories", "sodium", "alcohol", "cost"]], s=100, alpha=1, c=colors[data["cluster"]],
               figsize=(10, 10))
plt.suptitle("With 3 centroids initialized")
plt.show()

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




#计算轮廓系数-----------------------------------------------------------------------------------------------------------
from sklearn import metrics

score_scaled = metrics.silhouette_score(X, data.scaled_cluster)
score = metrics.silhouette_score(X, data.cluster)
print(score_scaled, score)

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

print(score)
plt.plot(list(range(2, 20)), scores)
plt.show()

DBSCAN算法实现

import pandas as pd

data = pd.read_csv("data.txt", sep=" ")

X = data[["calories", "sodium", "alcohol", "cost"]]
from sklearn.cluster import DBSCAN

db = DBSCAN(eps=10, min_samples=2).fit(X)
labels = db.labels_
data["cluster_db"] = labels
data = data.sort_values("cluster_db").reset_index()
print(data)

你可能感兴趣的:(机器学习算法)