自從18年10月底開始課余在導師的公司實習窟感,不知不覺入坑機器學習和深度學習已經(jīng)小半年時間。目前的主要方向是NLP和數(shù)據(jù)挖掘歉井。
這期間接觸了許多新的知識,見識了火熱的深度學習的魅力和實際應用哈误,也認識了很多浙大的牛人哩至,有很多感觸躏嚎。
這篇文章,是對我近期做的情感分析demo的一個總結(jié)菩貌;但正因為它簡單又內(nèi)容豐富卢佣,相信會幫助即便外行的讀者,也能對爬蟲和深度學習有新的認識箭阶。
全文共計3800余字虚茶,閱讀時間預計10分鐘。閱讀完本文仇参,你將學習到:
01 如何安裝使用python
02 如何用python爬取數(shù)據(jù)
03 如何使用pandas嘹叫、numpy做簡單的數(shù)據(jù)處理
04 如何調(diào)用bert-as-service,快速得到中文詞向量
05 如何使用深度學習框架keras建模诈乒,做簡單的情感分析
01 如何安裝使用Python
安裝python
的方式很多罩扇,而Mac os
和Ubuntu
等操作系統(tǒng)甚至已經(jīng)預裝了python
。
但是怕磨,我還是強烈推薦你安裝Anaconda
套裝喂饥。它是一個開源的python發(fā)行版本,包含了180多個科學包及其依賴項肠鲫,其中很多工具包對于后期機器學習的研究非常重要员帮。所以第一次就安裝它,可以“一勞永逸”导饲。
進入Anaconda
官網(wǎng)的下載頁面捞高,可以根據(jù)你使用的系統(tǒng)下載最新版本的conda
。如果你想下載歷史版本的Anaconda
帜消,可以點擊此鏈接
此后棠枉,根據(jù)中文提示一步步安裝即可,非常簡單方便泡挺。
Windows
下稱“命令提示符”),我們使用conda
創(chuàng)建一個虛擬環(huán)境娄猫,這樣可以和系統(tǒng)中原有的python環(huán)境相隔離贱除。
如圖,我們創(chuàng)建了一個python3.6
版本的虛擬環(huán)境媳溺,使用conda env list
可以查看我們當前所有虛擬環(huán)境(目前只有py36)月幌,然后source activate py36
激活它。
到此悬蔽,python
最基礎的環(huán)境搭建全部完成啦扯躺。
02 如何用python爬取數(shù)據(jù)
學不學計算機,想必你都曾經(jīng)聽過“爬蟲”這個詞。說實話录语,我當初第一次聽到這兩個字倍啥,想到的是一群蟲子在我身上爬,起了一身雞皮疙瘩....
好澎埠!我們言歸正傳虽缕。在準備爬取數(shù)據(jù)前,我們得先對什么是爬蟲有簡單的了解:
網(wǎng)絡爬蟲(Web crawler)蒲稳,是一種按照一定的規(guī)則氮趋,自動地抓取萬維網(wǎng)信息的程序或者腳本,采集所有其能夠訪問到的頁面內(nèi)容(包括文本江耀、圖片剩胁、視頻、音頻等)
簡單的說决记,所謂爬蟲就是用程序去自動采(爬)集(却菁健)互聯(lián)網(wǎng)上的公開內(nèi)容。
而爬蟲之所以總是和python
掛鉤系宫,是因為python
這一腳本語言非常適合寫爬蟲代碼索昂。如果你問我有多簡單?
兩行代碼就完事了扩借!
import requests
r = requests.get(url="http://www.baidu.com")
requests
庫會自動向我們指定的url鏈接(百度)發(fā)起http請求椒惨,并將結(jié)果返回到r.content
中。
當然這只是最簡單的一種情況潮罪,爬取到的內(nèi)容也不過是百度首頁的源碼康谆;但實際開發(fā)爬蟲時的核心內(nèi)容,已經(jīng)在這兩行代碼里完美呈現(xiàn)了嫉到,可以說剩下的都是“點綴”沃暗。
在我們的這個項目中,使用了一個比requests庫稍復雜的框架Scrapy
何恶,它是python
最火熱的爬蟲框架孽锥,結(jié)構(gòu)化的設計可以讓開發(fā)人員非常方便的根據(jù)項目需求進行修改。
如果對 Scrapy
有興趣的同學细层,我可以為你提供一些參考資料:
01 Scrapy官方文檔
02 《Python爬蟲開發(fā)與項目實戰(zhàn)》
03 構(gòu)建單機千萬級別的微博爬蟲系統(tǒng)
當然惜辑,我覺得最快的學習方式是先簡單了解scrapy
的理論基礎(如5大組成部分),然后進行項目實戰(zhàn)(參考微博爬蟲項目疫赎,寫的挺完善)盛撑。
這里的美團點評爬蟲,爬取的是杭州捧搞、上海抵卫、北京等5大城市各1000家餐館的前200條點評(合計約100w+評論數(shù)據(jù))狮荔,通過構(gòu)造訪問api
接口,提取json
格式的數(shù)據(jù)陌僵。代碼類似于長這樣:
由于本文的重點不是爬蟲講解轴合,所以代碼部分直接一帶而過创坞。
在評論內(nèi)容的篩選上碗短,我只保留了4-5星和1-2星的評論,作為后期情感識別的訓練/測試數(shù)據(jù)题涨。
最終爬取結(jié)果:
mongodb
中偎谁,省去了建表的麻煩。
如果嫌慢纲堵,我們還可以采取分布式的架構(gòu)(如scrapy-redis
)巡雨,加快爬蟲的爬取速度。
耐心等待爬蟲運行結(jié)束席函,去數(shù)據(jù)庫中查看爬蟲忠誠的為我們爬取的數(shù)據(jù):
有了數(shù)據(jù)铐望,接下來要做的就是數(shù)據(jù)預處理啦!
03 使用pandas茂附、numpy做簡單的數(shù)據(jù)處理
很多人把pandas
正蛙、numpy
、matplotlib
3個庫稱為python數(shù)據(jù)處理和可視化的三劍客营曼,因為它們真的功能強大又好用乒验。這里我先介紹前兩個,matplotlib
留到第5小節(jié)蒂阱。
我們爬取的數(shù)據(jù)保留在mongodb
中锻全,我們可以用mogoexport
或借助數(shù)據(jù)庫可視化軟件將其導出到csv
文件中。
這里為了簡化录煤,我們分別導出評分5星和評分1星的評論(剛好對應正負兩面情感)各6800條鳄厌;在后續(xù)處理中,每種情感取6000條用作訓練(包含驗證集)妈踊,剩余800條作為測試了嚎。
我們分別導出的數(shù)據(jù)命名為10_star.csv
、50_star.csv
响委,借助pandas
庫用一行代碼導入新思,并查看前5行內(nèi)容。
import pandas as pd
df1 = pd.read_csv('./10_star.csv')
df2 = pd.read_csv('./10_star.csv')
print(df1.head())
print(df1.head())
接下來赘风,我們要遍歷comment
列的每一行夹囚,過濾其中的非中文字符;再將字數(shù)大于10的評論加入一個列表邀窃。
這是對其中的負面評論的數(shù)據(jù)處理荸哟,正面評論處理類似假哎。最后將數(shù)據(jù)直接整合在一起:
X_data = X_data1[:6000] + X_data2[:6000] # 訓練數(shù)據(jù)
X_test_data = X_data1[6000:6800] + X_data2[6000:6800] # 測試數(shù)據(jù)
請注意,這里我們保證了X_data
前6000條數(shù)據(jù)是負面的(來自X_data1)鞍历,后6000條是正面的(來自X_data2)舵抹。X_test_data
也同理。
得到訓練數(shù)據(jù)后劣砍,我們手工創(chuàng)建一個labels
數(shù)組(訓練標簽)惧蛹,前6000個元素是0,后6000個元素是1刑枝;再通過numpy
庫轉(zhuǎn)換為numpy數(shù)組
香嗓,便于后期輸入到神經(jīng)網(wǎng)絡中。
import numpy as np
y_data = [0 for i in range(6000)] + [1 for i in range(6000)]
y_data = np.asarray(y_data, dtype=np.float32)
y_test_data = [0 for i in range(800)] + [1 for i in range(800)]
y_test_data = np.asarray(y_data, dtype=np.float32)
現(xiàn)在装畅,聰明的你可能發(fā)現(xiàn)一個問題:我們的數(shù)據(jù)太有規(guī)律啦靠娱,正負情感剛好前后各占了一半;假如我們輸入了前3000條到模型中掠兄,機器“機智的”全判斷為負面像云,能證明準確率就有100%了?
為了避免數(shù)據(jù)分布不規(guī)律的現(xiàn)象蚂夕,我們需要為數(shù)據(jù)進行“洗牌”(隨機打亂)迅诬。
還是借助numpy
,我們可以輕松實現(xiàn)這一過程双抽。
X_train = []
y_train = []
X_test = []
y_test = []
nums = np.arange(12000)
# 隨機打亂12000個訓練數(shù)據(jù)
np.random.shuffle(nums)
for i in nums:
X_train.append(X_data[i])
y_train.append(y_data[i])
# 隨機打亂1600個測試數(shù)據(jù)
nums_ = np.arange(1600)
np.random.shuffle(nums_) # shuffle改變的是自身的內(nèi)容
for i in nums_:
X_test.append(X_test_data [i])
y_test.append(y_test_data [i])
# list轉(zhuǎn)Numpy數(shù)組
X_train= np.asarray(X_train, dtype=np.float32)
X_test= np.array(X_test, dtype=np.float32)
到此為止百框,簡單的數(shù)據(jù)預處理就結(jié)束了,是不是可以開始搭建我們的神經(jīng)網(wǎng)絡模型了牍汹?
別急铐维!這兒我們的數(shù)據(jù)還全都是中文,即便是英文字母慎菲,計算機也一概不認識嫁蛇。所以,一位重量級的選手馬上就要登場和我們見面了露该。????
04 調(diào)用bert-as-service睬棚,快速得到中文詞向量
在自然語言處理任務中,首先需要考慮詞如何在計算機中表示解幼。常見的表示方法有兩種
01 one-hot representation (獨熱編碼)
02 distribution representation
第一種是離散的表示方法抑党,得到的是高維度的稀疏矩陣;第二種方法(Word Embedding)則是將詞表示成定長的連續(xù)稠密向量撵摆。想深入的同學底靠,請利用好您的搜索引擎(上網(wǎng)搜!)
從頭訓練一個有效的語言模型是耗時又耗能的過程特铝。學習NLP的同學暑中,一定知道去年底Google發(fā)布的Bert
模型壹瘟。
本例中,我們借助騰訊AI實驗室發(fā)布的bert-as-service
接口鳄逾,讓你能簡單的通過兩行代碼稻轨,即可使用預訓練好的bert模型生成句向量和ELMO風格的詞向量。
關(guān)于bert-as-service
的官方介紹雕凹,可以點擊查看作者:肖涵博士的Git倉庫殴俱。
我們來看一看這兩行代碼是怎么實現(xiàn)的?
from bert_serving.client import BertClient
bc = BertClient
# 將待訓練的中文數(shù)據(jù)轉(zhuǎn)換為(请琳,768)維的句向量
input_train = bc.encode(X_train)
覺得上面的內(nèi)容不能馬上看懂粱挡?
沒關(guān)系,送上免費學習傳送門:兩行代碼玩轉(zhuǎn)Google BERT句向量詞向量俄精。寫的很詳細哦!
bert-as-service
將一個句子統(tǒng)一轉(zhuǎn)換成768維
的句向量榕堰;最終我們得到的就是12000 * 768
維度的句向量矩陣竖慧,也就是我們將輸入到神經(jīng)網(wǎng)絡模型的真正數(shù)據(jù)。
05 使用Keras逆屡,實現(xiàn)簡單的情感分析模型
雖然我們這里跑的只是一個很小的demo圾旨,但是數(shù)據(jù)處理部分依然是整個工程中最耗時間的部分;實際開發(fā)中也往往如此魏蔗。
有了處理后的數(shù)據(jù)砍的,后邊的路一下暢通了許多,尤其是有keras
這樣容易上手的工具莺治。
Keras
是一個高層神經(jīng)網(wǎng)絡API廓鞠,由純python
編寫并使用Tensorflow
,Theano
,CNTK
作為后端,以簡介谣旁、快速為設計原則床佳。
直接使用pip
即可快速安裝Keras
和Tensorflow
$ pip install keras
$ pip install tensorflow
典型的Keras
工作流程大致可以分為四步:
(1) 定義訓練數(shù)據(jù):輸入張量和目標張量。
(2) 定義層組成的網(wǎng)絡(或模型)榄审,將輸入映射到目標砌们。
(3) 配置學習過程:選擇損失函數(shù)、優(yōu)化器和需要監(jiān)控的指標搁进。
(4) 調(diào)用模型的 fit 方法在訓練數(shù)據(jù)上進行迭代
我們直接使用使用Sequential
類來定義模型(僅用于層的線性堆疊浪感,是最常見的網(wǎng)絡架構(gòu))。
from keras.models import Sequential
from keras.layers import Dense, Dropout
import tensorflow as tf
model = Sequential()
# 搭建模型
model.add(Dense(32, activation='relu', input_shape=(768,)))
model.add(Dropout(0.3))
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
對于簡單的二分類問題饼问,模型使用Dense
全連接層拼接已經(jīng)夠用影兽,最后的輸出就是一個數(shù),代表了正面/負面情感的概率匆瓜。同時防止過擬合赢笨,在模型中加入了Dropout
層未蝌,
接下來,我們來指定模型使用的優(yōu)化器和損失函數(shù)茧妒,以及訓練過程中想要監(jiān)控的指標萧吠。
model.compile(
loss='binary_crossentropy',
optimizer=tf.train.AdamOptimizer(),
metrics=['acc']
)
最后,通過fit
方法將輸入數(shù)據(jù)的Numpy數(shù)組
傳入模型桐筏;請注意纸型,我們留出了20%的數(shù)據(jù)作為驗證集:
history = model.fit(
X_train, y_train,
epochs=30,
batch_size=128,
validation_split=0.2,
verbose=1
)
我們的模型就開始愉快的迭代訓練啦!
可以觀察到梅忌,隨著迭代次數(shù)增加狰腌,模型的損失
loss
逐漸下降,準確度acc
逐漸上升牧氮,直到最終趨于穩(wěn)定琼腔,與我們的預期完全一致。
運行結(jié)束后踱葛,我們使用matplotlib
庫將結(jié)果可視化吧~
import matplotlib.pyplot as plt
history_dict = history.history
epochs = range(1, len(history_dict['acc']) + 1)
# 繪圖部分
plt.figure()
plt.plot(epochs, history_dict['acc'], 'b', label='acc')
plt.plot(epochs, history_dict['val_acc'], 'bo', label='val_acc')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
分別畫出訓練過程中損失和精確度的變化丹莲,可以知道我們的模型確實從輸入數(shù)據(jù)中有效“學習”到了情感識別的模式。
因為訓練數(shù)據(jù)不算太少尸诽,又加入了
dropout
預防過擬合甥材,同時任務本身不算復雜,保證了我們的模型對于美團點評數(shù)據(jù)是好評還是差評有了96%
的準確率性含!通過調(diào)參和加大模型的復雜度洲赵,這一結(jié)果應該會更高。
別忘了我們還有1600條
數(shù)據(jù)被當作測試集還沒使用商蕴,也就是說模型還沒有“見過”這批數(shù)據(jù)叠萍。是時候派他們上場了!
調(diào)用evaluate
方法實驗我們的測試數(shù)據(jù):
test_loss = model.evaluate(
X_test,
y_test,
batch_size=63,
verbose=1
)
print(test_loss)
得到結(jié)果:
[0.07956909381508012, 0.9731250016018749]
它表示訓練損失和準確率分別為0.07
和97%
究恤。
小結(jié)
本文帶你了解了如何安裝使用python
俭令,如何使用python
爬取數(shù)據(jù)(構(gòu)造爬蟲),如何處理數(shù)據(jù)以及使用Keras
訓練模型部宿,讓最后的結(jié)果可視化抄腔。
可能涉及的內(nèi)容比較多,又限于篇幅理张,對各個模塊的內(nèi)容只是管中窺豹赫蛇,簡要帶過。
其實雾叭,這里很多模塊的內(nèi)容遠不是一篇文章悟耘,甚至一本書就能全面詳細介紹的(如對于爬蟲的反爬措施部分,就可以寫一本書)织狐。如果大家愿意看暂幼,筆者會持續(xù)更新本專題下的文章筏勒。對于本文談論的內(nèi)容,你有沒有什么不同的意見或者更好的建議旺嬉?歡迎留言管行!
喜歡請不要吝嗇于點贊哈。