我对聚类算法的理解:将一堆,无划分的数据,通过它们之间的相似度进行划分。(简单粗暴^。^)
根据上面的理解,K-means算法就能知名晓意了:就是将一堆无划分的样本数据,定义需要划分为K堆,然后通过每个样本数据点与中心点间的距离进行归簇。(在k-means中需要在划分前需指定中心点,这是它的缺点)
下面是官方一点的说法:
K-Means算法是最为经典的基于划分的聚簇方法,是十大经典数据挖掘算法之一。简单的说K-Means就是在没有任何监督信号的情况下将数据分为K份的一种方法。聚类算法就是无监督学习中最常见的一种,给定一组数据,需要聚类算法去挖掘数据中的隐含信息。聚类算法的应用很广:顾客行为聚类,google新闻聚类等。K值是聚类结果中类别的数量。
其实k-means算法真的简单,先不说代码,就说原理,你只要仔细理解一遍,用自己的语言总结一下,慢慢就能摸索出代码。我刚学时参考了一篇博客,找不到连接了,很感谢他写的很简单,理解的很快,过了一段时间用自己的思路将代码摸索了出来。直接看完整代码:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
global K
global N
global spot
global unite
global mean
global count
def cluster(): #划分每个点一个到簇
global unite
unite = [] #这里千万注意,需要每次都定义,否则会重复添加长度。当下一次运行cluster函数时才会重置unite列表
for i in range(K):
unite.append([])
for i in range(len(spot)):
max_max = np.iinfo(np.int32).max #预定义一个极大值,用于比较
flag = -1
for j in range(K):
n = (spot[i][0]-mean[j][0])**2+(spot[i][1]-mean[j][1])**2
if(n<max_max):
max_max = n
flag = j
unite[flag].append(spot[i])
for i in range(K):
print("第{}簇:{}".format(i,unite[i]))
def square_d():
global count
sum_E = 0
for i in range(len(unite)):
for j in range(len(unite[i])):
sum_E += ((unite[i][j][0]-mean[i][0])**2 + (unite[i][j][1]-mean[i][1])**2)
count +=1
return sum_E
def remean():
for i in range(len(unite)):
sum_x = 0
sum_y = 0
for j in range(len(unite[i])):
sum_x += unite[i][j][0]
sum_y += unite[i][j][1]
# if(len(unite[i]) == 0): #分母不为0,如果前面判断了中心值不一样可以省略
# mean[i] = (0,0)
# else:
# mean[i] = (sum_x/len(unite[i]),sum_y/len(unite[i]))
mean[i] = (sum_x/len(unite[i]),sum_y/len(unite[i])) #根据均值,重新定义的中心值
def show():
#样本数据横坐标列表
xx = []
for i in range(K):
xx.append([])
#样本数据纵坐标列表
yy = []
for i in range(K):
yy.append([])
#使用样本坐标,绘制散点图
for i in range(K):
for j in range(len(unite[i])):
xx[i].append(unite[i][j][0])
for j in range(len(unite[i])):
yy[i].append(unite[i][j][1])
plt.scatter(xx[i],yy[i],label=i)
plt.scatter(mean[i][0],mean[i][1],label=i)
plt.legend()
#显示散点图
plt.show()
if __name__=="__main__":
K = 4 #聚类数 手动设置
N = 30 #样本数 手动设置
spot = [] #样本列表
for i in range(N):
spot.append((np.random.randint(50),np.random.randint(50))) #50是我给它定义的范围
unite = [] #每个点归属簇
mean = [] #每个簇的中心值
set_t = set()
while(1): #虽然两行代码就可以搞定这个选值,但是我建议使用集合,防止重复值
d = np.random.randint(N) #当然如果你有更简单的方法除外,就我觉得使用集合比较简单
set_t.add(d)
if(len(set_t)==K):
for i in set_t:
mean.append(spot[i])
break
count = 0
m = []
for i in range(2): #首先两次循环,得出两个比较的平方误差
cluster() #聚类
temp = square_d() #计算平方误差
m.append(temp)
print("第{}次聚类平方的差值为:{}".format(count,temp))
remean() #重定义中心值
while(m[0] != m[1]): #就两次循环后,重复选中心值,直至相等
m[0] = m[1]
cluster()
m[1] = square_d()
print("第{}次聚类平方的差值为:{}".format(count,m[1]))
remean()
show() #构散点图 构图与k-means无关,但是利用图表将数据展示出来更直观、更有说服力
这算是写的很简单的了,稍微复杂点的,定义每个部分的类于不同文件,在每个类中更细致的实现方法,再相互调用实例。
这里我根据代码总结了实现聚类的思想:
1:随机选择K个中心值
2:根据样本数据各点与中心点的距离来进行归簇
3:通过整个簇的均值,重置每个簇的中心值
4:重复2、3,直至达到最大的迭代次数(例如:我这里的条件设置为本次与上次的平方误差相等)
适用范围及缺陷:
K-Menas算法尝试找到使平方误差准则函数最小的簇。当潜在的簇形状是凸面的,簇与簇之间区别较明显,且簇大小相近时,其聚类结果较理想。对于处理大数据集合,该算法非常高效,且伸缩性较好。
但该算法除了要事先确定簇数K和对初始聚类中心敏感外,经常以局部最优结束,同时对“噪声”和孤立点敏感,并且该方法不适于发现非凸面形状的簇或大小差别很大的簇。
克服缺点的方法:使用尽量多的数据;使用中位数代替均值来克服outlier的问题。
优缺点是借鉴别人的,感觉比我总结的好那么一点点。所以记住上面的步骤,就算忘记了模板,也能自己慢慢摸索出来。