Kmeans学习

Kmeans学习

背景

咱们目的是将样本分红k个类,其实说白了就是求每一个样例x的隐含类别y,而后利用隐含类别将x归类。因为咱们事先不知道类别y,那么咱们首先能够对每一个样例假定一个y吧,可是怎么知道假定的对不对呢?怎么评价假定的好很差呢?咱们使用样本的极大似然估计来度量,这里是就是x和y的联合分布P(x,y)了。若是找到的y可以使P(x,y)最大,那么咱们找到的y就是样例x的最佳类别了,x顺手就聚类了。可是咱们第一次指定的y不必定会让P(x,y)最大,并且P(x,y)还依赖于其余未知参数,固然在给定y的状况下,咱们能够调整其余参数让P(x,y)最大。可是调整完参数后,咱们发现有更好的y能够指定,那么咱们从新指定y,而后再计算P(x,y)最大时的参数,反复迭代直至没有更好的y能够指定。css

使用

聚类的目标:python

  • 高内聚(类内距离加和尽量小!)
    • 量化指标:wcss(组内平方和,WCSS within-cluster sum of squares)
    • 寻找k个聚类中心,使得数据到聚类中心的距离最小
  • 低耦合(类与类之间的距离越大越好)!
    • 将每一个数据点分配到距离最近的聚类中心

步骤

K-means算法是将样本聚类成k个簇(cluster),具体算法描述以下算法

  • 初始化:对每一个cluster,任意选择空间中的一个点做为cluster中心
  • 迭代直到收敛:
    • 分配:将每个数据点分配到距离最近的中心
    • 重调:根据新的分配从新计算聚类中心

复杂度:n*k*tapp

优势:dom

缺点:ide

  • 对初试聚类中心依赖性强,最终效果随机性强
  • K值很难明确
    • 所以经常使用于预处理的去重操做
    • 同类别的商品基本上类似
  • 不能发现非凸形状的簇
  • 异或数据没法区分
  • 结果很难保证全局最优,只是局部最优

分析

K-means面对的第一个问题是如何保证收敛,前面的算法中强调结束条件就是收敛,能够证实的是K-means彻底能够保证收敛性。下面咱们定性的描述一下收敛性,咱们定义畸变函数distortion function以下:函数

Kmeans学习
J函数表示每一个样本点到其质心的距离平方和。K-means是要将J调整到最小。假设当前J没有达到最小值,那么首先能够固定每一个类的质心μ,调整每一个样例的所属的类别c^(i)^来让J函数减小,一样,固定c^(i)^,调整每一个类的质心μ也可使J减少。这两个过程就是内循环中使J单调递减的过程。当J递减到最小时,μ和c也同时收敛。(在理论上,能够有多组不一样的μ和c值可以使得J取得最小值,但这种现象实际上不多见)。学习

Kmeans学习

因为畸变函数J是非凸函数,意味着咱们不能保证取得的最小值是全局最小值,也就是说k-means对质心初始位置的选取比较感冒,但通常状况下k-means达到的局部最优已经知足需求。但若是你怕陷入局部最优,那么能够选取不一样的初始值跑多遍k-means,而后取其中最小的J对应的μ和c输出。3d

实现代码

def ReAssignClass():
    did = 0
    totalDis = 0.0  # 全部的距离
    for doc in DocList:
        min = ComputeDis(doc, ClassCenterList[0])
        minIndex = 0
        for i in range(1, K):
            dis = ComputeDis(doc, ClassCenterList[i])
            if dis < min:
                min = dis
                minIndex = i
        ClassList[did] = minIndex
        did += 1
        totalDis += min
    return totalDis

注意到,K是咱们事先给定的聚类数,ComputeDis将会计算出样例i与k个类中距离最近的那个类,其的值是1到k中的一个。质心表明咱们对属于同一个类的样本中心点的猜想(即μ,其实也就是咱们随机初始化一个点),如若拿星团模型来解释就是要将全部的星星聚成k个星团,首先随机选取k个宇宙中的点(或者k个星星)做为k个星团的质心,而后第一步对于每个星星计算其到k个质心中每个的距离,而后选取距离最近的那个星团记为min,这样通过第一步每个星星都有了所属的星团。code

def ComputeDis(doc1, doc2):
    sum = 0.0
    for (wid, freq) in doc1.items():
        if wid in doc2:
            d = freq - doc2[wid]
            sum += d * d
        else:
            sum += freq * freq
    for (wid, freq) in doc2.items():
        if wid not in doc1:
            sum += freq * freq
    sum = math.sqrt(sum)
    return sum

第二步对于每个星团,从新计算它的质心ReComputeCentroids(对里面全部的星星坐标求平均)。重复迭代第一步和第二步直到质心不变或者变化很小。

def ReComputeCentroids():
    for i in range(K):
        ClassSizeList[i] = 0
        ClassCenterList[i] = {}
    for i in range(len(DocList)):
        classid = ClassList[i]
        ClassSizeList[classid] += 1
        AddDoc(ClassCenterList[classid], DocList[i])
    for i in range(K):
        ClassCenterList[i] = Average(i)

实践

基于Kmeans的文章聚类(把相同的文章聚合)

准备数据

1000份已经打好标签的文本,而且由标签分类如bussiness,it,yule...

Kmeans学习

抽取其中一分内容已经通过文本预处理,每一个词汇经过 分隔开

Kmeans学习

数据预处理以后经过idf为这些词打分

def AddIDF(DocList):
    wordDic = {}
    for doc in DocList:
        for word in doc.keys():
            if word in wordDic:
                wordDic[word] += 1
            else:
                wordDic[word] = 1
    N = len(DocList)
    for doc in DocList:
        for word in doc.keys():
            doc[word] *= math.log(N + 1 / (float)(wordDic[word]))
        Normalize(doc)

Kmeans分析

初始化K个类中心,也就是Kmeans的核心节点

def Init():
    templist = random.sample(DocList, K)
    for i in range(K):
        ClassSizeList.append(0)
        ClassCenterList.append(templist[i])

计算各个点到(类)中心的距离,固然了,这个距离是尽量的越小越好,输出的结果就是wcss,其计算方式以下:

def ComputeDis(doc1, doc2):
    sum = 0.0
    for (wid, freq) in doc1.items():
        if wid in doc2:
            d = freq - doc2[wid]
            sum += d * d
        else:
            sum += freq * freq
    for (wid, freq) in doc2.items():
        if wid not in doc1:
            sum += freq * freq
    sum = math.sqrt(sum)
    return sum

本质上就是计算同一个簇内的距离的平方和后开方,

while math.fabs(oldWCSS - WCSS) > Threshold:
        oldWCSS = WCSS
        print "Iteration", i, "WCSS:", WCSS
        ReComputeCentroids()
        WCSS = ReAssignClass()
        i += 1
    ReComputeCentroids()
    print "Final iteration WCSS:", WCSS

重复迭代计算,直到wcss是最小,我用oldWCSS - WCSS作差,而threshold我自定义为1,固然了能够更加精确的,好比0.0001??

运行结果如图所示

Kmeans学习

有5种分类方式,其中第一种的分类方式准确率是0.6,第二种是0.9,。。。。。。

相关文章
相关标签/搜索