聚類算法:鑑別《紅樓夢》120回是否同一作者所著?

第一次看到老師給的題目的時候,我就很懷疑:通過每個章回虛詞出現的頻率(頻數),就能判別是否是同一作者?

大概出現的虛詞:

cell=['之','其','或','亦','方','於','即','皆','因','仍','故','尚','乃','呀','嗎','咧','罷咧','啊','罷','罷了','麼','呢','了','的','著','一','不','把','讓','向','往','是','在','別','好','可','便','就','但','越','再','更','比','很','偏','兒']

當然,首先考慮到:比如說“之”這個字,就有很多用法,1 助詞 2動詞 3代詞,而動詞是不屬於虛詞的,但是怎麼判斷文章中出現的”之“是不是虛詞呢?好像得用到語義分析,但是某文智系統都不靠譜:

聚類算法:鑑別《紅樓夢》120回是否同一作者所著?

就算了吧,就簡單實現一下對特定的這45個字(詞)的每章回出現的頻率(頻數)進行統計就完事了。

先挖個坑,如果以後有時間的話,研究研究文本的特徵挖掘,寫個[下](估計是不太可能了)。

首先,讀入txt文件。[該txt中一行代表一個段落]

<code>file=open('redmansiondream.txt',encoding="ansi")
file_context=file.readlines()/<code>

這樣就把txt中的信息存到列表file_context裡了,每個內容代表一個段落中所有的文字。

其次,使用正則表達式分割file_context,本代碼採用的是判斷”第XXX回“出現的段號,即file_context中內容為"第XXX回"的下標,並把每回的開始段號和結束段號存儲在二維數組中。

(ps:習慣了C和mat的for循環 python的for不太習慣 所以循環都是用的while)

<code>t=0 #第t回
#提取每個章回的開始結束段號
while i key=re.compile(u'第[\\\\u4e00-\\\\u9fa5]{0,6}回') #正則表達式查找字符串‘第X回’ 其中X長度為[0,6]

pa=re.findall(key,file_context[i])
if (len(pa)==1) & (file_context[i][0]=='第')& (len(file_context[i])<30):#因內容中有提及之前章回之嫌,判斷字符串是否位於段首
t=t+1
index[t-1][0]=i#開始段號
if t!=1:
index[t-2][1]=i #結束段號
i=i+1
index[119][1]=len(file_context)-2 #最後一回段號
/<code>

這樣,我們就得出了每一回的起始段號和結束段號,就相當於實現了”分割“。

之後,對於每一回,分別計算出45個指定的字出現的次數,並儲存在二維數組中。

data1 儲存頻率,data2儲存頻數

<code>i=0
while i<120:
start=index[i][0]+1
end=index[i][1]
num=0;#統計該章回總共字數 回車符不計
while start num=num+len(file_context[int(start)])-1;
start=start+1
c=0
while c data2[i][c]=data2[i][c]+len(re.findall(cell[c],file_context[int(start)])) #匹配得到的次數累加
c=c+1
#得出的結果 比如 '罷'的次數中包括'罷咧'的次數 應減減去
k1=0
while k1 k2=0

while k2 if k1!=k2:
if (cell[k1] in cell[k2])==True: #判斷是否是子串 如果是 前者的值變為前者的值減後者的值
data2[i][k1]=data2[i][k1]-data2[i][k2]
k2=k2+1
k1=k1+1
#求頻率
k=0
while k data1[i][k]=data2[i][k]*1000/num; #數值太小 統一乘以1000
k=k+1;
i=i+1
/<code>

從而得出頻率和頻數。

首先使用K-means算法進行聚類:

自己寫的k-means(有點長亂,可以略過):

<code>#2_means-----(頻數版)
k1=np.zeros(46)
k2=np.zeros(46)
i=0
#隨機初始化2類均值 直接指定第11段為一類 101段為2類
while i k1[i]=data2[10][i]
k2[i]=data2[100][i]
i=i+1
classi=np.zeros(120) #每一回章所屬於的類別 取值 1或 2
while True:
ret=1 #判斷是否退出循環的條件

