聚类与分类的最大不同在于,分类的目标事先已知,而聚类则不一样。因为其产生的结果与分类相同,而只是类别没有预定义,聚类有时也称为无监督分类(unsupervised classification)
K-means算法
优点:容易实现
缺点:可能收敛到局部最小值,在大规模数据集上收敛缓慢
适用数据类型:数值型数据。
K-均值是发现给定数据集的k个簇的算法。簇个数k是用户给定的,每个簇通过其质心(centroid),即簇中所有点的中心来描述。
工作流程如下:
(1) 随机确定k个初始点作为质心。
(2) 将数据集中的每个点分配到一个簇中,具体讲为每个点找距其最近的质心,并将其分配给该质心所对应的簇。
(3) 每个簇的质心更新为该簇所有点的平均值。
伪码如下:
创建k个点作为起始质心(随机选择)
当任意一个点的簇分配结果发生改变时
对数据集中的每个数据点
对每个质心
计算质心与数据点之间的距离
将数据点分配到距其最近的簇
对每一个簇,计算簇中所有点的均值并将均值作为质心
代码是从源码中拮取下来的, 修改了一个地方,见17行处,该处不用list()处理的话会有问题,代码比较简单。不过有些numpy的数据处理比较生疏了,自己写代码理解下:
主要是使用mat()矩阵化,易于处理数据。
clusterAssment[:,0].A==i该语句返回一个矩阵,如下:
[[False]
[False]
[False]
[False]
[ True]
[ True]
[ True]
[ True]
[ True]
[ True]]
而nonzero()返回true对应的下标组成的单行矩阵,如下:
[4 5 6 7 8 9]
data[nonzero(clusterAssment[:,0].A==i)[0]]获取到筛选后的矩阵
[[4]
[5]
[6]
[7]
[8]
[9]]
用于后续求平均值,更新质心。
二分K-均值算法
目的:解决k-均值算法收敛于局部最小值的问题
算法流程:首先将所有点作为一个簇,然后将簇一分为二,之后选择其中一个簇继续进行划分,选择哪一个簇进行划分取决于对其划分是否可以最大程度降低SSE的值。上述基于SSE的划分过程不断重复,直到得到用户指定的簇数目为止。
伪代码如下:
将所有点看成一个簇
当簇数目小于k时
对于每一个簇
计算总误差
在给定的簇上面进行K-均值聚类(k=2)
计算将该簇一分为二之后的总误差
选择使得误差最小的那个簇进行划分操作
K-means算法
优点:容易实现
缺点:可能收敛到局部最小值,在大规模数据集上收敛缓慢
适用数据类型:数值型数据。
K-均值是发现给定数据集的k个簇的算法。簇个数k是用户给定的,每个簇通过其质心(centroid),即簇中所有点的中心来描述。
工作流程如下:
(1) 随机确定k个初始点作为质心。
(2) 将数据集中的每个点分配到一个簇中,具体讲为每个点找距其最近的质心,并将其分配给该质心所对应的簇。
(3) 每个簇的质心更新为该簇所有点的平均值。
伪码如下:
创建k个点作为起始质心(随机选择)
当任意一个点的簇分配结果发生改变时
对数据集中的每个数据点
对每个质心
计算质心与数据点之间的距离
将数据点分配到距其最近的簇
对每一个簇,计算簇中所有点的均值并将均值作为质心
代码如下:
from numpy import *
def loadDataSet(fileName):
dataMat = []
fr = open(fileName)
for line in fr.readlines():
curLine = line.strip().split('\t')
from numpy import *
def loadDataSet(fileName):
dataMat = []
fr = open(fileName)
for line in fr.readlines():
curLine = line.strip().split('\t')
fltLine = list(map(float,curLine))
dataMat.append(fltLine)
return dataMat
def distEclud(vecA, vecB):
return sqrt(sum(power(vecA - vecB, 2)))
def randCent(dataSet, k):
n = shape(dataSet)[1]
centroids = mat(zeros((k,n)))
for j in range(n):
minJ = min(dataSet[:,j])
rangeJ = float(max(dataSet[:,j]) - minJ)
centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1))
return centroids
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
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:
clusterChanged = True
clusterAssment[i,:] = minIndex,minDist**2
for cent in range(k):
ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]
centroids[cent,:] = mean(ptsInClust, axis=0)
return centroids, clusterAssment
datMat = loadDataSet('testSet.txt')
myCentroids, clusterAssing = kMeans(datMat, 4)
dataMat.append(fltLine)
return dataMat
def distEclud(vecA, vecB):
return sqrt(sum(power(vecA - vecB, 2)))
def randCent(dataSet, k):
n = shape(dataSet)[1]
centroids = mat(zeros((k,n)))
for j in range(n):
minJ = min(dataSet[:,j])
rangeJ = float(max(dataSet[:,j]) - minJ)
centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1))
return centroids
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
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:
clusterChanged = True
clusterAssment[i,:] = minIndex,minDist**2
for cent in range(k):
ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]
centroids[cent,:] = mean(ptsInClust, axis=0)
return centroids, clusterAssment
datMat = loadDataSet('testSet.txt')
myCentroids, clusterAssing = kMeans(datMat, 4)
代码是从源码中拮取下来的, 修改了一个地方,见17行处,该处不用list()处理的话会有问题,代码比较简单。不过有些numpy的数据处理比较生疏了,自己写代码理解下:
clusterAssment = mat(zeros((10,2)))
print(clusterAssment[:,0].A)
clusterAssment[0,:] = 1, 0
clusterAssment[1,:] = 1, 10
clusterAssment[2,:] = 2, 20
clusterAssment[3,:] = 3, 30
print(clusterAssment[:,0].A)
data = []
for i in range(10):
data.append([i])
data = mat(data)
for i in range(4):
print(clusterAssment[:,0].A==i)
print(nonzero(clusterAssment[:,0].A==i)[0])
ptsInClust = data[nonzero(clusterAssment[:,0].A==i)[0]]
print(ptsInClust)
print()
主要是使用mat()矩阵化,易于处理数据。
clusterAssment[:,0].A==i该语句返回一个矩阵,如下:
[[False]
[False]
[False]
[False]
[ True]
[ True]
[ True]
[ True]
[ True]
[ True]]
而nonzero()返回true对应的下标组成的单行矩阵,如下:
[4 5 6 7 8 9]
data[nonzero(clusterAssment[:,0].A==i)[0]]获取到筛选后的矩阵
[[4]
[5]
[6]
[7]
[8]
[9]]
用于后续求平均值,更新质心。
二分K-均值算法
目的:解决k-均值算法收敛于局部最小值的问题
算法流程:首先将所有点作为一个簇,然后将簇一分为二,之后选择其中一个簇继续进行划分,选择哪一个簇进行划分取决于对其划分是否可以最大程度降低SSE的值。上述基于SSE的划分过程不断重复,直到得到用户指定的簇数目为止。
伪代码如下:
将所有点看成一个簇
当簇数目小于k时
对于每一个簇
计算总误差
在给定的簇上面进行K-均值聚类(k=2)
计算将该簇一分为二之后的总误差
选择使得误差最小的那个簇进行划分操作