引言
從deeplearning.ai的課程開始,嘗試撿回荒廢了3年的NLP。
Coursera課程鏈接
搭建jupyter + vscode學(xué)習(xí)環(huán)境
Start with Why
為什么要用vscode涩堤?
我很想用諸如:“誰用誰知道,不用就吃虧”這樣的話來偷懶,但為了能讓心存疑慮的小伙伴放心去用,好歹要用自己的話說一下這工具為什么好用耸黑。
vscode是寫程序必備的“萬用軍刀”,如果硬要說有什么它辦不到篮幢,那可能只是還沒找到合適的插件罷了大刊。
因此,我不打算寫vscode功能的詳細清單三椿。用過的同學(xué)們都知道缺菌,一旦用上,不光敲代碼搜锰,可能日常碼字你都離不開它伴郁。
現(xiàn)在我在vscode上面完成的工作有:前后端開發(fā),代碼調(diào)試纽乱,記筆記蛾绎,遠程登錄服務(wù)器操作,命令行鸦列,上線代碼/博客,等等鹏倘。相信未來它能承載更多工作入口薯嗤。就正如我現(xiàn)在想要把Jupyter整合進去一樣。
Jupyter Notebook幾年前剛開始學(xué)機器學(xué)習(xí)就用過纤泵,但漸漸少用(少用的原因是Mac算力限制骆姐,跑機器學(xué)習(xí)太費勁)之后連怎么搭環(huán)境都給忘了。
這段時間想把自己的NLP技能撿回來捏题,于是就有了這想法玻褪。簡單一搜,果然有方案公荧,馬上動手不啰嗦带射。
步驟一:搭建本地Jupyter服務(wù)器
jupyter notebook 是非常好的用于學(xué)習(xí)人工智能編程的工具。
首先Jupyter配合anaconda讓你可以在不同的packages環(huán)境下進行相對應(yīng)的開發(fā)循狰,特別是在跑機器學(xué)習(xí)時往往需要加載大量的庫來配合工作窟社,省去折騰各種不同版本的包和運行環(huán)境的麻煩。
其次使用Jupyter還可以一邊做筆記绪钥,一邊看程序運行結(jié)果灿里,免去界面切換的繁瑣。當(dāng)你做完一次學(xué)習(xí)之后程腹,筆記可以立馬拿去發(fā)布分享匣吊,強化自身學(xué)習(xí)動力。
因此,強烈建議大家都在自家電腦上搭建一個Jupyter Notebook的運行環(huán)境色鸳,網(wǎng)上教程很多這里就不再累贅社痛。
首先你要自行安裝好Python3環(huán)境
下載并安裝Anaconda(這又是個什么玩意兒?)
我記得以前安裝anaconda都是跑命令行搞出來的缕碎,現(xiàn)在居然下載完了直接就可以裝了褥影。好吧,那就隨帶說一下為什么要用Anaconda咏雌,然后使用過程又要注意什么凡怎。
Anaconda解決了維護運行環(huán)境不一致的問題,你可以為每一個應(yīng)用配置單獨的赊抖,隔離的環(huán)境统倒。(一句話說完)
如果這句話你還是理解不了的話,建議隨便在github上找?guī)讉€Python項目拉下來玩氛雪,不用Anaconda房匆,然后就知道為啥要用這東西了。
安裝完了之后啟動Jupyter notebook报亩,運行
jupyter notebook
命令運行成功后系統(tǒng)會為你自動打開 localhost:8888浴鸿,因為我們是要在vscode里面去用的,所以直接關(guān)掉就行弦追。
步驟二:配置vscode
在插件市場安裝Jupyter插件岳链,成功后啟動命令窗口(Shift+Command+P)
執(zhí)行 Jupyter:Create New Blank Jupyter Notebook
然后就可以開始使用了,在新建的文檔中能看到的信息和你在網(wǎng)頁上使用無異劲件,可以看到已連接的local掸哑,Python3是否正在執(zhí)行等等。
參考資料
- Working with Jupyter Notebooks in Visual Studio Code
- Install and Use — Jupyter Documentation 4.1.1 alpha documentation
NLP基礎(chǔ)01 - 數(shù)據(jù)預(yù)處理
- 對數(shù)據(jù)進行預(yù)處理
- 使用NLTK處理數(shù)據(jù)集
引入包
NLTK(http://www.nltk.org/)是一個自然語言工具箱零远,提供超過50種語料庫和詞法資源(如WordNet)提供了易于使用的接口苗分,還提供了一套用于分類、標(biāo)記牵辣、詞干提取摔癣、標(biāo)記、解析和語義推理的文本處理庫服猪、工業(yè)強度NLP庫的包裝器供填。
適合于語言學(xué)家、工程師罢猪、學(xué)生近她、教育工作者、研究人員和行業(yè)用戶膳帕。NLTK可用于Windows粘捎、Mac OS X和Linux薇缅。最重要的是,NLTK是一個免費的攒磨、開源的泳桦、社區(qū)驅(qū)動的項目。
Python的自然語言處理為語言處理編程提供了一個實用的入門娩缰。它由NLTK的創(chuàng)建者編寫灸撰,指導(dǎo)讀者了解編寫Python程序的基礎(chǔ)知識、使用語料庫拼坎、對文本進行分類浮毯、分析語言結(jié)構(gòu)等等。該書的在線版本已經(jīng)針對Python 3和NLTK 3進行了更新泰鸡。(Python 2的原始版本仍然可以在http://nltk.org/book_1ed上找到债蓝。)
對tweets數(shù)據(jù)進行情感性分析,即判斷每一條tweet是正向盛龄,負向饰迹,還是中性描述。
在NLTK包中有預(yù)加載的一個Twitter實驗數(shù)據(jù)集余舶,可直接使用啊鸭。
import nltk
from nltk.corpus import twitter_samples
import matplotlib.pyplot as plt
import random
關(guān)于Twitter數(shù)據(jù)集
NLTK這個數(shù)據(jù)集已經(jīng)把tweets劃分成了正向或負向,各5000條匿值。雖然數(shù)據(jù)集來源于真實數(shù)據(jù)莉掂,但這樣的劃分是人為的。
由于本地使用 nltk.download('twitter_samples') 語句會報錯:Errno 61 Connection refused
因此需要在命令行中進行如下操作(同一窗口操作命令行是vscode優(yōu)勢之一)
- 在nltk/nltk_data: NLTK Data 下載zip
- 解壓后把文件夾改名為nltk_data
- 若運行下一步時報錯千扔,可查看提示搬運文件夾到程序會檢索的目錄下
from nltk.book import *
*** Introductory Examples for the NLTK Book ***
Loading text1, ..., text9 and sent1, ..., sent9
Type the name of the text or sentence to view it.
Type: 'texts()' or 'sents()' to list the materials.
text1: Moby Dick by Herman Melville 1851
text2: Sense and Sensibility by Jane Austen 1811
text3: The Book of Genesis
text4: Inaugural Address Corpus
text5: Chat Corpus
text6: Monty Python and the Holy Grail
text7: Wall Street Journal
text8: Personals Corpus
text9: The Man Who Was Thursday by G . K . Chesterton 1908
用 strings() 函數(shù)加載數(shù)據(jù)
all_positive_tweets = twitter_samples.strings('positive_tweets.json')
all_negative_tweets = twitter_samples.strings('negative_tweets.json')
現(xiàn)在,我們可以先來看看數(shù)據(jù)長什么樣子库正。這在正式跑數(shù)之前是非常重要的操作
print('Number of postive tweets: ', len(all_positive_tweets))
print('Number of negative tweets: ', len(all_negative_tweets))
print('\nThe type of all_positive_tweets is: ', type(all_positive_tweets))
print('\nThe type of all_negative_tweets is: ', type(all_negative_tweets))
print('\nThe type of a tweet entry is: ', type(all_negative_tweets[0]))
Number of postive tweets: 5000
Number of negative tweets: 5000
The type of all_positive_tweets is: <class 'list'>
The type of all_negative_tweets is: <class 'list'>
The type of a tweet entry is: <class 'str'>
從上面結(jié)果可以看出來曲楚,兩個json文件已被轉(zhuǎn)換成了列表,而一條tweet則是一個字符串褥符。
你還可以使用 pyplot 庫去畫一個餅圖龙誊,用來描述上述的數(shù)據(jù)(增加一點數(shù)據(jù)可視化總是有好處滴)
pyplot庫使用可參考 Basic pie chart — Matplotlib 3.3.3 documentation
# 自定義圖形大小
fig = plt.figure(figsize=(5, 5))
# 定義標(biāo)簽
labels = 'Positives', 'Negative'
# 每頁大小
sizes = [len(all_positive_tweets), len(all_negative_tweets)]
# 聲明餅圖,頁大小喷楣,保留小數(shù)位趟大,陰影,角度-90為垂直切分
plt.pie(sizes, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90)
plt.axis('equal')
plt.show()
查看原始文本數(shù)據(jù)
查看真實的數(shù)據(jù)情況铣焊,下面的代碼會print出正向逊朽,負向的評論,以不同顏色為區(qū)分
# 正向評論 綠色
print('\033[92m' + all_positive_tweets[random.randint(0,5000)])
# 負向評論 紅色
print('\033[91m' + all_negative_tweets[random.randint(0,5000)])
?[92m@JayHorwell Hi Jay, if you haven't received it yet please email our events team at events@breastcancernow.org and they'll sort it :)
?[91m@pickledog47 @FoxyLustyGrover Its Kate, tho!! :( #sniff
由此發(fā)現(xiàn)數(shù)據(jù)中含有不少表情符號及url信息曲伊,在后續(xù)的處理中需要考慮在內(nèi)
對原始文本進行預(yù)處理
數(shù)據(jù)預(yù)處理是所有機器學(xué)習(xí)的關(guān)鍵步驟叽讳。包括數(shù)據(jù)清洗和格式化。對NLP而言,主要有以下任務(wù):
- 分詞
- 處理大小寫
- 刪除停止詞(Stop Words)和標(biāo)點符號
- 提取詞根(處理英語時特有的Stemming)
# 選擇一條較為復(fù)雜的數(shù)據(jù)
tweet = all_positive_tweets[2277]
print(tweet)
My beautiful sunflowers on a sunny Friday morning off :) #sunflowers #favourites #happy #Friday off… https://t.co/3tfYom0N1i
import re # 正則表達式庫
import string # 字符串操作庫
from nltk.corpus import stopwords # NLTK的stopwords庫岛蚤,貌似不支持中文
from nltk.stem import PorterStemmer # stemming 庫
from nltk.tokenize import TweetTokenizer # 推特分詞器
去除超鏈接邑狸,推特標(biāo)簽和格式
刪除推特平臺常用字符串,就像微博一樣涤妒,有許多'@' '#' 和url
使用re庫執(zhí)行正則表達式操作单雾。使用sub()替換成空串
關(guān)于python正則表達式出來參考:Python 正則表達式 | 菜鳥教程
可以直接使用vscode的查找工具進行正則表達式的調(diào)試
print('\033[92m' + tweet)
print('\033[94m')
tweet2 = re.sub(r'^RT[\s]+', '', tweet) #處理 RT【空格】打頭的數(shù)據(jù),即“轉(zhuǎn)發(fā)”類的tweet
tweet2 = re.sub(r'https?:\/\/.*[\r\n]*', '', tweet2) #去除超鏈接
tweet2 = re.sub(r'#', '', tweet2)
print(tweet2)
?[92mMy beautiful sunflowers on a sunny Friday morning off :) #sunflowers #favourites #happy #Friday off… https://t.co/3tfYom0N1i
?[94m
My beautiful sunflowers on a sunny Friday morning off :) sunflowers favourites happy Friday off…
先試試直接分詞她紫,看看結(jié)果如何
print()
print('\033[92m' + tweet2)
print('\033[94m')
tokenizer = TweetTokenizer(preserve_case=False, strip_handles=True, reduce_len=True)
tweet_tokens = tokenizer.tokenize(tweet2)
print()
print('Tokenized string:')
print(tweet_tokens)
?[92mMy beautiful sunflowers on a sunny Friday morning off :) sunflowers favourites happy Friday off…
?[94m
Tokenized string:
['my', 'beautiful', 'sunflowers', 'on', 'a', 'sunny', 'friday', 'morning', 'off', ':)', 'sunflowers', 'favourites', 'happy', 'friday', 'off', '…']
去掉stop words和標(biāo)點符號
stop words是常用的沒有實際意義的那些詞語硅堆,之前試過生成詞云都會發(fā)現(xiàn)諸如“的”,“那么”這些詞會很多犁苏,所以在處理前最好先去掉硬萍。
在英文情況下會有所不同,具體看下一步執(zhí)行結(jié)果围详。
stopwords_english = stopwords.words('english')
print('Stop words\n')
print(stopwords_english)
print('\nPunctuation\n')
print(string.punctuation)
Stop words
['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're", "you've", "you'll", "you'd", 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 'himself', 'she', "she's", 'her', 'hers', 'herself', 'it', "it's", 'its', 'itself', 'they', 'them', 'their', 'theirs', 'themselves', 'what', 'which', 'who', 'whom', 'this', 'that', "that'll", 'these', 'those', 'am', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing', 'a', 'an', 'the', 'and', 'but', 'if', 'or', 'because', 'as', 'until', 'while', 'of', 'at', 'by', 'for', 'with', 'about', 'against', 'between', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from', 'up', 'down', 'in', 'out', 'on', 'off', 'over', 'under', 'again', 'further', 'then', 'once', 'here', 'there', 'when', 'where', 'why', 'how', 'all', 'any', 'both', 'each', 'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', 's', 't', 'can', 'will', 'just', 'don', "don't", 'should', "should've", 'now', 'd', 'll', 'm', 'o', 're', 've', 'y', 'ain', 'aren', "aren't", 'couldn', "couldn't", 'didn', "didn't", 'doesn', "doesn't", 'hadn', "hadn't", 'hasn', "hasn't", 'haven', "haven't", 'isn', "isn't", 'ma', 'mightn', "mightn't", 'mustn', "mustn't", 'needn', "needn't", 'shan', "shan't", 'shouldn', "shouldn't", 'wasn', "wasn't", 'weren', "weren't", 'won', "won't", 'wouldn', "wouldn't"]
Punctuation
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
我們可以看到上面的停止詞包含了一些可能很重要的詞朴乖。例如“I”,"not", "between", "won", "against" 助赞。
不同分析目的买羞,可能要對停止詞表進一步加工,在我們前面下載nltk_data里面有一個stopwords的文件夾雹食,對應(yīng)的English那個文件就是停止詞的詞表畜普。
在這個練習(xí)里,則用整個列表群叶。
下面開始進行分詞操作
print()
print('033[92m')
print(tweet_tokens)
print('033[94m')
tweets_clean = []
for word in tweet_tokens:
if (word not in stopwords_english and
word not in string.punctuation):
tweets_clean.append(word)
print('removed stop words and punctuation:')
print(tweets_clean)
033[92m
['my', 'beautiful', 'sunflowers', 'on', 'a', 'sunny', 'friday', 'morning', 'off', ':)', 'sunflowers', 'favourites', 'happy', 'friday', 'off', '…']
033[94m
removed stop words and punctuation:
['beautiful', 'sunflowers', 'sunny', 'friday', 'morning', ':)', 'sunflowers', 'favourites', 'happy', 'friday', '…']
詞干提取(Stemming)
這是處理英語時需要特別考慮的一個因素吃挑,比如
- learn
- learning
- learned
- learnt
這些詞的詞根都是learn,但處理時提取出來的可能不是learn街立。例如舶衬,happy
- happy
- happiness
- happier
我們需要提取出happi,而不是happ赎离,因為它是happen的詞根逛犹。
NLTK有不同的模塊用于詞干提取,我們將使用使用PorterStemmer完成此操作
print()
print('\033[92m')
print(tweets_clean)
print('\033[94m')
stemmer = PorterStemmer()
tweets_stem = []
for word in tweets_clean:
stem_word = stemmer.stem(word)
tweets_stem.append(stem_word)
print('stemmed words:')
print(tweets_stem)
?[92m
['beautiful', 'sunflowers', 'sunny', 'friday', 'morning', ':)', 'sunflowers', 'favourites', 'happy', 'friday', '…']
?[94m
stemmed words:
['beauti', 'sunflow', 'sunni', 'friday', 'morn', ':)', 'sunflow', 'favourit', 'happi', 'friday', '…']
process_tweet()
可使用諸如utils.py這樣的文件梁剔,對上述過程進行封裝虽画,例如process_tweet函數(shù)的以下應(yīng)用
utils.py的代碼放在最后
from utils import process_tweet
tweet = all_positive_tweets[2277]
print()
print('\033[92m')
print(tweet)
print('\033[94m')
tweets_stem = process_tweet(tweet);
print('preprocessed tweet:')
print(tweets_stem)
?[92m
My beautiful sunflowers on a sunny Friday morning off :) #sunflowers #favourites #happy #Friday off… https://t.co/3tfYom0N1i
?[94m
preprocessed tweet:
['beauti', 'sunflow', 'sunni', 'friday', 'morn', ':)', 'sunflow', 'favourit', 'happi', 'friday', '…']
總結(jié)
通過這個練習(xí),我們知道了一般NLP的預(yù)處理過程荣病,當(dāng)然實際過程(涉及中文時)會更復(fù)雜码撰,要結(jié)合數(shù)據(jù)具體情況不斷調(diào)整。
把以下內(nèi)容保存為文件utils.py众雷,放在ipynb文件同一個目錄下灸拍,最后一個步驟才能運行成功
import re
import string
import numpy as np
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
from nltk.tokenize import TweetTokenizer
def process_tweet(tweet):
"""Process tweet function.
Input:
tweet: a string containing a tweet
Output:
tweets_clean: a list of words containing the processed tweet
?
"""
stemmer = PorterStemmer()
stopwords_english = stopwords.words('english')
# remove stock market tickers like $GE
tweet = re.sub(r'\$\w*', '', tweet)
# remove old style retweet text "RT"
tweet = re.sub(r'^RT[\s]+', '', tweet)
# remove hyperlinks
tweet = re.sub(r'https?:\/\/.*[\r\n]*', '', tweet)
# remove hashtags
# only removing the hash # sign from the word
tweet = re.sub(r'#', '', tweet)
# tokenize tweets
tokenizer = TweetTokenizer(preserve_case=False, strip_handles=True,
reduce_len=True)
tweet_tokens = tokenizer.tokenize(tweet)
tweets_clean = []
for word in tweet_tokens:
if (word not in stopwords_english and # remove stopwords
word not in string.punctuation): # remove punctuation
# tweets_clean.append(word)
stem_word = stemmer.stem(word) # stemming word
tweets_clean.append(stem_word)
return tweets_clean
def build_freqs(tweets, ys):
"""Build frequencies.
Input:
tweets: a list of tweets
ys: an m x 1 array with the sentiment label of each tweet
(either 0 or 1)
Output:
freqs: a dictionary mapping each (word, sentiment) pair to its
frequency
"""
# Convert np array to list since zip needs an iterable.
# The squeeze is necessary or the list ends up with one element.
# Also note that this is just a NOP if ys is already a list.
yslist = np.squeeze(ys).tolist()
# Start with an empty dictionary and populate it by looping over all tweets
# and over all processed words in each tweet.
freqs = {}
for y, tweet in zip(yslist, tweets):
for word in process_tweet(tweet):
pair = (word, y)
if pair in freqs:
freqs[pair] += 1
else:
freqs[pair] = 1
return freqs
ChangeLog
- 2021/1/28 17:12:10 折騰了兩小時做祝,先到這里。其實你會發(fā)現(xiàn)搞程序遇到的麻煩鸡岗,跟你在玩一個游戲(比較虐的那種)時被卡住的感覺很像混槐,這時應(yīng)該先設(shè)法讓自己先停下來去搞點別的……
- 2021/2/1 16:28:38 花了兩小時把后面內(nèi)容完成