zoukankan      html  css  js  c++  java
  • Kmeans文档聚类算法实现之python

    实现文档聚类的总体思想:

    1. 将每个文档的关键词提取,形成一个关键词集合N;
    2. 将每个文档向量化,可以参看计算余弦相似度那一章;
    3. 给定K个聚类中心,使用Kmeans算法处理向量;
    4. 分析每个聚类中心的相关文档,可以得出最大的类或者最小的类等;

    将已经分好词的文档提取关键词,统计词频:

    # 计算每个文档的关键词和词频
    # 关键词统计和词频统计,以列表形式返回
    def Count(resfile):
        t = {}
        infile = open(resfile, 'r', encoding='utf-8')
        i = 0
        f = infile.readlines()
        count = len(f)
        # print(count)
        infile.close()
        s = open(resfile, 'r', encoding='utf-8')
        while i < count:
            line = s.readline()
            line = line.rstrip('
    ')
            # print(line)
            words = line.split(" ")
            #   print(words)
            for word in words:
                if word != "" and t.__contains__(word):
                    num = t[word]
                    t[word] = num + 1
                elif word != "":
                    t[word] = 1
            i = i + 1
        # 按键值降序
        dic = sorted(t.items(), key=lambda t: t[1], reverse=True)
        s.close()
        # 返回的是一篇文档的词项统计表,形式为[(word:出现次数)]
        return dic

      上面的count函数统计的一篇文档的词频,如果每篇文档都需要统计则需要调用这个count函数,每调用一次就返回一个dict,给一个文档集统计词频的参考代码如下(假设有500篇文档):

    def readfile():
        f = open("res.txt", "w", encoding="utf-8")
        # mergeword 用来记录所有文档的词项集合,不重复,其长度是用来作为文档向量维度
        mergeword = []
        everyDocumentDict = []
        for i in range(500):
           filedir
    = "D:/PythonCodingLover/PythonPro/DailyStudy/互联网项目二/CNS/"+ "CNS" +str(i)+"_C.txt" # 将每个文档的字典写入res.txt中 dict = Count(filedir) # everyDocumentDict记录的是每篇文档的词项统计 everyDocumentDict.append(dict) # print(type(dict)) for j in range(len(dict)): if dict[j][0] not in mergeword: mergeword.append(dict[j][0]) f.close() # 返回文档集的词项集 return mergeword,everyDocumentDict

      上面两部分可以实现将文档集里的关键词,担心是否正确可以使用简单的测试代码,如下:

    # 测试文档集关键词是否正确
    mergeword ,eveKeywordOfCount= readfile()
    print(type(eveKeywordOfCount))
    print(len(eveKeywordOfCount))
    print(len(mergeword))

    将每篇文档向量化,便于后面的文档聚类:

      下面这个函数将所有的文档向量一起返回,而不是一篇文档向量;

    # 现在有了500个文档的总关键词和每篇文档的词项统计,所以我们现在要做的是将每篇文档向量化,维度是len(mergeword)
    # 注意EveDocCount的结构是[[(),()],[(),()]],里面记录的列表是每个文档的词项统计,而括号里面的是keyword:词频

    print("-------------------文档向量化开始操作-----------------") def VectorEveryDoc(EveDocCount,mergeword): # vecOfDoc列表记录的是每篇文档向量化后的向量列表,共有500个元素 vecOfDoc = [] # vecDoc列表记录的是一篇文档的向量模型,向量化后添加到vecOfDoc vectorLenth = len(mergeword) # 下面开始将500文档向量化 i = 0 while i < 500: # EveDocCount[i]记录的是第几篇文档的词项统计 vecDoc = [0] * vectorLenth # 测试是正确的 # print(EveDocCount[i]) for ch in range(len(EveDocCount[i])): # termFrequence 是词项对应的频数 termFrequence = EveDocCount[i][ch][1] # keyword是词项 keyword = EveDocCount[i][ch][0] # 下面开始具体的向量化 j = 0 while j < vectorLenth: if keyword == mergeword[j]: # 这里是J 而不是 I ,写错了就很容易出错了 vecDoc[j] = termFrequence break else: j = j + 1 vecOfDoc.append(vecDoc) i = i+ 1 # 返回500个文档的文档向量 return vecOfDoc print("-------------------文档向量化操作结束-----------------")

    向量化结束之后,便需要计算余弦距离(也可以使用其他距离,例如欧几里得距离):

      说明:一个文档集的关键词可能有很多,为了方便后面的计算,引入科学计算包numpy,示例代码如下:

      

    # 导入科学计算包
    import numpy as np

      而后将500个文档向量传给numpy的数组,构造矩阵,示例代码如下:

    resultVec = VectorEveryDoc(eveKeywordOfCount,mergeword)
    vecDate = np.array(resultVec)

      之后便计算余弦相似度,这里和前面写的余弦距离相似度计算类似,不同的是使用了nmupy数组,注意其中的矩阵乘法,示例代码如下:

    # 计算余弦距离
    def CalConDis(v1,v2):
        lengthVector = len(v1)
        # 计算出两个向量的乘积
        # 将v2变换,转置矩阵v2
        v2s =v2.T
        B = np.dot(v1,v2s)
        # 计算两个向量的模的乘积
        v1s = v1.T
        A1 = np.dot(v1,v1s)
        A2 = np.dot(v2,v2s)
        A = math.sqrt(A1) * math.sqrt(A2)
        # print('相似度 = ' + str(float(B) / A))
        resdis = format(float(B) / A,".3f")
        return float(resdis)

    Kmeans聚类算法实现文档聚类:

    随机产生K个聚类中心点:

    # 随机选取中心点,dateSet是m * n矩阵,K是要指定的聚类的个数
    def createRandomCent(dateSet,k):
        # 返回整个矩阵的列的列数
        n = np.shape(dateSet)[1]
        # 创建一个k * n 的零矩阵
        centroids = np.mat(np.zeros((k, n)))
        # 随机产生k个中心点
        for j in range(n):
            minJ = min(dateSet[:, j])
            rangeJ = float(max(dateSet[:, j]) - minJ)
            centroids[:, j] = np.mat(minJ + rangeJ * np.random.rand(k, 1))
        # 返回随机产生的k个中心点
        return centroids

    Kmeans算法按照随机产生的聚类中心开始聚类,返回的一个矩阵:

    countclu = 1
    # 具体的Kmeans算法实现
    # dateset是指500个文档的向量集合(500 * length),dis用的是余弦距离,k是给定的k个聚类中心,createCent是随机生成的K个初始中心
    def dfdocKmeansCluster(dateset,k,discos = CalConDis,createCent = createRandomCent):
        # docCount 记录的总共有多少个样本,既矩阵的行数
        docCount = np.shape(dateset)[0]
        # 在构建一个500 * 2的0矩阵,用来存放聚类信息
        docCluster = np.mat(np.zeros((docCount,2)))
    
        # 初始化K个聚类中心
        centerOfCluster = createCent(dateset,k)
        # clusterFlag用来判定聚类是否结束
        clusterFlag = True
        while clusterFlag:
            clusterFlag = False
            for each in range(docCount):
                # 将最大余弦距离初始化成一个负数
                maxCosDis = -100
                # 文档索引
                minIndex = -1
                # 找到每篇文档距离最近的中心
                for i in range(k):
                    # 计算每个文档到中心点的余弦相似度,
                    global countclu
                    countclu = countclu+ 1
                    print("已经聚类第" + str(countclu) + "")
                    distcosOfDocToDoccenter = discos(centerOfCluster[i, :], dateset[each, :])
                    # 选择余弦距离最大的一个中心
                    if distcosOfDocToDoccenter > maxCosDis:
    
                        maxCosDis = distcosOfDocToDoccenter
                        minIndex = i
                if docCluster[each, 0] != minIndex:
                    # 如果没到最优方案则继续聚类
                    clusterFlag = True
                # 第1列为所属中心,第2列为余弦距离
                docCluster[each, :] = minIndex, maxCosDis
            # 打印随机产生的中心点
            print(centerOfCluster)
    
            # 更改聚类中心点
            for cent in range(k):
                ptsInClust = dateset[np.nonzero(docCluster[:, 0].A == cent)[0]]
                centerOfCluster[cent, :] = np.mean(ptsInClust, axis=0)
        # 返回K个中心点,
        return centerOfCluster,docCluster

      这里返回的一个500*2的矩阵,第一列是聚类中心,第二列是和中心的余弦距离,索引就是文档编号

      如果需要得出具体的类有几篇文档等问题,则需要对返回的矩阵进行分析(注意是numpy矩阵);

      程序到了这里。就基本上结束了;

  • 相关阅读:
    派生
    什么是类的继承
    python中一切皆对象
    类之属性查找
    类之 __init__方法

    MySql cmd下的学习笔记 —— 有关分组的操作(group by)
    MySql cmd下的学习笔记 —— 有关select的操作(max, min等常见函数)
    MySql cmd下的学习笔记 —— 有关select的操作(in, and, where, like等等)
    MySql cmd下的学习笔记 —— 有关表的操作(对表的增删改查)
  • 原文地址:https://www.cnblogs.com/zuixime0515/p/9604034.html
Copyright © 2011-2022 走看看