K-Means(K-均值) ->聚类
K-Means 是一种使用广泛的聚类的算法,将各种聚类子集内的所有数据样本的均值作为该聚类的代表点。
算法主要思想:通过迭代把数据集划分为不同的类别,使得评价聚类性能的准则函数达到最优,从而使得生成的每个聚类类内紧凑,类间独立。
由于每次都要计算所有的样本与每一个质心之间的距离,在大规模数据集上收敛速度较慢。
算法思想及步骤
- 设置 k , 以及k个聚类中心 u1,u2,...,uk u 1 , u 2 , . . . , u k
- 分组:
- 将样本分配给距离最近的聚类中心
- 由这些样本构造不相交(non-overlapping)的聚类
- 确定中心: 用个聚类的均值向量作为新的聚类中心
- 重复2,3直至算法收敛即聚类中心达到稳定。
算法要点
选定某种距离作为数据样本间的相似性度量
k-means聚类算法不适合处理离散型属性,对连续性属性比较适合
计算样本之间的距离时,根据实际需要选择距离测度作为算法的相似性度量,如欧式距离,曼哈顿距离(各维差的绝对值之和),马氏距离(两个服从同一分布并且其协方差矩阵为Σ的随机变量之间的差异程度)
选择评价聚类性能的准则函数
k-means聚类算法使用误差平方和准则函数来评价聚类性能。
cost⋅Function=∑i=1k∑xj∈Si(xj−ui)2 c o s t · F u n c t i o n = ∑ i = 1 k ∑ x j ∈ S i ( x j − u i ) 2相似性的计算根据一个簇中对象的平均值(均值向量)来进行
性能分析
Advantages:
- 解决聚类问题的经典算法,简单,快速
- 处理大数据集,相对可伸缩和高效率的,复杂度是O(nkt), k <
算法改进
- 对于离散型属性和符号型属性,度量相似度采用:
- 比较记录,属性值相同为0,不相同为1,并取和。
- 更新新聚类中心,选择每个簇中的属性值出现频率最大的一个或几个作为代表簇的属性值。
- 对于类别数k的指定,考虑类别的合并与分裂。
- 合并: 某一类中样本太少,两类聚类中心距离过近
- 分裂:方差过大
- 初始值敏感
- 多设置不同的初始值,对比最后的结果,直至结果趋同。(耗时)
- 对于“噪声”和孤立数据点
- 不采用均值,采用中心点
- 基于最小化所有对象与其参照点之间相异度之和的原则???
算法实现(python)
导入数据
def loadDataSet(fileName):
dataMat = []
with open(fileName, 'r') as fp:
for line in fp.readlines():
curLine = line.strip().split('\t')
fltLine = [float(x) for x in curLine]
dataMat.append(fltLine)
return mat(dataMat)
生成k个点
def distEclud(vecA, vecB):
return sqrt(sum(power(vecA - vecB, 2)))
def randCent(dataSet, k):
# the dimension
n = shape(dataSet)[1]
# get the random center coordinates
centroids = mat(zeros((k, n)))
for j in range(n):
minJ = min(dataSet[:, j])
rangeJ = float(max(dataSet[:, j]) - minJ)
centroids[:,j] = minJ + rangeJ * random.rand(k, 1)
return centroids
k-means:
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
m = shape(dataSet)[0]
clusterAssment = mat(zeros((m, 2)))
centroids = createCent(dataSet, k)
clusterChanged = True
while clusterChanged:
clusterChanged = False
# calcuate the distance
for i in range(m):
minDist = inf
minIndex = -1
for j in range(k):
distJI = distMeas(centroids[j, :], dataSet[i, :])
if distJI < minDist:
minDist = distJI
minIndex = j
if clusterAssment[i, 0] != minIndex:
# unable to be stable
clusterChanged = True
clusterAssment[i, :] = minIndex, minDist**2
# print(centroids)
# update center coordinates
for cent in range(k):
ptsInClust = dataSet[nonzero(clusterAssment[:, 0].A == cent)[0]]
centroids[cent, :] = mean(ptsInClust, axis=0)
return centroids, clusterAssment
画图
def draw(dataSet, centroids, clusterAssment):
m = shape(dataSet)[0]
for i in range(m):
plt.scatter(dataSet[i, 0], dataSet[i, 1], c=color(clusterAssment[i, 0]), )
plt.show()
主程序
def main():
dataSet = loadDataSet('places.txt')
centroids, clusterAssment = kMeans(dataSet, 4)
draw(dataSet, centroids, clusterAssment)
二分k-means优化
def biKmeans(dataSet, k, distMeas=distEclud):
# number of dataSet
m = shape(dataSet)[0]
clusterAssment = mat(zeros((m, 2)))
# the first of center coordinate
centroidOne = mean(dataSet, axis=0).tolist()[0]
centList = [centroidOne]
for j in range(m):
# SSE of the first center coordiante and every one of dataset
clusterAssment[j, 1] = distMeas(mat(centroidOne), dataSet[j, :])**2
while (len (centList) < k):
lowestSSE = inf
for i in range(len(centList)):
# 第 i 类的数据集
ptsInCurrClust = dataSet[nonzero(clusterAssment[:, 0].A == i)[0], :]
centroidMat, splitClustAss = kMeans(ptsInCurrClust, 2, distMeas)
# calculate the SSE
sseSplit = sum(splitClustAss[:, 1])
sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:, 0].A != i)[0], 1])
print("SSE of split : %d \nSSE of nosplit : %d" % (sseSplit, sseNotSplit))
if (sseSplit + sseNotSplit) < lowestSSE:
bestCentToSpit = i
bestNewCents = centroidMat
bestClustAss = splitClustAss.copy()
lowestSSE = sseSplit + sseNotSplit
# divide it
bestClustAss[nonzero(bestClustAss[:, 0].A == 1)[0], 0] = len(centList)
bestClustAss[nonzero(bestClustAss[:, 0].A == 0)[0], 0] = bestCentToSpit
print("The bestCentToSpit is %d " % (bestCentToSpit))
print("The len of bestClustAss is %d " % (len(centList)))
# update and add center coordinate
centList[bestCentToSpit] = bestNewCents[0, :]
centList.append(bestNewCents[1, :])
# change the class which is divided into 2 parts
clusterAssment[nonzero(clusterAssment[:, 0].A == bestCentToSpit)[0], :] = bestClustAss
return centList, clusterAssment
经过几次测试,发现不如不优化。这个是通过我每次去找一个当前最优解。
KNN(近邻法)
最近邻
设有c个类 ω1,ω2,...,ωc ω 1 , ω 2 , . . . , ω c ,每类有 Ni N i 个样本。
待测样本的到第i类的最近距离: gi(x)=min||x−xki|| (xki表示的是第i类第k个样本,k=1,...Ni) g i ( x ) = m i n | | x − x i k | | ( x i k 表 示 的 是 第 i 类 第 k 个 样 本 , k = 1 , . . . N i )
距离我们除了可以采用欧式距离和曼哈顿距离,还可以采用明考斯基距离。
名考夫斯基距离:
加权名考夫斯基距离:
决策规则
把待测样本加g(x)最小的那个类中。
k = 1时称为最近邻分类器。
给定测试样本,若其最近邻样本为z,则最近邻分类器出错的概率就是x与z类别标记不同的概率
最近邻分类器虽简单,但是他的泛化错误率不超过贝叶斯最优分类器的错误率的两倍。
低维嵌入
当训练样本的采集密度足够大,成为”密采样(dense sample)”,但随着维度的提升,样本数目明显不够,导致数据样本稀疏,距离计算困难等难题,即“维数灾难(curse of dimensionality)”。
缓解的一个重要途径就是降维(dimension reduction).人们观测数据样本虽是高维的,但是与学习任务密切相关的也许尽是某个低维分布。
典型的多维缩放(Multiple Dimensional Scaling , MDS):
假定m个样本在原始控件的距离矩阵为 D∈Rm×m,distij D ∈ R m × m , d i s t i j 表示 xi x i 到 xj x j 的距离,目标是获取d’维空间的表示 Z∈Rd′×m Z ∈ R d ′ × m , 且任意两个样本在d’维空间中的欧氏距离等于原始空间中的距离。
令 B=ZTZ∈Rm×m B = Z T Z ∈ R m × m , 其中B为降维后样本的内积矩阵,有 bij=zTizj b i j = z i T z j