NLP--基於聚類的方法,對影評文本分類,並對幾種聚類方法進行比較,以及與分類的方法的效果進行比較。

【方法原理】

Sklearn的cluster提供了kmeans,Agglomerative(層級聚類中的聚合方法,另一個是分裂)和DBSCAN聚類函數(屬密度聚類)。

 KMeans均值算法表示以空間中k個點爲中心進行聚類,對靠近的點歸類。
1、從數據集(或者數據空間範圍內)D中隨機取k(預先人爲設定)個元素,作爲k個類的各自的初始中心。
2、分別計算剩下的元素到k個類中心的距離,依據距離大小,將這些元素分別劃歸到距離最近的類中。
3、根據聚類結果,重新計算k個類各自的中心。計算方法一般是取類中所有元素各自維度的算術平均數。
 DBSCAN的核心思想是:密度較高的點(不是距離相近的點)連成一片,進而生成同一個類。
算法實現:
1、對每個數據點,做以eps(預先設定)爲半徑的圓,如果圓內的點數多於閾值MinPts(預先設定),則稱該點爲核心點或者高密度點。把圈內的所有點連接起來,形成一個鏈路。鏈路上所有點即爲一個類。
2、如果圈內點數少於MinPts,則稱爲低密度的點,或者離羣點,異常點。
 層次聚類(Hierarchical Clustering)是一種聚類算法,通過計算不同類別數據點間的相似度來創建一棵有層次的嵌套聚類樹。在聚類樹中,不同類別的原始數據點是樹的最低層,樹的頂層是一個聚類的根節點。

聚類效果評估:
1)蘭德指數
表達的是從兩個集合中隨機選擇一對元素,是相同的概率。
ARI值的範圍是[-1,1],負的結果都是較差的,說明標籤是獨立分佈的,相似分佈的ARI結果是正的,1是最佳結果,說明兩種標籤的分佈完全一致;
隨機均勻的標籤分佈的ARI值接近0;
2)輪廓係數
樣本i的輪廓係數根據樣本i的簇內不相似度a (i) 和簇間不相似度b(i)定義。
核心思想是判斷:類間距離與類內距離的相對大小,如果類間距離>類內距離,則說明聚類結果好,反之,則不好。
s(i)接近1,則說明樣本i聚類合理;接近-1,則說明樣本i該分類到另外的簇;近似0,則說明在兩個簇的邊界上

【結果】

在這裏插入圖片描述

【代碼】

import nltk
from nltk.corpus import movie_reviews
from pylab import plot,show
from numpy import array
from numpy.random import rand
from scipy.cluster.vq import kmeans,vq,whiten
import numpy as np
import random

documents = [(list(movie_reviews.words(fileid)), category) for category in movie_reviews.categories() for fileid in movie_reviews.fileids(category)]  #轉化爲詞列表的影評,與標籤,組成二元組
random.shuffle(documents)	

all_words = nltk.FreqDist(w.lower() for w in movie_reviews.words())	 #建立全部影評的詞頻表
all_words=all_words.most_common(2000)			#詞頻表按頻率排序
stopwords = nltk.corpus.stopwords.words('english')
word_features  =[w for (w,f) in all_words if w not in stopwords] 		#特徵詞爲詞頻表中前2000詞

features = np.zeros([len(documents),len(word_features)],dtype=float)
#np.zeros((數組形狀),dtype,older)--返回一個給定形狀和類型的用0填充的數組
#(形狀:(5,)(5,5);older: C表示行優先,F表示列優先(可選參數))
for n in range(len(documents)):
        document_words = set(documents[n][0])
        for  m in range(len(word_features)):
                if word_features[m] in document_words:
                        features[n,m] = 1

target=[c for (d,c) in documents]

'''Kmeans聚類'''
##1)Kmeans的Scipy實現
data=whiten(features)
#Whiten:通過除以標準差,歸一化各維度的變化尺度。在Kmeans算法實施前做爲預處理,使每個特徵的作用相同。處理後的向量變爲‘白噪聲’。
centroids,_ = kmeans(data,2)
idx,_ = vq(data,centroids)

target1=[1 if x =='pos' else 0 for x in target]
a=sum(target1==idx)/len(target1)
print('scipy_eu=',max(a,1-a))

##2)Kmeans的NLTK實現。NLTK,Bio都可以選擇距離函數
from nltk.cluster import KMeansClusterer,cosine_distance
clus=KMeansClusterer(2,cosine_distance)#分爲兩類,距離函數用餘弦相似度
results=clus.cluster(data,True,trace=False)


##3)Kmeans的Bio實現
#from Bio.Cluster import kcluster
#clusterid, error, nfound = kcluster(data,2,dist='c')

'''層級聚類(聚合Agglomerative)'''
import scipy
from scipy.cluster.hierarchy import linkage,fcluster
agg=linkage(data,method='single',metric='euclidean')
#獲取集羣信息
max_d=50#選擇臨界距離決定集羣數量(應該畫圖看出吧)
clusters=fcluster(agg, max_d, criterion='distance')
#print(clusters)

'''密度聚類(DBSCAN)'''
from sklearn.cluster import DBSCAN
#eps爲距離閾值ϵ,min_samples爲鄰域樣本數閾值MinPts,X爲數據
y_pred = DBSCAN(eps = 50, min_samples = 3,metric='euclidean').fit(data)
labels=y_pred.labels_       #聚類標籤
print(labels[:100])

##聚類效果評估
print("蘭德指數ARI:")
from sklearn import metrics 
print("Kmeans_ARI:%s"%metrics.adjusted_rand_score(np.array(target1),results))
print("Agglomerative_ARI:%s"%metrics.adjusted_rand_score(np.array(target1),clusters))
print("DBSCAN_ARI:%s"%metrics.adjusted_rand_score(np.array(target1),labels))

print("輪廓係數:")
from sklearn.metrics import silhouette_score
print("1)使用歐式距離:")
sc_score = silhouette_score(data, results, metric='euclidean')
print("Kmeans:",sc_score)
sc_score = silhouette_score(data, clusters, metric='euclidean')
print("Agglomerative:",sc_score)
sc_score = silhouette_score(data, labels, metric='euclidean')
print("DBSCAN:",sc_score)
print("2)使用餘弦距離:")
sc_score = silhouette_score(data, results, metric='cosine')
print("Kmeans:",sc_score)
sc_score = silhouette_score(data, clusters, metric='cosine')
print("Agglomerative:",sc_score)
sc_score = silhouette_score(data, labels, metric='cosine')
print("DBSCAN:",sc_score)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章