fuli2020

2020-08-14   阅读量: 890

无监督聚类算法

扫码加入数据分析学习群

无监督的算法在训练的时候只需要特征矩阵X,不需要标签。无监督学习的代表算法有聚类算法、降维算法

聚类分析仅根据在数据中发现的描述对象及其关系的信息,将数据对象分组。其目标是,组内的对象相互之间是相似的(相关的),而不同组中的 对象是不同的(不相关的)。组内的相似性(同质性)越大,组间差别越大,聚类就越好。

Kmeans计算过程:

创建k个点作为初始质心(通常是随机选择)

当任意一个点的簇分配结果发生改变时:

对数据集中的每个点:

对每个质心:

计算质心与数据点之间的距离

将数据点分配到距其最近的簇

对每个簇,计算簇中所有点的均值并将均值作为新的质心

直到簇不再发生变化或者达到最大迭代次数


对于一个簇来说,所有样本点到质心得距离之和越小,我们就认为这个簇中的样本越相似,簇内差异就越小。⽽而距离的衡量方法有多种,令x 表示簇中的⼀一个样本点, μ表示该簇中的质心,n表示每个样本点中的特征数目,i表示组成点 的每个特征,则该样本点到质心的距离可以由以下距离来度量。


图片.png


图片.png


轮廓系数是最常用的聚类算法的评价指标,它是对每个样本来定义的,它能够同时衡量:

(1)样本与其自身所在的簇中的其他样本的相似度a,等于样本与同一簇中所有其他点之间的平均距离

(2)样本与其他簇中的样本的相似度b,等于样本与下一个最近的簇中的所有点之间的平均距离

根据聚类的要求“簇内差异小,簇外差异大”,我们希望b永远大于a,并且大的越多越好

单个样本的轮廓系数计算为:

图片.png


图片.png


很容易理解轮廓系数范围是(-1,1),其中值越接近1表示样本与自己所在的簇中的样本很相似,并且与其他簇中的样本不相似,当样本点与簇外的样本更相似的时候,轮廓系数就为负。当轮廓系数为0时,则代表两个簇中的样本相似度一致,两个簇本应该是一个簇。


如果簇中的大多数样本具有比较高的轮廓系数,则簇会有较高的总轮廓系数,则整个数据集的平均轮廓系数越高,则聚类是合适的。如果许多样本点具有低轮廓系数甚至负值,则聚类是不合适的,聚类的超参数K可能设定得太大或太小。


在sklearn中,我们使用模板metrics中的类silhouette_score来计算轮廓系数,它返回的是一个数据集中,所有样本的轮廓系数的均值。但我们还有同在metrics模块中的silhouette_sample,它的参数与轮廓系数一致,但返回的是数据集中每个样本自己的轮廓系数。


DBSCAN基本原理

密度的基于中心的方法使得我们可以将点分类为:

(1)核心点:这些点在基于密度的簇内部。点的领域由距离函数和用户指定的距离参数Eps决定。核心点的定义是,如果该点的给定领域内的点的个数超过给定的阈值MinPts,其中MinPts也是一个用户指定的参数。

(2)边界点

(3)噪声点


任意两个足够靠近(相互之间的距离在Eps之内)的核心点将放在同一个簇中,同样,任何与核心点足够靠近的边界点也放到与核心点相同的簇中,噪声点被丢弃。

DBSCAN算法:

(1)将所有点标记为核心点、边界点和噪声点

(2)删除噪声点

(3)为距离在Eps之内的所有核心点之间赋予一条边

(4)每个彼此联通的核心点组成一个簇

(5)将每个边界点指派到一个与之关联的核心点的簇当中


#导入一些包

import numpy as np

import pandas as pd

import matplotlib as mpl

import matplotlib.pyplot as plt

%matplotlib inline

from sklearn.datasets import make_blobs


#模拟出一些数据集出来

r=4

k=3

x,y=make_blobs(n_samples=300,

cluster_std=[0.3,0.3,0.3],

centers=[[0,0],[1,1],[-1,1]],

random_state=r

)

sim_data=pd.DataFrame(x,columns=['x1','x2'])

datasets=sim_data.copy()

plt.scatter(sim_data['x1'],sim_data['x2'])


#手动生成随机的k个质心点出来

centers=[

[-1.5,0.5],

[1.5,0],

[1,-0.5]

]


centers=pd.DataFrame(centers,

columns=['x1','x2'],

index=['blue','green','red'])


#取出其中一个质心点,尝试计算每一个点到这个质心点的距离

tmp_centers=centers.loc['blue',:]


#直接使用数据-质心点的方式尝试计算每个点到质心点的距离

np.power(datasets-tmp_centers,2).sum(axis=1)


l=[]

for i in centers.index:

tmp_centers=centers.loc[i,:]

l.append(np.power(datasets-tmp_centers,2).sum(axis=1))


d_to_centers=pd.concat(l,axis=1)

d_to_centers.columns=centers.index

curr_group=d_to_centers.idxmin(axis=1)


#当每一个点有一个新的簇的时候,就可以计算新的质心点的位置了

tmp_data=datasets.copy()

tmp_data['curr_group']=curr_group

centers=tmp_data.groupby('curr_group').mean()


#创建一个空的SSE_list,用来存SSE的

#初始化质心点

centers=[

[-1,0.5],

[1,0],

[1,-1]

]


centers=pd.DataFrame(centers,

columns=['x1','x2'],

index=['blue','green','red'])


SSE_list=[]

SSE=-1


#开始迭代

while True:

#保持质心点不变,更新类别

l=[]

#记录上一次迭代中centers,SSE的值

last_centers=centers.copy()

last_SSE=SSE


for i in centers.index:

