99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁精彩閱讀震驚!用Python探索《紅樓夢》的人物關系
震驚!用Python探索《紅樓夢》的人物關系
2022-08-09
收藏

文 | 周蘿卜

來源:Python 技術「ID: pythonall」

相信很多人都知道,《紅樓夢》就是中國古典小說的巔峰之作,太多人沉迷其中,而紅學也經(jīng)久不衰。當然今天我們不是來探究小說的,而是通過 Python 來探索下紅樓夢里那千絲萬縷的人物關系

開干~

數(shù)據(jù)準備

  • 紅樓夢 txt 電子書一份
  • 金陵十二釵 + 賈寶玉 人物名稱列表寶玉 nr
    黛玉 nr
    寶釵 nr
    湘云 nr
    鳳姐 nr
    李紈 nr
    元春 nr
    迎春 nr
    探春 nr
    惜春 nr
    妙玉 nr
    巧姐 nr
    秦氏 nr

該分列表是為了做分詞時使用,后面的 nr 就是人名的意思

人物出鏡次數(shù)

首先讀取小說

with open("紅樓夢.txt", encoding="gb18030") as f:    honglou = f.read()

接下來進行出場次數(shù)數(shù)據(jù)整理

honglou = honglou.replace("n", " ")honglou_new = honglou.split(" ")renwu_list = ['寶玉', '黛玉', '寶釵', '湘云', '鳳姐', '李紈', '元春', '迎春', '探春', '惜春', '妙玉', '巧姐', '秦氏']renwu = pd.DataFrame(data=renwu_list, columns=['姓名'])renwu['出現(xiàn)次數(shù)'] = renwu.apply(lambda x: len([k for k in honglou_new if x[u'姓名'] in k]), axis=1)renwu.to_csv('renwu.csv', index=False, sep=',')renwu.sort_values('出現(xiàn)次數(shù)', ascending=False, inplace=True)attr = renwu['姓名'][0:12]v1 = renwu['出現(xiàn)次數(shù)'][0:12]

這樣我們就得到了 attr 和 v1 兩個數(shù)據(jù),內容如下

下面就可以通過 pyecharts 來繪制柱狀圖

bar = (    Bar()    .add_xaxis(attr.tolist())    .add_yaxis("上鏡次數(shù)", v1.tolist())    .set_global_opts(title_opts=opts.TitleOpts(title="紅樓夢上鏡13人")))bar.render_notebook()

人物關系

數(shù)據(jù)處理

我們先將讀取到內存中的小說內容進行 jieba 分詞處理

import jiebajieba.load_userdict("renwu_forcut")renwu_data = pd.read_csv("renwu_forcut", header=-1)mylist = [k[0].split(" ")[0] for k in renwu_data.values.tolist()]

通過 load_userdict 將我們上面自定義的詞典加載到了 jieba 庫中

接下來進行分詞處理

tmpNames = []names = {}relationships = {}for h in honglou:    h.replace("賈妃", "元春")    h.replace("李宮裁", "李紈")    poss = pseg.cut(h)    tmpNames.append([]) for w in poss: if w.flag != 'nr' or len(w.word) != 2 or w.word not in mylist: continue tmpNames[-1].append(w.word) if names.get(w.word) is None:            names[w.word] = 0 relationships[w.word] = {}        names[w.word] += 1

因為文中"賈妃", "元春","李宮裁", "李紈" 等人物名字混用嚴重,所以這里做替換處理。

然后使用 jieba 庫提供的 pseg 工具來做分詞處理,會返回每個分詞的詞性。

之后做判斷,只有符合要求且在我們提供的字典列表里的分詞,才會保留。

一個人每出現(xiàn)一次,就會增加一,方便后面畫關系圖時,人物 node 大小的確定。

對于存在于我們自定義詞典的人名,保存到一個臨時變量當中 tmpNames

下面處理每個段落中的人物關系

for name in tmpNames:        for name1 in name:            for name2 in name:                if name1 == name2:                    continue                if relationships[name1].get(name2) is None:                    relationships[name1][name2] = 1                else:                    relationships[name1][name2] += 1

對于出現(xiàn)在同一個段落中的人物,我們認為他們是關系緊密的,同時每出現(xiàn)一次,關系增加1

最后可以把相關信息保存到文件當中

with open("relationship.csv", "w", encoding='utf-8') as f:        f.write("Source,Target,Weightn") for name, edges in relationships.items(): for v, w in edges.items():                f.write(name + "," + v + "," + str(w) + "n")with open("NameNode.csv", "w", encoding='utf-8') as f:    f.write("ID,Label,Weightn") for name, times in names.items():        f.write(name + "," + name + "," + str(times) + "n")

文件1:人物關系表,包含首先出現(xiàn)的人物、之后出現(xiàn)的人物和一同出現(xiàn)次數(shù)

文件2:人物比重表,包含該人物總體出現(xiàn)次數(shù),出現(xiàn)次數(shù)越多,認為所占比重越大

數(shù)據(jù)分析

下面我們可以做一些簡單的人物關系分析

這里我們還是使用 pyecharts 繪制圖表

def deal_graph():    relationship_data = pd.read_csv('relationship.csv')    namenode_data = pd.read_csv('NameNode.csv')    relationship_data_list = relationship_data.values.tolist()    namenode_data_list = namenode_data.values.tolist()    nodes = [] for node in namenode_data_list: if node[0] == "寶玉":            node[2] = node[2]/3 nodes.append({"name": node[0], "symbolSize": node[2]/30})    links = [] for link in relationship_data_list:        links.append({"source": link[0], "target": link[1], "value": link[2]})    g = (        Graph()        .add("", nodes, links, repulsion=8000)        .set_global_opts(title_opts=opts.TitleOpts(title="紅樓人物關系"))    ) return g

首先把兩個文件通過 pandas 讀取到內存當中

對于“寶玉”,由于其占比過大,如果統(tǒng)一進行縮放,會導致其他人物的 node 過小,展示不美觀,所以這里先做了一次縮放

最后我們得到的人物關系圖如下

好了,這就是今天分享的全部內容,我們下次再見~


數(shù)據(jù)分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數(shù)據(jù)分析師考試動態(tài)
數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調用 initGeetest 進行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調,回調的第一個參數(shù)驗證碼對象,之后可以使用它調用相應的接口 initGeetest({ // 以下 4 個配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗服務器是否宕機 new_captcha: data.new_captcha, // 用于宕機時表示是新驗證碼的宕機 product: "float", // 產品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計時完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }