1. 程式人生 > >Python基於Kmeans演算法實現文字聚類的簡單練習

Python基於Kmeans演算法實現文字聚類的簡單練習

接觸機器學習時間不長,也一直有興趣研究這方面的演算法。最近在學習Kmeans演算法,但由於工作的原因無法接觸到相關的專案實戰。為了理清思路、熟悉程式碼,在參照了幾篇機器學習大神的博文後,做了一個簡單的Kmeans演算法的簡單練習。作為一枚機器學習的門外漢,對於文中的一些錯誤和不足,還望您多多包涵,也歡迎您的批評和建議(第一次發部落格,有點語無倫次,見諒哈)。

先說一下我的大致思路:

1、利用爬蟲進行文字資料的爬取。本文爬取了豆瓣電影TOP250榜單內的電影劇情簡介作為聚類文字。

2、利用jieba分詞對文字進行預處理(文字分詞、停用詞過濾、語料庫的建立等)。

3、利用scikit-learn計算詞語的tfidf並建立VSM。

4、利用Kmeans進行文字聚類。

5、結果展示。

話不多說,直接進入正題吧。

一、文字資料的爬取

先上程式碼:

# -*- coding: utf-8 -*-
import urllib.request
import re
from lxml import etree
urllib.request.urlcleanup()
import urllib.error
import time
'''豆瓣設定了反扒機制,通過設定代理並將爬蟲偽裝成瀏覽器,以及在出現錯誤時設定延時後發現能狗成功'''
def use_proxy(proxy_ip,url):
	try:
		req=urllib.request.Request(url)
		req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0')
		proxy=urllib.request.ProxyHandler({'http':proxy_ip})
		opener=urllib.request.build_opener(proxy,urllib.request.HTTPHandler)
		urllib.request.install_opener(opener)
		data=urllib.request.urlopen(req).read().decode('utf-8','ignore')
		return data
	except urllib.error.URLError as e:
		if hasattr(e,'code'):
			print(e.code)
		if hasattr(e,'reason'):
			print(e.reason)
		time.sleep(10) #出現異常延時10s
	except Exception as e:
		print('exception:'+str(e))
		time.sleep(1)
'''爬取榜單上電影的連結'''
for i in range(0,225,25):
    url='https://movie.douban.com/top250?start='+str(i)
    proxy_ip='127.0.0.1:8888'
    data=use_proxy(proxy_ip,url)
    response = etree.HTML(data)
    link = response.xpath('//div[@class="pic"]/a/@href')
    '''在爬取過程中發現豆瓣上有4部電影的連結無法開啟,將其剔除'''
        unlink=['https://movie.douban.com/subject/5912992/',
            'https://movie.douban.com/subject/1292000/',
            'https://movie.douban.com/subject/1300299/',
            'https://movie.douban.com/subject/1417598/']
    for j in range(0,len(link)):
        thisurl=link[j]
        if thisurl in unlink:
                continue
        '''爬取劇情簡介文字,並寫入本地檔案'''
        data=use_proxy(proxy_ip,thisurl)
        pat='<span property="v:summary".*?>(.*?)</span>'
        content=re.compile(pat,re.S).findall(data)
        pat1='<title>(.*?)</title>'
        title=re.compile(pat1,re.S).findall(data)
        content_data=content[0].replace('<br />','').strip().replace('\n','').replace(' ','')
        filename='D:/Python_work/Data Mining/db250/'+title[0].strip()+'.txt'
        with open(filename,'w',encoding='utf-8') as fh:
            fh.write(content_data)

爬取結果:


二、文字預處理

文字預處理主要利用jieba分詞進行中文分詞,根據停用詞的語料庫進行停用詞的過濾以及特殊字元的處理,建立語料庫。

本文停用詞庫的建立參考博文:點選開啟連結

程式碼如下:

# -*- coding: utf-8 -*-
from os import listdir
import jieba
from sklearn import feature_extraction  
from sklearn.feature_extraction.text import TfidfTransformer  
from sklearn.feature_extraction.text import CountVectorizer  
all_file=listdir('D:/Python_work/Data Mining/db250') #獲取資料夾中所有檔名
labels=[] #用以儲存電影名稱
corpus=[] #空語料庫
'''停用詞的過濾'''
typetxt=open('D:/Python_work/Data Mining/文字相似度計算/停用詞.txt') 
texts=['\u3000','\n',' '] #爬取的文字中未處理的特殊字元
'''停用詞庫的建立'''
for word in typetxt:
    word=word.strip()
    texts.append(word)
'''語料庫的建立'''
for i in range(0,len(all_file)):
    filename=all_file[i]
    filelabel=filename.split('.')[0]
    labels.append(filelabel) #電影名稱列表
    file_add='D:/Python_work/Data Mining/db250/'+ filename
    doc=open(file_add,encoding='utf-8').read()
    data=jieba.cut(doc) #文字分詞
    data_adj=''
    delete_word=[]
    for item in data:
        if item not in texts: #停用詞過濾
            data_adj+=item+' '
        else:
            delete_word.append(item)        
    corpus.append(data_adj) #語料庫建立完成

結果展示(corpus):

三、計算詞語的tfidf值,此部分程式碼主要參考大神博文:點選開啟連結

程式碼:

vectorizer=CountVectorizer()#該類會將文字中的詞語轉換為詞頻矩陣,矩陣元素a[i][j] 表示j詞在i類文字下的詞頻
transformer=TfidfTransformer()#該類會統計每個詞語的tf-idf權值
tfidf=transformer.fit_transform(vectorizer.fit_transform(corpus))#第一個fit_transform是計算tf-idf,第二個fit_transform是將文字轉為詞頻矩陣
weight=tfidf.toarray()#將tf-idf矩陣抽取出來,元素a[i][j]表示j詞在i類文字中的tf-idf權重
word=vectorizer.get_feature_names()#獲取詞袋模型中的所有詞

結果展示:


from sklearn.cluster import KMeans
mykms=KMeans(n_clusters=10)
y=mykms.fit_predict(weight)
for i in range(0,10):
    label_i=[]
    for j in range(0,len(y)):
        if y[j]==i:
            label_i.append(labels[j])
    print('label_'+str(i)+':'+str(label_i))

結果如下:

五、剛學機器學習不久,此篇文章純粹是作練習用,結果沒有什麼價值,此外對於Kmeans部分也只是簡單的呼叫,後續還需要進行更深入的學習。非科班出身,程式碼也是業餘時間的個人愛好,文章中的一些問題也歡迎各位大佬指出,也希望能結識喜歡機器學習的小夥伴,多交流,一起學習,一起成長!