本文由 伯樂在線 - 東狗 翻譯,toolate 校稿。未經許可,禁止轉載!
英文出處:blog.dominodatalab.com。歡迎加入翻譯小組。css
本文介紹一個將911襲擊及後續影響相關新聞文章的主題可視化的項目。我將介紹個人出發點,實現的技術細節和我對一些結果的思考。html
近代美國曆史上再沒有比911襲擊影響更深遠的事件了,它的影響在將來還會持續。從事件發生到如今,成千上萬主題各異的文章付梓。咱們怎樣能利用數據科學的工具來探索這些主題,而且追蹤它們隨着時間的變化呢?前端
首先提出這個問題的是一家叫作Local Projects的公司,有人委任它們爲紐約的國家911博物館設置一個展覽。他們的展覽,Timescape,將事件的主題和文章可視化以後投影到博物館的一面牆上。不幸的是,因爲考慮到官僚主義的干預和現代人的三分鐘熱度,這個展覽只能展示不少主題,快速循環播放。Timescape的設計給了我啓發,可是我想試着更深刻、更有交互性,讓每一個能接入互聯網的人都能在空閒時觀看。python
這個問題的關鍵是怎麼講故事。每篇文章都有不一樣的講故事角度,可是有線索經過詞句將它們聯繫到一塊兒。」Osama bin Laden」、 「Guantanamo Bay」、」Freedom」,還有更多詞彙組成了我模型的磚瓦。算法
全部來源當中,沒有一個比紐約時報更適合講述911的故事了。他們還有一個神奇的API,容許在數據庫中查詢關於某一主題的所有文章。我用這個API和其餘一些Python網絡爬蟲以及NLP工具構建了個人數據集。數據庫
爬取過程是以下這樣的:網絡
我寫了一個Python腳本自動作這些事,並可以構建一個有成千上萬文章的數據集。也許這個過程當中最有挑戰性的部分是寫一個從HTML文檔裏提取正文的函數。近幾十年來,紐約時報不時也更改了他們HTML文檔的結構,因此這個抽取函數取決於笨重的嵌套條件語句:dom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# s is a BeautifulSoup object containing the HTML of the page
if
s.find(
'p'
, {
'itemprop'
:
'articleBody'
})
is
not
None
:
paragraphs
=
s.findAll(
'p'
, {
'itemprop'
:
'articleBody'
})
story
=
' '
.join([p.text
for
p
in
paragraphs])
elif
s.find(
'nyt_text'
):
story
=
s.find(
'nyt_text'
).text
elif
s.find(
'div'
, {
'id'
:
'mod-a-body-first-para'
}):
story
=
s.find(
'div'
, {
'id'
:
'mod-a-body-first-para'
}).text
story
+
=
s.find(
'div'
, {
'id'
:
'mod-a-body-after-first-para'
}).text
else
:
if
s.find(
'p'
, {
'class'
:
'story-body-text'
})
is
not
None
:
paragraphs
=
s.findAll(
'p'
, {
'class'
:
'story-body-text'
})
story
=
' '
.join([p.text
for
p
in
paragraphs])
else
:
story
=
''
|
在咱們應用機器學習算法以前,咱們要將文檔向量化。感謝scikit-learn的IT-IDF Vectorizer模塊,這很容易。只考慮單個詞是不夠的,由於個人數據集裏並不缺一些重要的名字。因此我選擇使用n-grams,n取了1到3。讓人高興的是,實現多個n-gram和實現單獨關鍵詞同樣簡單,只須要簡單地設置一下Vectorizer的參數。機器學習
1
2
3
|
vec
=
TfidfVectorizer(max_features
=
max_features,
ngram_range
=
(
1
,
3
),
max_df
=
max_df)
|
開始的模型裏,我設置max_features(向量模型裏詞或詞組的最大數量)參數爲20000或30000,在我計算機的計算能力以內。可是考慮到我還加入了2-gram和3-gram,這些組合會致使特徵數量的爆炸(這裏面不少特徵也很重要),在個人最終模型裏我會提升這個數字。函數
非負矩陣分解(Non-negative Matrix Factorization,或者叫NMF),是一個線性代數優化算法。它最具魔力的地方在於不用任何闡釋含義的先驗知識,它就能提取出關於主題的有意義的信息。數學上它的目標是將一個nxm的輸入矩陣分解成兩個矩陣,稱爲W和H,W是nxt的文檔-主題矩陣,H是txm的主題-詞語矩陣。你能夠發現W和H的點積與輸入矩陣形狀同樣。實際上,模型試圖構建W和H,使得他們的點積是輸入矩陣的一個近似。這個算法的另外一個優勢在於,用戶能夠自主選擇變量t的值,表明生成主題的數量。
再一次地,我把這個重要的任務交給了scikit-learn,它的NMF模塊足夠處理這個任務。若是我在這個項目上投入更多時間,我也許會找一些更高效的NMF實現方法,畢竟它是這個項目裏最複雜耗時的過程。實現過程當中我產生了一個主意,但沒實現它,是一個熱啓動的問題。那樣可讓用戶用一些特定的詞來填充H矩陣的行,從而在造成主題的過程當中給系統一些領域知識。無論怎麼樣,我只有幾周時間完成整個項目。還有不少其餘的事須要我更多的精力。
由於主題模型是整個項目的基石,我在構建過程當中作的決定對最終成果有很大影響。我決定輸入模型的文章爲911事件發生18個月之後的。在這個時間段喧囂再也不,因此這段時間出現的主題的確是911事件的直接結果。在向量化的階段,開始幾回運行的規模受限於個人計算機。20或者30個主題的結果還不錯,可是我想要包含更多結果的更大模型。
我最終的模型使用了100000個向量詞彙和大約15000篇文章。我設置了200個主題,因此NMF算法須要處理15000×100000, 15000×200和200×100000規模的矩陣。逐漸變換後兩個矩陣來擬合第一個矩陣。
最終模型矩陣完成以後,我查看每一個主題並檢查關鍵詞(那些在主題-詞語矩陣裏有最高几率值的)。我給每一個主題一個特定的名字(在可視化當中能夠用),並決定是否保留這個主題。一些主題因爲和中心話題無關被刪除了(例如本地體育);還有一些太寬泛(關於股票市場或者政治的主題);還有一些太特定了,極可能是NMF算法的偏差(一系列來源於同一篇文章中的有關聯的3-grams)
這個過程以後我有了75個明確和相關的主題,每一個都根據內容進行命名了。
主題模型訓練好以後,算出給定文章的不一樣主題的權重就很容易了:
更難的部分在於決定怎麼把這些權重變成一個能講故事的可視化的形式。若是我只是簡單地將一段時期所有文章的話題權重加起來,這個分佈應該是一個關於那段時間中每一個主題出現頻率的準確表達。可是,這個分佈的組成部分對人類來講毫無心義。換種方式想,若是我對每一個主題作一個二分分類,我就能算出一段時間內和一個主題相關的文章百分數。我選擇了這個方法由於它更能說明問題。
話題二分分類也有難度,尤爲是這麼多文章和話題的狀況下。一些文章在不少主題下都有更高的權重,由於他們比較長而且包含的關鍵詞出如今不一樣主題裏。其餘一些文章在大多主題下權重都很低,即便人工判斷都能發現它的確和某些主題相關。這些差異決定了固定權重閾值不是一個好的分類方法;一些文章屬於不少主題而一些文章不屬於任何主題。我決定將每篇文章分類到權重最高的三個主題下。儘管這個方法不完美,它仍是能提供一個很好的平衡來解決咱們主題模型的一些問題。
儘管數據獲取,主題模型和分析階段對這個項目都很重要,它們都是爲最終可視化服務的。我努力平衡視覺吸引力和用戶交互,讓用戶能夠不需指導地探索和理解主題的趨勢。我開始的圖使用的是堆疊的區塊,後來我意識到簡單的線畫出來就足夠和清晰了。
我使用d3.js來作可視化,它對本項目數據驅動的模式來講正合適。數據自己被傳到了網頁上,經過一個包含主題趨勢數據的CSV文件和兩個包含主題和文章元數據的JSON文件。儘管我不是前端開發的專家,我仍是成功地經過一週的課程學習了足夠的d3,html和css知識,來構建一個使人滿意的可視化頁面。
儘管我提出這個項目的時候就對主題模型和數據處理中的各個組分有了解,這個項目的真正意義在於它(再次)講出的故事。911事件的本質是消極的,可是也有許多積極的故事:許多英雄救了不少人,社區融合,以及重建。
不幸的是,在我主題模型中展示出來這樣的媒體環境:關注負能量、反派和破壞。固然,單獨的一些英雄在一兩篇文章中被讚賞了,可是沒有一個足夠廣來造成一個主題。另外一方面,像奧薩瑪·本拉登和卡利亞·穆薩維這樣的反派在不少文章中被說起。即便是理查德·裏德,一個笨手笨腳的(試圖)穿炸彈鞋炸飛機的人,都比一些成功的英雄有更持久的媒體影響(一個補充:注重詞彙的主題模型的一個缺點就是,像Reid這樣普通的名字會致使談論不一樣人物的文章被彙集到一塊兒。在這個例子裏,哈利·裏德和理查德·裏德)。