d=0
while d c=0
dis1=0
dis2=0
while c dis1+=(data2[d][c]-k1[c])*(data2[d][c]-k1[c])
dis2+=(data2[d][c]-k2[c])*(data2[d][c]-k2[c])
c=c+1
dis1=math.sqrt(dis1)
dis2=math.sqrt(dis2)
class_old=classi[d]
if dis1<=dis2:
classi[d]=1
else:
classi[d]=2
if class_old!=classi[d]:
ret=0
d=d+1
#重新計算兩類均值 先清0
num1=0
num2=0
com=0
i=0
while i k1[i]=0
k2[i]=0
i=i+1

while com if classi[com]==1:
num1+=1
cop=0
while cop k1[cop]+=data2[com][cop];
cop+=1

else:
num2+=1
cop=0
while cop k2[cop]+=data2[com][cop];
cop+=1
com+=1
cop=0
while cop k1[cop]=math.sqrt(k1[cop])
k2[cop]=math.sqrt(k2[cop])
cop+=1

if ret==1:
break


i=0
/<code>


直接使用sklearn自帶的包:

<code>from sklearn.cluster import KMeans
model=KMeans(n_clusters=2)
s=model.fit(data2)
print(model.labels_)/<code>


最後兩者分別得出的結果如下:

聚類算法:鑑別《紅樓夢》120回是否同一作者所著?

聚類算法:鑑別《紅樓夢》120回是否同一作者所著?

總體看來這兩個類分佈的錯落有致,無法區分(我就說怎麼可能靠譜)

試試用決策樹分類的效果:令前10個為1類(label 0),後10個為2類(label 1),對中間100回進行預測:

<code>from sklearn.ensemble import RandomForestRegressor  
X_train=np.concatenate((data2[:10],data2[110:]),0)
Y_train=np.array([0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,])
rf=RandomForestRegressor(46)
rf.fit(X_train,Y_train)
X_test=np.concatenate((data2[10:50],data2[50:110]),0)
Y_test=rf.predict(X_test)

i=0
while i Y_test[i]=round(Y_test[i])
i=i+1
/<code>



結果如下:

聚類算法:鑑別《紅樓夢》120回是否同一作者所著?

<code>
貌似效果和K-means差不多。
 
然後再試試層次聚類的效果:

import scipy.cluster.hierarchy as sch
import matplotlib.pylab as plt
disMat = sch.distance.pdist(data2,'euclidean')
Z=sch.linkage(disMat,method='average')
P=sch.dendrogram(Z)
plt.savefig('C:/Users/71405/Desktop/大數據分析/14/plot_dendrogram.png')/<code>
聚類算法:鑑別《紅樓夢》120回是否同一作者所著?

結果:

(啥都看不清。。。。)

就這樣了,效果很差,以後有時間研究一下特徵提取,來代替虛詞詞頻。

完整的越到後越懶得寫註釋的代碼:

<code># -*- coding: utf-8 -*-
"""
Created on Thu May 31 08:24:07 2018
@author: Type真是太帥了
"""
import re
import numpy as np
import math
data1=np.zeros((120,46)) #儲存120回中的46個虛詞的出現頻率
data2=np.zeros((120,46)) #儲存120回中的46個虛詞的出現頻數
index=np.zeros((120,2)) #統計每回開始的段號和結束的段號(均不包括)
cell=['之','其','或','亦','方','於','即','皆','因','仍','故','尚','乃','呀','嗎','咧','罷咧','啊','罷','罷了','麼','呢','了','的','著','一','不','把','讓','向','往','是','在','別','好','可','便','就','但','越','再','更','比','很','偏','兒']
file=open('redmansiondream.txt',encoding="ansi")
file_context=file.readlines() #把所有內容讀入到file_context裡
i=1
t=0 #第t回
#提取每個章回的開始結束段號
while i key=re.compile(u'第[\\\\u4e00-\\\\u9fa5]{0,6}回') #正則表達式查找字符串‘第X回’ 其中X長度為[0,6]
pa=re.findall(key,file_context[i])
if (len(pa)==1) & (file_context[i][0]=='第')& (len(file_context[i])<30):#因內容中有提及之前章回之嫌,判斷字符串是否位於段首
t=t+1
index[t-1][0]=i#開始段號
if t!=1:
index[t-2][1]=i #結束段號
i=i+1
index[119][1]=len(file_context)-2 #最後一回段號


