基本概念:
“物以类聚,人以群分”,所谓的聚类,就是将样本划分为由类似的对象组成的多个类的过程。聚类后,我们可以更加准确的在每个类中单独使用统计模型进行估计、分析或预测;也可以探究不同类之间的相关性和主要差异。
聚类和分类的区别:分类是已知类别的,聚类未知。
算法描述:
1、假定我们要对N个样本观测做聚类,要求聚为K类,首先选择K个点作为初始中心点;
2、接下来,按照距离初始中心点最小的原则,把所有观测分到各中心点所在的类中;
3、每类中有若干个观测,计算K个类中所有样本点的均值,作为第二次迭代的K个中心点;
4、然后根据这个中心重复第2、3步,直到收敛(中心点不再改变或达到指定的迭代次数),聚类过程结束。
#K-means算法
from pylab import *
from numpy import *
import codecs
import matplotlib.pyplot as plt
data=[]
labels=[]
#数据读取
with codecs.open("data.txt","r") as f:
for line in f.readlines():
x,y,label=line.strip().split('\t')
data.append([float(x),float(y)])
labels.append(float(label))
datas=array(data)
k=3#聚类数目
#计算欧式距离
def distance(x1,x2):
return sqrt(sum(power(x1-x2,2)))
#随机初始化类中心
def randcenter(set,k):
dim=shape(set)[1]
init_cen=zeros((k,dim))
for i in range(dim):
min_i=min(set[:,i])
range_i=float(max(set[:,i]) - min_i)
init_cen[:,i]=min_i + range_i*random.rand(k)
return init_cen
#主程序
def Kmeans(dataset,k):
row_m=shape(dataset)[0]
cluster_assign=zeros((row_m,2))
center=get_centroids(dataset,k)
change=True
while change:
change=False
for i in range(row_m):
mindist=inf
min_index=-1
for j in range(k):
distance1=distance(center[j,:],dataset[i,:])
if distance1<mindist:
mindist=distance1
min_index=j
if cluster_assign[i,0] != min_index:
change=True
cluster_assign[i,:]=min_index,mindist**2
for cen in range(k):
cluster_data=dataset[nonzero(cluster_assign[:,0]==cen)]
center[cen,:]=mean(cluster_data,0)
return center ,cluster_assign
cluster_center,cluster_assign=Kmeans(datas,k)
print(cluster_center)
#设置x,y轴的范围
xlim(0, 10)
ylim(0, 10)
#做散点图
f1 = plt.figure(1)
plt.scatter(datas[nonzero(cluster_assign[:,0]==0),0],datas[nonzero(cluster_assign[:,0]==0),1],marker='o',color='r',label='0',s=30)
plt.scatter(datas[nonzero(cluster_assign[:,0]==1),0],datas[nonzero(cluster_assign[:,0]==1),1],marker='+',color='b',label='1',s=30)
plt.scatter(datas[nonzero(cluster_assign[:,0]==2),0],datas[nonzero(cluster_assign[:,0]==2),1],marker='*',color='g',label='2',s=30)
plt.scatter(cluster_center[:,1],cluster_center[:,0],marker = 'x', color = 'm', s = 50)
plt.show()
K-means运行结果:
类中心:
[[ 7.16504475 7.12121176]
[ 2.94805141 2.84547461]
[ 4.92859254 4.93144926]]
二、 K-Means++
K-Means++算法在初始化聚类中心时的基本原则是使聚类中心之间的相互距离尽可能的远。
算法步骤:
1、在数据集中随机选择一个样本作为第一个初始化聚类中心;
2、计算样本中每一个样本点与已经初始化的聚类中心的距离,并选择其中最短的距离;
3、以概率选择距离最大的点作为新的聚类中心;
4、重复2、3步直至选出k个聚类中心;
5、对k个聚类中心使用K-Means算法计算最终的聚类结果。
通过上述的步骤可知,K-Means++算法和K-Means算法最本质的区别在与聚类中心的初始化
#K-means++
from pylab import *
from numpy import *
import codecs
import matplotlib.pyplot as plt
data=[]
labels=[]
#数据读取
with codecs.open("data.txt","r") as f:
for line in f.readlines():
x,y,label=line.strip().split('\t')
data.append([float(x),float(y)])
labels.append(float(label))
datas=array(data)
#计算欧氏距离
def distance(x1,x2):
return sqrt(sum(power(x1-x2,2)))
#对一个样本找到与该样本距离最近的聚类中心
def nearest(point, cluster_centers):
min_dist = inf
m = np.shape(cluster_centers)[0] # 当前已经初始化的聚类中心的个数
for i in range(m):
# 计算point与每个聚类中心之间的距离
d = distance(point, cluster_centers[i, ])
# 选择最短距离
if min_dist > d:
min_dist = d
return min_dist
#选择尽可能相距较远的类中心
def get_centroids(dataset, k):
m, n = np.shape(dataset)
cluster_centers = np.zeros((k , n))
index = np.random.randint(0, m)
cluster_centers[0,] = dataset[index, ]
# 2、初始化一个距离的序列
d = [0.0 for _ in range(m)]
for i in range(1, k):
sum_all = 0
for j in range(m):
# 3、对每一个样本找到最近的聚类中心点
d[j] = nearest(dataset[j, ], cluster_centers[0:i, ])
# 4、将所有的最短距离相加
sum_all += d[j]
# 5、取得sum_all之间的随机值
sum_all *= random.rand()
# 6、获得距离最远的样本点作为聚类中心点
for j, di in enumerate(d):
sum_all=sum_all - di
if sum_all > 0:
continue
cluster_centers[i,] = dataset[j, ]
break
return cluster_centers
#主程序
def Kmeans(dataset,k):
row_m=shape(dataset)[0]
cluster_assign=zeros((row_m,2))
center=get_centroids(dataset,k)
change=True
while change:
change=False
for i in range(row_m):
mindist=inf
min_index=-1
for j in range(k):
distance1=distance(center[j,:],dataset[i,:])
if distance1<mindist:
mindist=distance1
min_index=j
if cluster_assign[i,0] != min_index:
change=True
cluster_assign[i,:]=min_index,mindist**2
for cen in range(k):
cluster_data=dataset[nonzero(cluster_assign[:,0]==cen)]
center[cen,:]=mean(cluster_data,0)
return center ,cluster_assign
cluster_center,cluster_assign=Kmeans(datas,3)
print(cluster_center)
#设置x,y轴的范围
xlim(0, 10)
ylim(0, 10)
#做散点图
f1 = plt.figure(1)
plt.scatter(datas[nonzero(cluster_assign[:,0]==0),0],datas[nonzero(cluster_assign[:,0]==0),1],marker='o',color='r',label='0',s=30)
plt.scatter(datas[nonzero(cluster_assign[:,0]==1),0],datas[nonzero(cluster_assign[:,0]==1),1],marker='+',color='b',label='1',s=30)
plt.scatter(datas[nonzero(cluster_assign[:,0]==2),0],datas[nonzero(cluster_assign[:,0]==2),1],marker='*',color='g',label='2',s=30)
plt.scatter(cluster_center[:,1],cluster_center[:,0],marker = 'x', color = 'm', s = 50)
plt.show()
三、DBSCAN聚类算法
DBSCAN是一种基于密度的聚类算法,这类密度聚类算法一般假定类别可以通过样本分布的紧密程度决定。同一类别的样本,他们之间的紧密相连的,也就是说,在该类别任意样本周围不远处一定有同类别的样本存在。通过将紧密相连的样本划为一类,这样就得到了一个聚类类别。通过将所有各组紧密相连的样本划为各个不同的类别,则我们就得到了最终的所有聚类类别结果。
from sklearn import datasets
import numpy as np
import random
import matplotlib.pyplot as plt
import time
import copy
def find_neighbor(j, x, eps):
N = list()
for i in range(x.shape[0]):
temp = np.sqrt(np.sum(np.square(x[j]-x[i]))) # 计算欧式距离
if temp <= eps:
N.append(i)
return set(N)
def DBSCAN(X, eps, min_Pts):
k = -1
neighbor_list = [] # 用来保存每个数据的邻域
omega_list = [] # 核心对象集合
gama = set([x for x in range(len(X))]) # 初始时将所有点标记为未访问
cluster = [-1 for _ in range(len(X))] # 聚类
for i in range(len(X)):
neighbor_list.append(find_neighbor(i, X, eps))
if len(neighbor_list[-1]) >= min_Pts:
omega_list.append(i) # 将样本加入核心对象集合
omega_list = set(omega_list) # 转化为集合便于操作
while len(omega_list) > 0:
gama_old = copy.deepcopy(gama)
j = random.choice(list(omega_list)) # 随机选取一个核心对象
k = k + 1
Q = list()
Q.append(j)
gama.remove(j)
while len(Q) > 0:
q = Q[0]
Q.remove(q)
if len(neighbor_list[q]) >= min_Pts:
delta = neighbor_list[q] & gama
deltalist = list(delta)
for i in range(len(delta)):
Q.append(deltalist[i])
gama = gama - delta
Ck = gama_old - gama
Cklist = list(Ck)
for i in range(len(Ck)):
cluster[Cklist[i]] = k
omega_list = omega_list - Ck
return cluster
X1, y1 = datasets.make_circles(n_samples=2000, factor=.6, noise=.02)
X2, y2 = datasets.make_blobs(n_samples=400, n_features=2, centers=[[1.2, 1.2]], cluster_std=[[.1]], random_state=9)
X = np.concatenate((X1, X2))
eps = 0.08
min_Pts = 10
begin = time.time()
C = DBSCAN(X, eps, min_Pts)
end = time.time()
plt.figure()
plt.scatter(X[:, 0], X[:, 1], c=C)
plt.show()