1.k-均值聚类
因为前面的几种求聚类的算法,需要计算两两配对项的关系,在数据集大的时候,速度会很慢。所以我们要学习k-均值聚类
算法思想:我们会事先知道需要聚类的数量。这儿假设我们需要n个聚类,那么我们先随机生成n个中心位置。然后利用聚类算法将各个数据项分配给最邻近的中心位置,然后移动中心位置到聚类的平均位置处,然后循环以上步骤,知道分配过程不再变化,那么算法结束。返回n个聚类。具体代码如下
#k-均值类聚
#rows->数据集,distance->求聚类的算法,k->聚类个数
def kcluster(rows,distance=pearson,k=4):
#确定每个点的最小值和最大值
ranges=[(min([row[i] for row in rows]),max(row[i] for row in rows))for i in range(len(rows[0]))]
#随机创建k个中心点
clusters=[[random.random()*(ranges[i][1]-ranges[i][0])+ranges[i][0] for i in range(len(rows[0]))]for j in range(k)]
lastmatches=None
for t in range(100):
print 'Iteration %d' %t
bestmatches=[[]for i in range(k)]
#在每一行中寻找距离最近的中心点
for j in range(len(rows)):
row = rows[j]
bestmatch=0
for i in range(k):
d= distance(clusters[i],row)
if d<distance(clusters[bestmatch],row):
bestmatch=i
bestmatches[bestmatch].append(j)
#如果结果与上一次相同,则整个过程结束
if bestmatches==lastmatches:
break
lastmatches=bestmatches
#把中心点移到其所有成员的平均位置
for i in range(k):
avgs=[0.0]*len(rows[0])
if len(bestmatches[i])>0:
for rowid in bestmatches[i]:
for m in range(len(rows[rowid])):
avgs[m]+=rows[rowid][m]
for j in range(len(avgs)):
avgs[j]/=len(bestmatches[i])
clusters[i]=avgs
return bestmatches
返回的bestmatches存放的是每个聚类。
2.之前我们学习的类聚,都是基于两个物品间的距离类聚,而我们生活中可以有很多相似的类聚,不仅仅是两个。所以我们需要多维缩放技术寻找聚类。(表达有问题,解释不太清楚)
思路如下:随机生成每一个数据项在二维空间的坐标点。然后通过每个点对一个点的相对的真实距离的施力情况,来对这个点的位置进行调整(这儿就用了多维缩放)。最后调整到总的误差值变大了,则算法结束。
具体代码如下
def scaledown(data,distance=pearson,rate=0.01):
n=len(data)
#每一对数据项之间的真实距离
realdist=[[distance(data[i],data[j])for j in range(n)] for i in range(0,n)]
outersum=0.0
#随机初始化节点在二维空间中的起始位置
loc=[[random.random(),random.random()]for i in range(n)]
fakedist=[[0.0 for j in range(n)] for i in range(n)]
lasterror=None
for m in range(0,1000):
#寻找投影后的距离
for i in range(n):
for j in range(n):
fakedist[i][j]=sqrt(sum([pow(loc[i][x]-loc[j][x],2) for x in range(len(loc[i]))]))
#移动节点
grad=[[0.0,0.0]for i in range(n)]
totalerror=0
for k in range(n):
for j in range(n):
if j==k:
continue
#误差值等于目标距离与当前距离之间差值的百分比
errorterm=(fakedist[j][k]-realdist[j][k])/realdist[j][k]
#每一个节点都需要根据误差的多少,按比例移离或移向其他节点
grad[k][0]+=((loc[k][0]-loc[j][0])/fakedist[j][k])*errorterm
grad[k][1]+=((loc[k][1]-loc[j][1])/fakedist[j][k])*errorterm
#记录总的误差值
totalerror+=abs(errorterm)
print totalerror
#如果节点移动之后的情况变得更糟,则程序结束
if lasterror and lasterror<totalerror:
break
lasterror=totalerror
#根据rate参数与grad值想乘的结果,移动每一个节点
for k in range(n):
loc[k][0]-=rate*grad[k][0]
loc[k][1]-=rate*grad[k][1]
return loc
下面代码是结果可视化,作图
def draw2d(data,lables,jpeg='mds2d.jpg'):
img=Image.new('RGB',(2000,2000),(255,255,255))
draw=ImageDraw.Draw(img)
for i in range(len(data)):
x=(data[i][0]+0.5)*1000
y=(data[i][1]+0.5)*1000
draw.text((x,y),lables[i],(0,0,0))
img.save(jpeg,'JPEG')
这儿作出来的图,是以相对距离来判断他们的关联性的。可以很直观的看出聚类的信息。
这篇博客写的很差,自己理解了, 写不出来,尴尬。