i=0
while i<120:

start=index[i][0]+1
end=index[i][1]
num=0;#統計該章回總共字數 回車符不計
while start num=num+len(file_context[int(start)])-1;
start=start+1
c=0
while c data2[i][c]=data2[i][c]+len(re.findall(cell[c],file_context[int(start)])) #匹配得到的次數累加
c=c+1
#得出的結果 比如 '罷'的次數中包括'罷咧'的次數 應減減去
k1=0
while k1 k2=0
while k2 if k1!=k2:
if (cell[k1] in cell[k2])==True: #判斷是否是子串 如果是 前者的值變為前者的值減後者的值
data2[i][k1]=data2[i][k1]-data2[i][k2]
k2=k2+1
k1=k1+1
#求頻率
k=0
while k data1[i][k]=data2[i][k]*1000/num; #數值太小 統一乘以1000
k=k+1;
i=i+1



#2_means-----(頻數版)
k1=np.zeros(46)
k2=np.zeros(46)
i=0
#隨機初始化2類均值
while i k1[i]=data2[10][i]
k2[i]=data2[100][i]
i=i+1
classi=np.zeros(120) #每一回章所屬於的類別 取值 1或 2
while True:

ret=1 #判斷是否退出循環的條件
d=0
while d c=0
dis1=0
dis2=0
while c dis1+=(data2[d][c]-k1[c])*(data2[d][c]-k1[c])
dis2+=(data2[d][c]-k2[c])*(data2[d][c]-k2[c])
c=c+1
dis1=math.sqrt(dis1)
dis2=math.sqrt(dis2)
class_old=classi[d]
if dis1<=dis2:
classi[d]=1
else:
classi[d]=2
if class_old!=classi[d]:
ret=0
d=d+1
#重新計算兩類均值 先清0
num1=0
num2=0
com=0
i=0
while i k1[i]=0
k2[i]=0
i=i+1

while com if classi[com]==1:
num1+=1
cop=0
while cop k1[cop]+=data2[com][cop];
cop+=1

else:
num2+=1
cop=0
while cop k2[cop]+=data2[com][cop];
cop+=1
com+=1
cop=0
while cop k1[cop]=math.sqrt(k1[cop])

k2[cop]=math.sqrt(k2[cop])
cop+=1
if ret==1:
break


i=0

from sklearn.cluster import KMeans
model=KMeans(n_clusters=2)
s=model.fit(data2)
print(model.labels_)

from sklearn.ensemble import RandomForestRegressor
X_train=np.concatenate((data2[:10],data2[110:]),0)
Y_train=np.array([0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,])
rf=RandomForestRegressor(46)
rf.fit(X_train,Y_train)
X_test=np.concatenate((data2[10:50],data2[50:110]),0)
Y_test=rf.predict(X_test)
i=0
while i Y_test[i]=round(Y_test[i])
i=i+1

import scipy.cluster.hierarchy as sch
import matplotlib.pylab as plt
disMat = sch.distance.pdist(data2,'euclidean')
Z=sch.linkage(disMat,method='average')
P=sch.dendrogram(Z)
plt.savefig('C:/Users/71405/Desktop/大數據分析/14/plot_dendrogram.png')
/<code>


分享到:


相關文章: