# 計算每一個文檔的關鍵詞和詞頻 # 關鍵詞統計和詞頻統計,以列表形式返回 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('\n') # 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))
下面這個函數將全部的文檔向量一塊兒返回,而不是一篇文檔向量;app
# 如今有了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,示例代碼以下:dom
# 導入科學計算包 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)
# 隨機選取中心點,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
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的矩陣,第一列是聚類中心,第二列是和中心的餘弦距離,索引就是文檔編號;spa
若是須要得出具體的類有幾篇文檔等問題,則須要對返回的矩陣進行分析(注意是numpy矩陣);code
程序到了這裏。就基本上結束了;orm