K均值聚类
K-means算法是很典型的基于距离的聚类算法,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。算法采用误差平方和准则函数作为聚类准则函数。
算法过程如下:
1)从N个文档随机选取K个文档作为质心
2)对剩余的每个文档测量其到每个质心的距离,并把它归到最近的质心的类
3)重新计算已经得到的各个类的质心
4)迭代2~3步直至新的质心与原质心相等或小于指定阈值,算法结束
#_*_coding:utf-8_*_
#作者 :hjy
#创建时间 :19-3-4 上午11:09
#文件 :K_Mean.py
#IDE :PyCharm
from math import sqrt
import random
from PIL import ImageDraw, Image
def readfile(filename):
"""
读取表格型数据,获取特征数据集
:param filename:
:return: rownames, colnames, data
"""
lines = [line for line in open(filename)]
#第一行是列标题
colnames = lines[0].strip().split('\t')[1:]
rownames = []
data = []
for line in lines[1:]:
p = line.strip().split('\t')
#每行的第一列是行名
rownames.append(p[0])
#剩余部分就是该行对应的数据
onerow = [float(x) for x in p[1:]]
data.append(onerow)
return rownames, colnames, data
def pearson(v1, v2):
"""
计算两个聚类中心点的皮尔逊相似度
:param v1:
:param v2:
:return:
"""
#简单求和
sum1 = sum(v1)
sum2 = sum(v2)
#求平方和
sum1Sq = sum([pow(v, 2) for v in v1])
sum2Sq = sum([pow(v, 2) for v in v2])
#求乘积之和
pSum =sum([v1[i] * v2[i] for i in range(len(v1))])
#计算距离
num = pSum-(sum1 * sum2/len(v1))
den = sqrt((sum1Sq - pow(sum1, 2)/len(v1)) * (sum2Sq - pow(sum2, 2)/len(v1)))
if den == 0:
return 0
return 1.0-num/den
def tanamoto(v1, v2):
"""
使用tanimoto系数表示距离(相似度):两个向量的交集/两个向量的并集
:param v1:
:param v2:
:return:
"""
c1, c2, shr=0, 0, 0
for i in range(len(v1)):
if v1[i] != 0:
c1 += 1
if v2[i] != 0:
c2 += 1
if v1[i] != 0 and v2[i] != 0:
shr += 1
return 1.0 - (float(shr)/(c1 + c2 - shr))
def kcluster(rows, distance=pearson, k=4):
"""
K-mean算法
:param rows: 数据集
:param distance:
:param k:聚类数目
:return:
"""
#确定每个点的特征的最大值和最小值
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('迭代 %d' %t)
bestmatches = [[] for i in range(k)] #生成k个空数组,用于存储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#返回k个聚类点,以及所包含的所有成员
k-means聚类的优缺点:
k-means算法的优点:
(1)k-means算法是解决聚类问题的一种经典算法,算法简单、快速。
(2)对处理大数据集,该算法是相对可伸缩的和高效率的,因为它的复杂度大约是O(nkt),其中n是所有对象的数目,k是簇的数目,t是迭代的次数。通常k<<n。这个算法通常局部收敛。
(3)算法尝试找出使平方误差函数值最小的k个划分。当簇是密集的、球状或团状的,且簇与簇之间区别明显时,聚类效果较好。
缺点:
(1)k-平均方法只有在簇的平均值被定义的情况下才能使用,且对有些分类属性的数据不适合。
(2)要求用户必须事先给出要生成的簇的数目k。
(3)对初值敏感,对于不同的初始值,可能会导致不同的聚类结果。
(4)不适合于发现非凸面形状的簇,或者大小差别很大的簇。
(5)对于”噪声”和孤立点数据敏感,少量的该类数据能够对平均值产生极大影响。
k中心点算法
k中心算法的基本过程是:首先为每个簇随意选择一个代表对象,剩余的对象根据其与每个代表对象的距离(此处距离不一定是欧氏距离,也可能是曼哈顿距离)分配给最近的代表对象所代表的簇;然后反复用非代表对象来代替代表对象,以优化聚类质量。聚类质量用一个代价函数来表示。当一个中心点被某个非中心点替代时,除了未被替换的中心点外,其余各点被重新分配。
为了减轻k均值算法对孤立点的敏感性,k中心点算法不采用簇中对象的平均值作为簇中心,而选用簇中离平均值最近的对象作为簇中心。
算法如下:
输入:包含n个对象的数据库和簇数目k;
输出:k个簇
(1)随机选择k个代表对象作为初始的中心点
(2)指派每个剩余对象给离它最近的中心点所代表的簇
(3)随机地选择一个非中心点对象y
(4)计算用y代替中心点x的总代价s
(5)如果s为负,则用可用y代替x,形成新的中心点
(6) 重复(2)(3)(4)(5),直到k个中心点不再发生变化.
原文:https://blog.csdn.net/luanpeng825485697/article/details/78993977