【大数据】《红楼梦》作者分析(QDU)
- 【大數(shù)據(jù)】蔬菜價(jià)格分析(QDU)
- 【大數(shù)據(jù)】美國新冠肺炎疫情分析——錯誤版(QDU)
- 【大數(shù)據(jù)】美國新冠肺炎疫情分析——正確版(QDU)
- 【大數(shù)據(jù)】乳腺癌預(yù)測——老師給的鏈接(QDU)
- 由于kaggle上“貓狗大戰(zhàn)”的測試集標(biāo)簽是錯的,所以沒做出來,用的github上的代碼
- 【大數(shù)據(jù)】《紅樓夢》作者分析(QDU)
問題分析
《紅樓夢》是我國著名的四大名著之一,一般的認(rèn)為《紅樓夢》的前八十回為曹雪芹撰寫,后四十回為高鶚續(xù)寫,但也有學(xué)者對此并不認(rèn)可。
一般來說,不同的作者往往會具有不同的寫作風(fēng)格,這些風(fēng)格可以通過在文中的虛詞的頻率進(jìn)行衡量,因此,可以考慮統(tǒng)計(jì)各章中虛詞出現(xiàn)頻率,并以此作為基礎(chǔ)數(shù)據(jù)來聚類分析,對《紅樓夢》章節(jié)進(jìn)行劃分,從而分析章節(jié)與作者之間的關(guān)系。
解決思路
對比三種方式“K-Means聚類”、“層次聚類”和“DBSCAN”實(shí)現(xiàn)聚類效果上的區(qū)別,選擇最佳的聚類方式判斷《紅樓夢》的作者數(shù)。
數(shù)據(jù)處理
按行讀入txt文本,劃分章節(jié),對于每個(gè)章節(jié)統(tǒng)計(jì)總漢字個(gè)數(shù)和虛詞出現(xiàn)的個(gè)數(shù),記錄下每個(gè)章節(jié)的起始行號。
計(jì)算每個(gè)章節(jié)每種虛詞出現(xiàn)的頻率,以頻率作為依據(jù)進(jìn)行聚類分析。
總計(jì)120個(gè)章節(jié),46個(gè)虛詞。
統(tǒng)計(jì)虛詞個(gè)數(shù)時(shí)應(yīng)當(dāng)注意,'罷咧’和’罷了’的出現(xiàn)會過多統(tǒng)計(jì)’罷‘的個(gè)數(shù),因此對每個(gè)章節(jié)而言,統(tǒng)計(jì)完全部的行時(shí),應(yīng)當(dāng)將’罷‘的數(shù)量減去’罷咧’和’罷了’的數(shù)量。
劃分章節(jié)時(shí)需要判斷該章節(jié)關(guān)鍵詞的出現(xiàn)是因?yàn)槲闹刑峒吧匣剡€是作為新的章節(jié)的標(biāo)題,因?yàn)閷ι匣氐奶峒笆遣蛔鳛樾碌恼鹿?jié)進(jìn)行劃分的。
K-Means聚類
繪制分類數(shù)-DBI得分曲線,根據(jù)曲線變化確定最佳分類數(shù)。
戴維森堡丁指數(shù)(DBI),又稱為分類適確性指標(biāo),是由大衛(wèi)L·戴維斯和唐納德·Bouldin提出的一種評估聚類算法優(yōu)劣的指標(biāo)。首先假設(shè)我們有m個(gè)時(shí)間序列,這些時(shí)間序列聚類為nnn個(gè)簇。mmm個(gè)時(shí)間序列設(shè)為輸入矩陣XXX,nnn個(gè)簇類設(shè)為NNN作為參數(shù)傳入算法。使用下列公式進(jìn)行計(jì)算:
DBI=1N∑i=1Nmax?j≠i(Siˉ+Sjˉ∣∣wi?wj∣∣2)DBI=\frac{1}{N}\sum_{i=1}^N\max \limits_{j≠i}(\frac{\bar{S_i}+\bar{S_j}}{||w_i-w_j||_2}) DBI=N1?i=1∑N?j?=imax?(∣∣wi??wj?∣∣2?Si?ˉ?+Sj?ˉ??)
這個(gè)公式的含義是度量每個(gè)簇類最大相似度的均值。DBI的值最小是0,值越小,代表聚類效果越好。
繪制分類數(shù)-CH得分曲線,根據(jù)曲線變化確定最佳分類數(shù)。
CH分?jǐn)?shù)也稱之為 Calinski-Harabaz Index,這個(gè)計(jì)算簡單直接,得到的Calinski-Harabasz分?jǐn)?shù)值sss越大則聚類效果越好。
s(k)=Tr(Bk)Tr(Wk)×N?kk?1s(k)=\frac{Tr(B_k)}{Tr(W_k)}×\frac{N-k}{k-1} s(k)=Tr(Wk?)Tr(Bk?)?×k?1N?k?
其中
BkB_kBk?稱之為 between-clusters dispersion mean (簇間色散平均值)
WkW_kWk?稱之為 within-cluster dispersion (群內(nèi)色散之間)
它們的計(jì)算公式如下:
Wk=∑q=1k∑x∈cq(x?cq)(x?cq)TBk=∑qnq(cq?c)(cq?c)TW_k=\sum_{q=1}^k\sum_{x∈c_q}(x-c_q)(x-c_q)^T \\\\ B_k=\sum_{q}n_q(c_q-c)(c_q-c)^T Wk?=q=1∑k?x∈cq?∑?(x?cq?)(x?cq?)TBk?=q∑?nq?(cq??c)(cq??c)T
類別內(nèi)部數(shù)據(jù)的協(xié)方差越小越好,類別之間的協(xié)方差越大越好,這樣的Calinski-Harabasz分?jǐn)?shù)會高。
層次聚類
層次聚類(Hierarchical Clustering)是聚類算法的一種,基于層次的聚類算法(Hierarchical Clustering)可以是凝聚的(Agglomerative)或者分裂的(Divisive),取決于層次的劃分是“自底向上”還是“自頂向下”。
凝聚層次聚類原理是:最初將每個(gè)對象看成一個(gè)簇,然后將這些簇根據(jù)某種規(guī)則被一步步合并,就這樣不斷合并直到達(dá)到預(yù)設(shè)的簇類個(gè)數(shù)。
計(jì)算聚類簇之間的距離的方法:
計(jì)算聚類簇間距離的方法有三種,分別為Single Linkage,Complete Linkage和Average Linkage。
- Single Linkage:方法是將兩個(gè)組合數(shù)據(jù)點(diǎn)中距離最近的兩個(gè)數(shù)據(jù)點(diǎn)間的距離作為這兩個(gè)組合數(shù)據(jù)點(diǎn)的距離。這種方法容易受到極端值的影響。兩個(gè)不相似的組合數(shù)據(jù)點(diǎn)可能由于其中的某個(gè)極端的數(shù)據(jù)點(diǎn)距離較近而組合在一起。
- Complete Linkage:Complete Linkage的計(jì)算方法與Single Linkage相反,將兩個(gè)組合數(shù)據(jù)點(diǎn)中距離最遠(yuǎn)的兩個(gè)數(shù)據(jù)點(diǎn)間的距離作為這兩個(gè)組合數(shù)據(jù)點(diǎn)的距離。Complete Linkage的問題也與Single Linkage相反,兩個(gè)不相似的組合數(shù)據(jù)點(diǎn)可能由于其中的極端值距離較遠(yuǎn)而無法組合在一起。
- Average Linkage:Average Linkage的計(jì)算方法是計(jì)算兩個(gè)組合數(shù)據(jù)點(diǎn)中的每個(gè)數(shù)據(jù)點(diǎn)與其他所有數(shù)據(jù)點(diǎn)的距離。將所有距離的均值作為兩個(gè)組合數(shù)據(jù)點(diǎn)間的距離。這種方法計(jì)算量比較大,但結(jié)果比前兩種方法更合理。
DBSCAN
DBSCAN算法:
從樣本空間中任意選擇一個(gè)樣本,以事先給定的半徑做圓,凡被該圓圈中的樣本都視為與該樣本處于相同的聚類,以這些被圈中的樣本為圓心繼續(xù)做圓,重復(fù)以上過程,不斷擴(kuò)大被圈中樣本的規(guī)模,直到再也沒有新的樣本加入為止,至此即得到一個(gè)聚類。于剩余樣本中,重復(fù)以上過程,直到耗盡樣本空間中的所有樣本為止。
DBSCAN函數(shù)聚類效果主要取決于其參數(shù)eps和min_samples,因此在使用DBSCAN算法進(jìn)行聚類時(shí)主要問題就是確定這兩個(gè)參數(shù)的值。
采用遍歷的方法計(jì)算得分,以得分最大的參數(shù)作為最終參數(shù)。
解決方案
K-Means聚類
不同的得分計(jì)算方式下不同分類數(shù)對應(yīng)的效果
觀察兩條曲線,將DBI得分作為評判模型好壞的標(biāo)準(zhǔn)時(shí),可以發(fā)現(xiàn)隨著分類數(shù)的增多,分類得分先增多后減少,即分類效果先降低后升高;而采用CH得分作為指標(biāo)時(shí),分類效果隨著分類數(shù)的增多持續(xù)下降。
綜合兩條曲線的變化趨勢,可以總結(jié)出當(dāng)分類個(gè)數(shù)為2、3左右時(shí)分類效果最佳。
層次聚類
對比采用不同的linkage和不同的分類數(shù)對分類效果的影響,選取分類得分最高的作為分類算法
sklearn中的層次聚類函數(shù):
class sklearn.cluster.AgglomerativeClustering(n_clusters=2, affinity=’euclidean’, memory=None, connectivity=None, compute_full_tree=’auto’, linkage=’ward’, pooling_func=<function mean>)linkage:一個(gè)字符串,用于指定鏈接算法
- ‘ward’:單鏈接single-linkage,采用dmindmin
- ‘complete’:全鏈接complete-linkage算法,采用dmaxdmax
- ‘a(chǎn)verage’:均連接average-linkage算法,采用davgdavg
三種不同參數(shù)下得分隨分類數(shù)的變化曲線:
觀察曲線可以發(fā)現(xiàn),除平均值linkage方式外,另外兩種在分類數(shù)為2時(shí)都能使模型體現(xiàn)較佳的效果,因此選取ward作為linkage。
DBSCAN
首先,經(jīng)過大量測試,發(fā)現(xiàn)本實(shí)驗(yàn)中DBSCAN函數(shù)的min_samples參數(shù)值選3比較合適,因此只需要遍歷確定最佳的eps即可。
對于遍歷的每一種eps取值,都計(jì)算CH得分,選取CH得分最大時(shí)對應(yīng)的模型和eps。
最大CH得分及對應(yīng)模型聚類結(jié)果:
# 標(biāo)簽,其中-1表示孤立點(diǎn),0表示第一類 # 因此,可以看出DBSCAN只分得一類 [-1 0]# 每一章對應(yīng)的標(biāo)簽 [ 0 0 -1 0 0 0 0 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 0 -1 0 -1 0 00 0 0 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 0 -10 0 0 0 0 0 0 0 -1 -1 -1 -1 -1 -1 0 0 0 0 0 -1 0 0 0 -10 0 0 -1 -1 0 -1 -1 -1 -1 -1 -1 0 -1 -1 0 -1 -1 -1 -1 -1 0 -1 0]# eps 1.6363636363636362# 得分 61.796597508998026結(jié)果分析
對比三種方式下的CH得分可以發(fā)現(xiàn),與K-Means聚類和層次聚類相比,DBSCAN得分過低,因此不采用DBSCAN作為聚類的方法。
K-Means聚類和層次聚類得到的結(jié)果相對合理,因此對比兩種方式的聚類結(jié)果:
# K-Means聚類 [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 11 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1 0 0 11 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 0 0 1 0 0 1 1 0 0 0 0 01 0 0 0 1 0 1 0 1]# 層次聚類 [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 11 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 11 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 1 0 0 1 1 1 0 1 0 01 0 0 1 1 0 1 1 1]# 兩種聚類方式的相似度,即標(biāo)簽相同的個(gè)數(shù)與全部章節(jié)數(shù)之比 K-Means聚類與層次聚類結(jié)果的相似度:0.8666666666666667這說明兩種聚類結(jié)果比較相似,而且具有比較好的參考性。
可以判斷是兩個(gè)人共同完成的《紅樓夢》,但是對于其中一人完成前80章和另一人完成后80章的區(qū)分并不是很明顯。
總結(jié)展望
優(yōu)勢
局限性
附錄(代碼)
import re import numpy as np import matplotlib.pyplot as plt from sklearn import metrics # !!!不是keras的!!! from matplotlib.ticker import MaxNLocator# ------------------------ 數(shù)據(jù)處理 ------------------------def is_Chinese(ch):if '\u4e00' <= ch <= '\u9fff':return Truereturn Falsecell=['之','其','或','亦','方','于','即','皆','因','仍','故','尚','乃','呀','嗎','咧','罷咧','啊','罷','罷了','么','呢','了','的','著','一','不','把','讓','向','往','是','在','別','好','可','便','就','但','越','再','更','比','很','偏','兒']file = open('05.《紅樓夢》完整版.txt',encoding='utf-8') file_context=file.readlines() # print(len(file_context)) # 行數(shù)hui = 0 # 第幾回 row_num_start = [] # 每一回的開始段號 for i in range(0, len(file_context)):round = re.findall(u'第[一二三四五六七八九十百]+回', file_context[i])if (len(round) == 1) & (file_context[i][0] == '第') & (len(file_context[i]) < 30): # 唯一出現(xiàn)依次且位于段首,整行字?jǐn)?shù)不超過30個(gè)字,則判斷為新回row_num_start.append(i) # 保存每回的開始段號,本回的結(jié)束段號就是下回的開始段號前一個(gè)hui += 1# print(hui) # 總共120回 # print(len(cell)) # 總共46個(gè)虛詞 row_num_start.append(len(file_context)) # 文末frequency = [[0]*len(cell) for _ in range(hui)] # 統(tǒng)計(jì)頻次 # 注意不可以使用 [[0]*5]*6 的形式,會出現(xiàn)對二維列表中的某個(gè)位置進(jìn)行賦值,卻使得整一列都被賦值了的情況 frequency_rate = [[0]*len(cell) for _ in range(hui)] # 統(tǒng)計(jì)頻率 for i in range(0, hui):all_character_num = 0 # 某一回的全部漢字?jǐn)?shù)for j in range(row_num_start[i]+1, row_num_start[i+1]): # 遍歷某一回的全部行row_contxt = np.array(file_context[j])bool_row_context = (is_Chinese(row_contxt)) # bool數(shù)組all_character_num += np.sum(bool_row_context != 0) # 本行的漢字個(gè)數(shù)for k in range(0, len(cell)):frequency[i][k] += len(re.findall(cell[k],file_context[j]))# 罷咧rownum:16 罷rownum:18 罷了rownum:19frequency[i][18] -= frequency[i][16] + frequency[i][19] # “罷”的數(shù)數(shù)量要減去“罷了”和“罷咧”的數(shù)量for j in range(0, len(cell)):frequency_rate[i][j] = frequency[i][j] / all_character_num# ------------------------ K-means聚類 ------------------------from sklearn.cluster import KMeanstest_classifiation_num = 50 # 繪制DBI曲線 preds = [] for i in np.arange(2,test_classifiation_num):y_pred = KMeans(n_clusters=i, random_state=9).fit_predict(frequency_rate)preds.append(metrics.davies_bouldin_score(frequency_rate, y_pred)) # 戴維森堡丁指數(shù)(DBI) # DBI的值最小是0,值越小,代表聚類效果越好。 plt.subplot(121) plt.plot(np.arange(2, test_classifiation_num), preds) plt.gca().xaxis.set_major_locator(MaxNLocator(integer=True)) # 坐標(biāo)軸顯示為整數(shù) plt.xlabel('classifiation_number', fontsize=14) plt.ylabel('davies_bouldin_score', fontsize=14)# 繪制CH得分曲線 preds = [] for i in np.arange(2,test_classifiation_num):y_pred = KMeans(n_clusters=i, random_state=9).fit_predict(frequency_rate)preds.append(metrics.calinski_harabasz_score(frequency_rate, y_pred)) # CH分?jǐn)?shù) # 值越大效果越好 plt.subplot(122) plt.plot(np.arange(2, test_classifiation_num), preds) plt.gca().xaxis.set_major_locator(MaxNLocator(integer=True)) # 坐標(biāo)軸顯示為整數(shù) plt.xlabel('classifiation_number', fontsize=14) plt.ylabel('calinski_harabasz_score', fontsize=14)plt.suptitle('K-Means', fontsize=15) plt.show()# 觀察曲線變化可以發(fā)現(xiàn),選取二聚類和三聚類效果相對可能會好# ------------------------ 層次聚類 ------------------------ from sklearn import clusterfig=plt.figure() ax=fig.add_subplot(1,1,1) markers="+o*"linkages=['ward','complete','average'] nums=range(2, test_classifiation_num)for i, linkage in enumerate(linkages):preds = []for num in nums:clst = cluster.AgglomerativeClustering(n_clusters=num, linkage=linkage)predicted_labels = clst.fit_predict(frequency_rate)preds.append(metrics.calinski_harabasz_score(frequency_rate, predicted_labels))ax.plot(nums, preds, marker=markers[i], label="linkage:%s" % linkage)ax.set_xlabel("n_clusters", fontsize=14) ax.set_ylabel("calinski_harabasz_score", fontsize=14) ax.legend(loc="best") fig.suptitle("AgglomerativeClustering", fontsize=15) plt.show()# 觀察發(fā)現(xiàn)linkage選取ward比較平穩(wěn),且二聚類的得分最高,這與K-means的結(jié)果類似# ------------------------ DBSCAN ------------------------from sklearn.cluster import DBSCAN models, scores = [], [] epsilons = np.linspace(0.5, 3, 100)for eps in epsilons:model = DBSCAN(eps=eps, min_samples=3)model.fit(frequency_rate)if np.unique(model.labels_).shape[0] < 2: # 保證分類數(shù)至少為2,只分一組沒法使用calinski_harabasz_score,會報(bào)錯continuescore = metrics.calinski_harabasz_score(frequency_rate, model.labels_)models.append(model)scores.append(score)index = np.array(scores).argmax() # 最大得分對應(yīng)的索引 best_model = models[index] best_eps = epsilons[index] best_score = scores[index]predicted_labels = np.unique(best_model.labels_) print(predicted_labels) # [-1 0] print(best_model.labels_) print(best_eps) # 1.6363636363636362 print(best_score) # 61.796597508998026# DBSCAN的得分太低了KMeans_predict = KMeans(n_clusters=2, random_state=9).fit_predict(frequency_rate) print(KMeans_predict) AgglomerativeClustering_predict = \(np.array(cluster.AgglomerativeClustering(n_clusters=2, linkage='ward').fit_predict(frequency_rate)) == 0).astype(int) print(AgglomerativeClustering_predict)print('K-Means聚類與層次聚類結(jié)果的相似度:', np.sum((KMeans_predict == AgglomerativeClustering_predict) == 1) / hui) # 0.8666666666666667總結(jié)
以上是生活随笔為你收集整理的【大数据】《红楼梦》作者分析(QDU)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Excel实现报表
- 下一篇: SHA256sum系列命令检测文件完整性