1.什么是监督学习和无监督学习,半监督学习
对于"监督学习"(supervised learning),其训练样本是带有标记信息的,并且监督学习的目的是:对带有标记的数据集进行模型学习,从而便于对新的样本进行分类。
在“无监督学习”(unsupervised learning)中,训练样本的标记信息是未知的,目标是通过对无标记训练样本的学习来揭示数据的内在性质及规律,为进一步的数据分析提供基础。对于无监督学习,应用最广的便是"聚类"(clustering)。
半监督学习 :半监督学习使用大量的未标记数据,以及同时使用标记数据,来进行模式识别工作。当使用半监督学习时,将会要求尽量少的人员来从事工作,同时,又能够带来比较高的准确性,因此,半监督学习正越来越受到人们的重视。
2.什么是聚类算法
“聚类算法”试图将数据集中的样本划分为若干个通常是不相交的子集,每个子集称为一个“簇”(cluster),通过这样的划分,每个簇可能对应于一些潜在的概念或类别。
3.kmeans算法思想
以空间中k个点为中心进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果。
4.kmeans算法步骤
给定初始质心:首先选取初始质心集合centroids
样本聚类:计算每个样本和每个质心的距离,将样本聚类到距离最近的质心的簇里面
重新计算质心:每个簇的新质心的属性值等于此簇中所有样本的属性值得平均值
是否停止K-means:给定loop最大次数loopLimit 以及 所有质心变化距离的最大值maxDistance
如果step4没有结束k-means,就再执行step2-step3-step4-step5
如果step4结束了k-means,则就打印(或绘制)簇以及质心
5.k-means的算法核心三要素是什么
k值
k值小,近似误差(approximation error)会减小,但是估计误差(estimation error)会增大,模型更复杂,容易过拟合。
通常采用交叉验证法选取最优的k值,通常较小。
距离度量
e.g.欧氏距离,LpLp距离,Minkowski距离(在上面step2样本聚类步骤中我们使用欧氏距离作为样本和质心之间距离的度量方法。
也可以使用其他的距离度量方法,下面是常用的距离度量方法有:
1.2.1 欧氏距离
1.2.2 曼哈顿距离:
1.2.3 余弦相似度:
欧氏距离会受指标不同单位刻度(量纲不同)的影响,所以一般需要先进行标准化,同时距离越大,个体间差异越大;
空间向量余弦夹角的相似度度量不会受指标刻度的影响,余弦值落于区间[-1,1],值越大,差异越小。
)
分类决策规则
e.g.多数表决(等价于经验风险最小化)
6.既然知道了算法已经陷入了局部最小值,如何才能够进一步提升K-means算法的效果呢?
一种用于度量聚类效果的指标是SSE,即误差平方和, 为所有簇中的全部数据点到簇中心的误差距离的平方累加和。SSE的值如果越小,表示数据点越接近于它们的簇中心,即质心,聚类效果也越好。因为,对误差取平方后,就会更加重视那些远离中心的数据点。
显然,我们知道了一种改善聚类效果的做法就是降低SSE,那么如何在保持簇数目不变的情况下提高簇的质量呢?
一种方法是:我们可以将具有最大SSE值得簇划分为两个簇(因为,SSE最大的簇一般情况下,意味着簇内的数据点距离簇中心较远),具体地,可以将最大簇包含的点过滤出来并在这些点上运行K-means算法,其中k设为2.
同时,当把最大的簇(上图中的下半部分)分为两个簇之后,为了保证簇的数目是不变的,我们可以再合并两个簇。具体地:
一方面我们可以合并两个最近的质心所对应的簇,即计算所有质心之间的距离,合并质心距离最近的两个质心所对应的簇。
另一方面,我们可以合并两个使得SSE增幅最小的簇,显然,合并两个簇之后SSE的值会有所上升,那么为了最好的聚类效果,应该尽可能使总的SSE值小,所以就选择合并两个簇后SSE涨幅最小的簇。具体地,就是计算合并任意两个簇之后的总得SSE,选取合并后最小的SSE对应的两个簇进行合并。这样,就可以满足簇的数目不变。
7.1.3.聚类效果评价
轮廓系数(Silhouette Coefficient)结合了聚类的凝聚度(Cohesion)和分离度(Separation),用于评估聚类的效果。该值处于-1~1之间,值越大,表示聚类效果越好。具体计算方法如下:
对于每个样本点i,计算点i与其同一个簇内的所有其他元素距离的平均值,记作a(i),用于量化簇内的凝聚度。
选取i外的一个簇b,计算i与b中所有点的平均距离,遍历所有其他簇,找到最近的这个平均距离,记作b(i),即为i的邻居类,用于量化簇之间分离度。
对于样本点i,轮廓系数s(i) = (b(i) – a(i))/max{a(i),b(i)}
计算所有i的轮廓系数,求出平均值即为当前聚类的整体轮廓系数,度量数据聚类的紧密程度
从上面的公式,不难发现若s(i)小于0,说明i与其簇内元素的平均距离小于最近的其他簇,表示聚类效果不好。如果a(i)趋于0,或者b(i)足够大,即a(i)远远小于b(i),那么s(i)趋近与1,说明聚类效果比较好。
8.首先,随机确定k个初始点的质心;然后将数据集中的每一个点分配到一个簇中,即为每一个点找到距其最近的质心,并将其分配给该质心所对应的簇;该步完成后,每一个簇的质心更新为该簇所有点的平均值。代码如下:
#导入numpy库
from numpy import *
#K-均值聚类辅助函数
#文本数据解析函数
def numpy import *
dataMat=[]
fr=open(fileName)
for line in fr.readlines():
curLine=line.strip().split(’\t’)
#将每一行的数据映射成float型
fltLine=map(float,curLine)
dataMat.append(fltLine)
return dataMat
#数据向量计算欧式距离
def distEclud(vecA,vecB):
return sqrt(sum(power(vecA-vecB,2)))
#随机初始化K个质心(质心满足数据边界之内)
def randCent(dataSet,k):
#得到数据样本的维度
n=shape(dataSet)[1]
#初始化为一个(k,n)的矩阵
centroids=mat(zeros((k,n)))
#遍历数据集的每一维度
for j in range(n):
#得到该列数据的最小值
minJ=min(dataSet[:,j])
#得到该列数据的范围(最大值-最小值)
rangeJ=float(max(dataSet[:,j])-minJ)
#k个质心向量的第j维数据值随机为位于(最小值,最大值)内的某一值
centroids[:,j]=minJ+rangeJ*random.rand(k,1)
#返回初始化得到的k个质心向量
return centroids
#k-均值聚类算法
#@dataSet:聚类数据集
#@k:用户指定的k个类
#@distMeas:距离计算方法,默认欧氏距离distEclud()
#@createCent:获得k个质心的方法,默认随机获取randCent()
def kMeans(dataSet,k,distMeas=distEclud,createCent=randCent):
#获取数据集样本数
m=shape(dataSet)[0]
#初始化一个(m,2)的矩阵
clusterAssment=mat(zeros((m,2)))
#创建初始的k个质心向量
centroids=createCent(dataSet,k)
#聚类结果是否发生变化的布尔类型
clusterChanged=True
#只要聚类结果一直发生变化,就一直执行聚类算法,直至所有数据点聚类结果不变化
while clusterChanged:
#聚类结果变化布尔类型置为false
clusterChanged=False
#遍历数据集每一个样本向量
for i in range(m):
#初始化最小距离最正无穷;最小距离对应索引为-1
minDist=inf;minIndex=-1
#循环k个类的质心
for j in range(k):
#计算数据点到质心的欧氏距离
distJI=distMeas(centroids[j,:],dataSet[i,:])
#如果距离小于当前最小距离
if distJI<minDist:
#当前距离定为当前最小距离;最小距离对应索引对应为j(第j个类)
minDist=distJI;minIndex=j
#当前聚类结果中第i个样本的聚类结果发生变化:布尔类型置为true,继续聚类算法
if clusterAssment[i,0] !=minIndex:clusterChanged=True
#更新当前变化样本的聚类结果和平方误差
clusterAssment[i,:]=minIndex,minDist**2
#打印k-均值聚类的质心
print centroids
#遍历每一个质心
for cent in range(k):
#将数据集中所有属于当前质心类的样本通过条件过滤筛选出来
ptsInClust=dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]
#计算这些数据的均值(axis=0:求列的均值),作为该类质心向量
centroids[cent,:]=mean(ptsInClust,axis=0)
#返回k个聚类,聚类结果及误差
return centroids,clusterAssment
或
选择SSE最大的簇进行划分,知道簇数目达到用户指定的数目为止。
#二分K-均值聚类算法
#@dataSet:待聚类数据集
#@k:用户指定的聚类个数
#@distMeas:用户指定的距离计算方法,默认为欧式距离计算
def biKmeans(dataSet,k,distMeas=distEclud):
#获得数据集的样本数
m=shape(dataSet)[0]
#初始化一个元素均值0的(m,2)矩阵
clusterAssment=mat(zeros((m,2)))
#获取数据集每一列数据的均值,组成一个长为列数的列表
centroid0=mean(dataSet,axis=0).tolist()[0]
#当前聚类列表为将数据集聚为一类
centList=[centroid0]
#遍历每个数据集样本
for j in range(m):
#计算当前聚为一类时各个数据点距离质心的平方距离
clusterAssment[j,1]=distMeas(mat(centroid0),dataSet[j,:])**2
#循环,直至二分k-均值达到k类为止
while (len(centList)<k):
#将当前最小平方误差置为正无穷
lowerSSE=inf
#遍历当前每个聚类
for i in range(len(centList)):
#通过数组过滤筛选出属于第i类的数据集合
ptsInCurrCluster=
dataSet[nonzero(clusterAssment[:,0].Ai)[0],:]
#对该类利用二分k-均值算法进行划分,返回划分后结果,及误差
centroidMat,splitClustAss=
kMeans(ptsInCurrCluster,2,distMeas)
#计算该类划分后两个类的误差平方和
sseSplit=sum(splitClustAss[:,1])
#计算数据集中不属于该类的数据的误差平方和
sseNotSplit=
sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])
#打印这两项误差值
print(‘sseSplit,and notSplit:’,%(sseSplit,sseNotSplit))
#划分第i类后总误差小于当前最小总误差
if(sseSplit+sseNotSplit)<lowerSSE:
#第i类作为本次划分类
bestCentToSplit=i
#第i类划分后得到的两个质心向量
bestNewCents=centroidMat
#复制第i类中数据点的聚类结果即误差值
bestClustAss=splitClustAss.copy()
#将划分第i类后的总误差作为当前最小误差
lowerSSE=sseSplit+sseNotSplit
#数组过滤筛选出本次2-均值聚类划分后类编号为1数据点,将这些数据点类编号变为
#当前类个数+1,作为新的一个聚类
bestClustAss[nonzero(bestClustAss[:,0].A1)[0],0]=\
len(centList)
#同理,将划分数据集中类编号为0的数据点的类编号仍置为被划分的类编号,使类编号
#连续不出现空缺
bestClustAss[nonzero(bestClustAss[:,0].A0)[0],0]=\
bestCentToSplit
#打印本次执行2-均值聚类算法的类
print(‘the bestCentToSplit is:’,%bestCentToSplit)
#打印被划分的类的数据个数
print(‘the len of bestClustAss is:’,%(len(bestClustAss)))
#更新质心列表中的变化后的质心向量
centList[bestCentToSplit]=bestNewCents[0,:]
#添加新的类的质心向量
centList.append(bestNewCents[1,:])
#更新clusterAssment列表中参与2-均值聚类数据点变化后的分类编号,及数据该类的误差平方
clusterAssment[nonzero(clusterAssment[:,0].A
bestCentToSplit)[0],:]=bestClustAss
#返回聚类结果
return mat(centList),clusterAssment