本月的每月挑戰會主題是NLP,我們會在本文幫你開啟一種可能:使用pandas和python的自然語言工具包分析你Gmail郵箱中的內容。
NLP-風格的項目充滿無限可能:
- 情感分析是對諸如在線評論、社交媒體等情感內容的測度。舉例來說,關于某個話題的tweets趨向于正面還是負面的意見?一個新聞網站涵蓋的主題,是使用了更正面/負面的詞語,還是經常與某些情緒相關的詞語?這個“正面”的Yelp點評不是很諷刺么?(祝最后去的那位好運!)
- 分析語言在文學中的使用,進而衡量詞匯或者寫作風格隨時間/地區/作者的變化趨勢.
- 通過識別所使用的語言的關鍵特征,標記是否為垃圾內容。
- 基于評論所覆蓋的主題,使用主題抽取進行相似類別的劃分。
- 通過NLTK's的語料庫,應用Elastisearch和WordNet的組合來衡量Twitter流API上的詞語相似度,進而創建一個更好的實時Twitter搜索。
- 加入NaNoGenMo項目,用代碼生成自己的小說,你可以從這里大量的創意和資源入手。
將Gmail收件箱加載到pandas
讓我們從項目實例開始!首先我們需要一些數據。準備你的Gmail的數據存檔(包括你最近的垃圾郵件和垃圾文件夾)。
https://www.google.com/settings/takeout
現在去散步吧,對于5.1G大小的信箱,我2.8G的存檔需要發送一個多小時。
當你得到數據并為工程配置好本地環境之后好,使用下面的腳本將數據讀入到pandas(強烈建議使用IPython進行數據分析)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
from mailbox import mbox import pandas as pd def store_content(message, body = None ): if not body: body = message.get_payload(decode = True ) if len (message): contents = { "subject" : message[ 'subject' ] or "", "body" : body, "from" : message[ 'from' ], "to" : message[ 'to' ], "date" : message[ 'date' ], "labels" : message[ 'X-Gmail-Labels' ], "epilogue" : message.epilogue, } return df.append(contents, ignore_index = True ) # Create an empty DataFrame with the relevant columns df = pd.DataFrame( columns = ( "subject" , "body" , "from" , "to" , "date" , "labels" , "epilogue" )) # Import your downloaded mbox file box = mbox( 'All mail Including Spam and Trash.mbox' ) fails = [] for message in box: try : if message.get_content_type() = = 'text/plain' : df = store_content(message) elif message.is_multipart(): # Grab any plaintext from multipart messages for part in message.get_payload(): if part.get_content_type() = = 'text/plain' : df = store_content(message, part.get_payload(decode = True )) break except : fails.append(message) |
上面使用Python的mailbox模塊讀取并解析mbox格式的郵件。當然還可以使用更加優雅的方法來完成(比如,郵件中包含大量冗余、重復的數據,像回復中嵌入的“>>>”符號)。另外一個問題是無法處理一些特殊的字符,簡單起見,我們進行丟棄處理;確認你在這一步沒有忽略信箱中重要的部分。
需要注意的是,除了主題行,我們實際上并不打算利用其它內容。但是你可以對時間戳、郵件正文進行各種各樣有趣的分析,通過標簽進行分類等等。鑒于這只是幫助你入門的文章(碰巧會顯示來自我自己信箱中的結果),我不想去考慮太多細節。
查找常用詞語
現在我們已經得到了一些數據,那么來找出所有標題行中最常用的10個詞語:
1
2
3
4
5
6
7
8
|
# Top 10 most common subject words from collections import Counter subject_word_bag = df.subject. apply ( lambda t: t.lower() + " " ). sum () Counter(subject_word_bag.split()).most_common()[: 10 ] [( 're:' , 8508 ), ( '-' , 1188 ), ( 'the' , 819 ), ( 'fwd:' , 666 ), ( 'to' , 572 ), ( 'new' , 530 ), ( 'your' , 528 ), ( 'for' , 498 ), ( 'a' , 463 ), ( 'course' , 452 )] |
嗯,那些太常見了,下面嘗試對常用詞語做些限制:
1
2
3
4
5
6
|
from nltk.corpus import stopwords stops = [ unicode (word) for word in stopwords.words( 'english' )] + [ 're:' , 'fwd:' , '-' ] subject_words = [word for word in subject_word_bag.split() if word.lower() not in stops] Counter(subject_words).most_common()[: 10 ] [( 'new' , 530 ), ( 'course' , 452 ), ( 'trackmaven' , 334 ), ( 'question' , 334 ), ( 'post' , 286 ), ( 'content' , 245 ), ( 'payment' , 244 ), ( 'blog' , 241 ), ( 'forum' , 236 ), ( 'update' , 220 )] |
除了人工移除幾個最沒價值的詞語,我們也使用了NLTK的停用詞語料庫,使用前需要進行傻瓜式安裝。現在可以看到我收件箱中的一些典型詞語,但通常來講在英文文本中并不一定同樣是典型的。
二元詞組和搭配詞
NLTK可以進行另外一個有趣的測量是搭配原則。首先,我們來看下常用的“二元詞組”,即經常一起成對出現的兩個單詞的集合:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
from nltk import collocations bigram_measures = collocations.BigramAssocMeasures() bigram_finder = collocations.BigramCollocationFinder.from_words(subject_words) # Filter to top 20 results; otherwise this will take a LONG time to analyze bigram_finder.apply_freq_filter( 20 ) for bigram in bigram_finder.score_ngrams(bigram_measures.raw_freq)[: 10 ]: print bigram (( 'forum' , 'content' ), 0.005839453284373725 ) (( 'new' , 'forum' ), 0.005839453284373725 ) (( 'blog' , 'post' ), 0.00538045695634435 ) (( 'domain' , 'names' ), 0.004870461036311709 ) (( 'alpha' , 'release' ), 0.0028304773561811506 ) (( 'default' , 'widget.' ), 0.0026519787841697267 ) (( 'purechat:' , 'question' ), 0.0026519787841697267 ) (( 'using' , 'default' ), 0.0026519787841697267 ) (( 'release' , 'third' ), 0.002575479396164831 ) (( 'trackmaven' , 'application' ), 0.002524479804161567 ) |
我們可以對三元詞組(或n元詞組)重復相同的步驟來查找更長的短語。這個例子中,“new forum content”是出現次數最多的三元詞組,但是在上面例子的列表中,它卻被分割成兩部分并位居二元詞組列表的前列。
另外一個稍微不同類型的搭配詞的度量是基于點間互信息(pointwise mutual information)的。本質上,它所度量的是給定一個我們在指定文本中看到的單詞,相對于他們通常在全部文檔中單獨出現的頻率,另外一個單詞出現的可能性。舉例來說,通常,如果我的郵件主題使用單詞“blog”與/或“post”很多,那么二元組“blog post”并不是一個有趣的信號,因為一個單詞仍然可能不和另一個單詞同時出現。根據這條準則,我們得到一個不同的二元組的集合。
1
2
3
4
5
6
7
8
|
for bigram in bigram_finder.nbest(bigram_measures.pmi, 5 ): print bigram ( '4:30pm' , '5pm' ) ( 'motley' , 'fool' ) ( '60,' , '900,' ) ( 'population' , 'cap' ) ( 'simple' , 'goods' ) |
因此,我沒有收到很多提到單詞“motley”或者“fool”的郵件主題,但是當我看到其中任意一個,那么“Motley Fool”可能是相關聯的。
情感分析
最后,讓我們嘗試一些情感分析。為了快速入門,我們可以使用以NLTK為基礎的TextBlob庫,它提供了對于大量的常用NLP任務的簡單訪問。我們可以使用它內建的情感分析(基于模式)來計算主題的“極性(polarity)”。從,表示高度負面情緒的-1到表示正面情緒的1,其中0為中性(缺乏一個明確的信號)
接下來:分析一段時間內的你的收件箱;看看是否能夠通過郵件分類,確定正文的發送者/標簽/垃圾這些基本屬性。使用潛在語義索引去揭示所涵蓋的最常用的常規主題。將你的發件文件夾輸入到馬爾科夫模型(Markov model)中,結合詞性標注生成看起來連貫的自動回復
請讓我們知道你是否使用NLP嘗試了有趣的項目分支,包含一份開源庫將作為加分點。你可以在challenge.hackpad.com看下前面的展示,以找到更多的靈感!