tmp_centers=centers.loc[i,:]

l.append(np.power(datasets-tmp_centers,2).sum(axis=1))

d_to_centers=pd.concat(l,axis=1)

SSE=d_to_centers.min(axis=1).sum()

SSE_list.append(SSE)

if SSE==last_SSE:

break


d_to_centers.columns=centers.index

curr_group=d_to_centers.idxmin(axis=1)


#保持类别不变,更新质心点

tmp_data=datasets.copy()

tmp_data['curr_group']=curr_group

centers=tmp_data.groupby('curr_group').mean()


plt.scatter(datasets['x1'],datasets['x2'],c=curr_group)

plt.scatter(centers.iloc[:,0],centers.iloc[:,1],c='black',marker='x')



#所有代码和函数集合起来

def initial_centers(datasets,k=3):

cols=datasets.columns

data_content=datasets.loc[:,cols!='label']

range_info=data_content.describe().loc[['min','max']]

k_randoms=[np.random.uniform(range_info[i]['min'],

range_info[i]['max'],k)

for i in range_info.columns]

centers=pd.DataFrame(k_randoms,index=range_info.columns)

return centers.T


def cal_distant(dataset,centers):

data=dataset.loc[:,dataset.columns!='label']

d_to_centers=[np.power(data-centers.loc[i],2).sum(axis=1)

fro i in centers.index]

return pd.concat(d_to_centers,axis=1)


def iterate(dataset,centers):

d_to_centers=cal_distant(dataset,centers)

curr_group=d_to_centers.idxmin(axis=1)

SSE=d_to_centers.min(axis=1).sum()

centers=dataset.loc[:,dataset.columns !='label'].groupby(curr_group).mean()

return curr_group,SSE,centers


def Kmeans_regular(data,k=3):

SSE_list=[0]

centers=initial_centers(data,k=k)

while True:

curr_group,SSE,centers=iterate(data,centers)

if SSE_list[-1]==SSE:

break

SSE_list.append(SSE)

return curr_group,SSE_list,centers


#DBSCAN

from sklearn.datasets import make_moons

X,y=make_moons(200,noise=0.05,random_state=0)

plt.scatter(X[:,0],X[:,1],c=y)


from sklearn.cluster import KMeans

kmeans=KMeans(n_cluster=2)

kmeans.fit(X)

kmeans.labels_

centers=kmeans.cluster_centers_


#尝试使用轮廓系数来查看

from sklearn.cluster import KMeans

from sklearn.metrics import silhouette_score,silhouette_samples


import matplotlib.pyplot as plt

import matplotlib.cm as cm

import numpy as np


from sklearn.datasets import make_blobs


#创建数据集

X,y=make_blobs(n_sample=500,n_features=2,centers=4,random_state=1)

plt.scatter(X[:,0],X[:,1],marker='o',s=8)

data=pd.DataFrame(X)

data['label']=y


#先设定我们要分成的簇数

n_clusters=4

#创建一个画布,画布上共有一行两列两个图

fig,(ax1,ax2)=plt.subplots(1,2)


#画布尺寸

fig.set_size_inches(18,7)


ax1.set_xlim([-0.1,1])

ax1.set_ylim([0,X.shape[0]+(n_cluster+1)*10])


#开始建模,调用聚类好的标签

clusterer=KMeans(n_clusters=n_clusters,random_state=10).fix(X)

cluster_labels=clusterer.labels_


silhouette_avg=silhouette_score(X,cluster_labels)

sample_silhouette_values=silhouette_sample(X,cluster_labels)


y_lower=10


for i in range(n_clusters):

ith_cluster_silhouette_values=sample_silhouette_values[cluster_labels==i]

ith_cluster_silhouette_values.sort()

size_cluster_i=ith_cluster_silhouette_values.shape[0]


y_upper=y_lower+size_cluster_i

color=cm.nipy_spectral(float(i)/n_clusters)


ax1.fill_betweenx(np.arange(y_lower,y_upper),

ith_cluster_silhouette_values,

facecolor=color,

alpha=0.7)


#text的参数为(要显示编号的位置的横坐标,要显示标号的位置的纵坐标,要显示的编号内容)

ax1.text(-0.05,y_lower+0.5*size_cluster_i,str(i))

y_lower=y_upper+10


ax1.set_title('The silhouette plot for the various clusters.')

ax1.set_xlabel('The silhouette coefficient values')

ax1.set_ylabel('Cluster label')


ax1.axvline(x=silhouette_avg,color='red',linestyle='--')


#让y轴不显示任何刻度

ax1.set_yticks([])


#让x轴上的刻度显示为我们规定的列表

ax1.set_xticks([-0.1,0,0.2,0.4,0.6,0.8,1])


colors=cm.nipy_spectral(cluster_labels.astype(float)/n_clusters)


ax2.scatter(X[:,0],X[:,1],marker='o',s=8,c=colors)


centers=clusterer.cluster_centers_

ax2.scatter(centers[:,0],centers[:,1],marker='x',c='red',alpha=1,s=200)


ax2.set_title("The visualization of the clustered data.")
ax2.set_xlabel("Feature space for the 1st feature")
ax2.set_ylabel("Feature space for the 2nd feature")


#为整个图设置标题

plt.suptitle(("Silhouette analysis for KMeans clustering on sample data "
"with n_clusters = %d" % n_clusters),
fontsize=14, fontweight='bold')
plt.show()




添加CDA认证专家【维克多阿涛】,微信号:【cdashijiazhuang】,提供数据分析指导及CDA考试秘籍。已助千人通过CDA数字化人才认证。欢迎交流,共同成长!
47.5540 3 3 关注作者 收藏

评论(0)


暂无数据

推荐课程