更新時(shí)間:2022年02月09日17時(shí)41分 來源:傳智教育 瀏覽次數(shù):
文本數(shù)據(jù)分析能夠有效幫助我們理解數(shù)據(jù)語料, 快速檢查出語料可能存在的問題, 并指導(dǎo)之后模型訓(xùn)練過程中一些超參數(shù)的選擇.
我們將基于真實(shí)的中文酒店評(píng)論語料來講解常用的幾種文本數(shù)據(jù)分析方法.
屬于二分類的中文情感分析語料, 該語料存放在"./cn_data"目錄下.其中train.tsv代表訓(xùn)練集, dev.tsv代表驗(yàn)證集, 二者數(shù)據(jù)樣式相同.
該train.tsv數(shù)據(jù)樣式:
sentence label 早餐不好,服務(wù)不到位,晚餐無西餐,早餐晚餐相同,房間條件不好,餐廳不分吸煙區(qū).房間不分有無煙房. 0 去的時(shí)候 ,酒店大廳和餐廳在裝修,感覺大廳有點(diǎn)擠.由于餐廳裝修本來該享受的早飯,也沒有享受(他們是8點(diǎn)開始每個(gè)房間送,但是我時(shí)間來不及了)不過前臺(tái)服務(wù)員態(tài)度好! 1 有很長時(shí)間沒有在西藏大廈住了,以前去北京在這里住的較多。這次住進(jìn)來發(fā)現(xiàn)換了液晶電視,但網(wǎng)絡(luò)不是很好,他們自己說是收費(fèi)的原因造成的。其它還好。 1 非常好的地理位置,住的是豪華海景房,打開窗戶就可以看見棧橋和海景。記得很早以前也住過,現(xiàn)在重新裝修了??偟膩碚f比較滿意,以后還會(huì)住 1 交通很方便,房間小了一點(diǎn),但是干凈整潔,很有香港的特色,性價(jià)比較高,推薦一下哦 1 酒店的裝修比較陳舊,房間的隔音,主要是衛(wèi)生間的隔音非常差,只能算是一般的 0 酒店有點(diǎn)舊,房間比較小,但酒店的位子不錯(cuò),就在海邊,可以直接去游泳。8樓的海景打開窗戶就是海。如果想住在熱鬧的地帶,這里不是一個(gè)很好的選擇,不過威海城市真的比較小,打車還是相當(dāng)便宜的。晚上酒店門口出租車比較少。 1 位置很好,走路到文廟、清涼寺5分鐘都用不了,周邊公交車很多很方便,就是出租車不太愛去(老城區(qū)路窄愛堵車),因?yàn)槭抢腺e館所以設(shè)施要陳舊些, 1 酒店設(shè)備一般,套房里臥室的不能上網(wǎng),要到客廳去。 0
train.tsv中的數(shù)據(jù)內(nèi)容共分為2列, 第一列數(shù)據(jù)代表具有感情色彩的評(píng)論文本; 第二列數(shù)據(jù), 0或1, 代表每條文本數(shù)據(jù)是積極或者消極的評(píng)論, 0代表消極, 1代表積極.
# 導(dǎo)入必備工具包 import seaborn as sns import pandas as pd import matplotlib.pyplot as plt # 設(shè)置顯示風(fēng)格 plt.style.use('fivethirtyeight') # 分別讀取訓(xùn)練tsv和驗(yàn)證tsv train_data = pd.read_csv("./cn_data/train.tsv", sep="\t") valid_data = pd.read_csv("./cn_data/dev.tsv", sep="\t") # 獲得訓(xùn)練數(shù)據(jù)標(biāo)簽數(shù)量分布 sns.countplot("label", data=train_data) plt.title("train_data") plt.show() # 獲取驗(yàn)證數(shù)據(jù)標(biāo)簽數(shù)量分布 sns.countplot("label", data=valid_data) plt.title("valid_data") plt.show()
注意:在深度學(xué)習(xí)模型評(píng)估中, 我們一般使用ACC作為評(píng)估指標(biāo), 若想將ACC的基線定義在50%左右, 則需要我們的正負(fù)樣本比例維持在1:1左右, 否則就要進(jìn)行必要的數(shù)據(jù)增強(qiáng)或數(shù)據(jù)刪減. 上圖中訓(xùn)練和驗(yàn)證集正負(fù)樣本都稍有不均衡, 可以進(jìn)行一些數(shù)據(jù)增強(qiáng)。
# 在訓(xùn)練數(shù)據(jù)中添加新的句子長度列, 每個(gè)元素的值都是對(duì)應(yīng)的句子列的長度 train_data["sentence_length"] = list(map(lambda x: len(x), train_data["sentence"])) # 繪制句子長度列的數(shù)量分布圖 sns.countplot("sentence_length", data=train_data) # 主要關(guān)注count長度分布的縱坐標(biāo), 不需要繪制橫坐標(biāo), 橫坐標(biāo)范圍通過dist圖進(jìn)行查看 plt.xticks([]) plt.show() # 繪制dist長度分布圖 sns.distplot(train_data["sentence_length"]) # 主要關(guān)注dist長度分布橫坐標(biāo), 不需要繪制縱坐標(biāo) plt.yticks([]) plt.show() # 在驗(yàn)證數(shù)據(jù)中添加新的句子長度列, 每個(gè)元素的值都是對(duì)應(yīng)的句子列的長度 valid_data["sentence_length"] = list(map(lambda x: len(x), valid_data["sentence"])) # 繪制句子長度列的數(shù)量分布圖 sns.countplot("sentence_length", data=valid_data) # 主要關(guān)注count長度分布的縱坐標(biāo), 不需要繪制橫坐標(biāo), 橫坐標(biāo)范圍通過dist圖進(jìn)行查看 plt.xticks([]) plt.show() # 繪制dist長度分布圖 sns.distplot(valid_data["sentence_length"]) # 主要關(guān)注dist長度分布橫坐標(biāo), 不需要繪制縱坐標(biāo) plt.yticks([]) plt.show()
通過繪制句子長度分布圖, 可以得知我們的語料中大部分句子長度的分布范圍, 因?yàn)槟P偷妮斎胍鬄楣潭ǔ叽绲膹埩浚侠淼拈L度范圍對(duì)之后進(jìn)行句子截?cái)嘌a(bǔ)齊(規(guī)范長度)起到關(guān)鍵的指導(dǎo)作用. 上圖中大部分句子長度的范圍大致為20-250之間。
# 繪制訓(xùn)練集長度分布的散點(diǎn)圖 sns.stripplot(y='sentence_length',x='label',data=train_data) plt.show() # 繪制驗(yàn)證集長度分布的散點(diǎn)圖 sns.stripplot(y='sentence_length',x='label',data=valid_data) plt.show()
通過查看正負(fù)樣本長度散點(diǎn)圖, 可以有效定位異常點(diǎn)的出現(xiàn)位置, 幫助我們更準(zhǔn)確進(jìn)行人工語料審查. 上圖中在訓(xùn)練集正樣本中出現(xiàn)了異常點(diǎn), 它的句子長度近3500左右, 需要我們?nèi)斯彶椤?/p>
# 導(dǎo)入jieba用于分詞 # 導(dǎo)入chain方法用于扁平化列表 import jieba from itertools import chain # 進(jìn)行訓(xùn)練集的句子進(jìn)行分詞, 并統(tǒng)計(jì)出不同詞匯的總數(shù) train_vocab = set(chain(*map(lambda x: jieba.lcut(x), train_data["sentence"]))) print("訓(xùn)練集共包含不同詞匯總數(shù)為:", len(train_vocab)) # 進(jìn)行驗(yàn)證集的句子進(jìn)行分詞, 并統(tǒng)計(jì)出不同詞匯的總數(shù) valid_vocab = set(chain(*map(lambda x: jieba.lcut(x), valid_data["sentence"]))) print("訓(xùn)練集共包含不同詞匯總數(shù)為:", len(valid_vocab))
輸出效果:
訓(xùn)練集共包含不同詞匯總數(shù)為: 12147 訓(xùn)練集共包含不同詞匯總數(shù)為: 6857
# 使用jieba中的詞性標(biāo)注功能 import jieba.posseg as pseg def get_a_list(text): """用于獲取形容詞列表""" # 使用jieba的詞性標(biāo)注方法切分文本,獲得具有詞性屬性flag和詞匯屬性word的對(duì)象, # 從而判斷flag是否為形容詞,來返回對(duì)應(yīng)的詞匯 r = [] for g in pseg.lcut(text): if g.flag == "a": r.append(g.word) return r # 導(dǎo)入繪制詞云的工具包 from wordcloud import WordCloud def get_word_cloud(keywords_list): # 實(shí)例化繪制詞云的類, 其中參數(shù)font_path是字體路徑, 為了能夠顯示中文, # max_words指詞云圖像最多顯示多少個(gè)詞, background_color為背景顏色 wordcloud = WordCloud(font_path="./SimHei.ttf", max_words=100, background_color="white") # 將傳入的列表轉(zhuǎn)化成詞云生成器需要的字符串形式 keywords_string = " ".join(keywords_list) # 生成詞云 wordcloud.generate(keywords_string) # 繪制圖像并顯示 plt.figure() plt.imshow(wordcloud, interpolation="bilinear") plt.axis("off") plt.show() # 獲得訓(xùn)練集上正樣本 p_train_data = train_data[train_data["label"]==1]["sentence"] # 對(duì)正樣本的每個(gè)句子的形容詞 train_p_a_vocab = chain(*map(lambda x: get_a_list(x), p_train_data)) #print(train_p_n_vocab) # 獲得訓(xùn)練集上負(fù)樣本 n_train_data = train_data[train_data["label"]==0]["sentence"] # 獲取負(fù)樣本的每個(gè)句子的形容詞 train_n_a_vocab = chain(*map(lambda x: get_a_list(x), n_train_data)) # 調(diào)用繪制詞云函數(shù) get_word_cloud(train_p_a_vocab) get_word_cloud(train_n_a_vocab)
驗(yàn)證集正樣本形容詞詞云:
獲得驗(yàn)證集上正負(fù)的樣本的形容詞詞云
# 獲得驗(yàn)證集上正樣本 p_valid_data = valid_data[valid_data["label"]==1]["sentence"] # 對(duì)正樣本的每個(gè)句子的形容詞 valid_p_a_vocab = chain(*map(lambda x: get_a_list(x), p_valid_data)) #print(train_p_n_vocab) # 獲得驗(yàn)證集上負(fù)樣本 n_valid_data = valid_data[valid_data["label"]==0]["sentence"] # 獲取負(fù)樣本的每個(gè)句子的形容詞 valid_n_a_vocab = chain(*map(lambda x: get_a_list(x), n_valid_data)) # 調(diào)用繪制詞云函數(shù) get_word_cloud(valid_p_a_vocab) get_word_cloud(valid_n_a_vocab)
根據(jù)高頻形容詞詞云顯示, 我們可以對(duì)當(dāng)前語料質(zhì)量進(jìn)行簡單評(píng)估, 同時(shí)對(duì)違反語料標(biāo)簽含義的詞匯進(jìn)行人工審查和修正, 來保證絕大多數(shù)語料符合訓(xùn)練標(biāo)準(zhǔn). 上圖中的正樣本大多數(shù)是褒義詞, 而負(fù)樣本大多數(shù)是貶義詞, 基本符合要求, 但是負(fù)樣本詞云中也存在"便利"這樣的褒義詞, 因此可以人工進(jìn)行審查。
什么是數(shù)據(jù)分析?數(shù)據(jù)分析有什么作用?
北京校區(qū)