如何利用Python分析14億條數據!資深程序員手把手教你!過億級!
挑戰
1-gram 的數據集在硬盤上可以展開成為 27 Gb 的數據,這在讀入 python 時是一個很大的數據量級。Python可以輕易地一次性地處理千兆的數據,但是當數據是損壞的和已加工的,速度就會變慢而且內存效率也會變低。
總的來說,這 14 億條數據(1,430,727,243)分散在 38 個源文件中,一共有 2 千 4 百萬個(24,359,460)單詞(和詞性標註,見下方),計算自 1505 年至 2008 年。
Loading the data
下面所有的代碼/例子都是運行在 8 GB 內存 的 2016 年的 Macbook Pro。 如果硬件或雲實例有更好的 ram 配置,表現會更好。
1-gram 的數據是以 tab 鍵分割的形式儲存在文件中,看起來如下:
每一條數據包含下面幾個字段:
為了按照要求生成圖表,我們只需要知道這些信息,也就是:
1. 這個單詞是我們感興趣的?2. 發布的年份3. 單詞使用的總次數
通過提取這些信息,處理不同長度的字符串數據的額外消耗被忽略掉了,但是我們仍然需要對比不同字符串的數值來區分哪些行數據是有我們感興趣的字段的。這就是 pytubes 可以做的工作:
差不多 170 秒(3 分鐘)之後, one_grams 是一個 numpy 數組,裏面包含差不多 14 億行數據,看起來像這樣(添加表頭部為了說明):
╒═══════════╤════════╤═════════╕│ Is_Word │ Year │ Count │╞═══════════╪════════╪═════════╡│ 0 │ 1799 │ 2 │├───────────┼────────┼─────────┤│ 0 │ 1804 │ 1 │├───────────┼────────┼─────────┤│ 0 │ 1805 │ 1 │├───────────┼────────┼─────────┤│ 0 │ 1811 │ 1 │├───────────┼────────┼─────────┤│ 0 │ 1820 │ ... │╘═══════════╧════════╧═════════╛
從這開始,就只是一個用 numpy 方法來計算一些東西的問題了:
每一年的單詞總使用量
谷歌展示了每一個單詞出現的百分比(某個單詞在這一年出現的次數/所有單詞在這一年出現的總數),這比僅僅計算原單詞更有用。為了計算這個百分比,我們需要知道單詞總量的數目是多少。
幸運的是,numpy讓這個變得十分簡單:
繪制出這個圖來展示谷歌每年收集了多少單詞:
很清楚的是在 1800 年之前,數據總量下降很迅速,因此這回曲解最終結果,並且會隱藏掉我們感興趣的模式。為了避免這個問題,我們只導入 1800 年以後的數據:
這返回了 13 億行數據(1800 年以前只有 3.7% 的的占比)
Python 在每年的占比百分數
獲得 python 在每年的占比百分數現在就特別的簡單了。
繪制出 word_counts 的結果:
形狀看起來和谷歌的版本差不多
性能
谷歌生成圖片在 1 秒鐘左右,相較於這個腳本的 8 分鐘,這也是合理的。谷歌的單詞計算的後臺會從明顯的準備好的數據集視圖中產生作用。
舉個例子,提前計算好前一年的單詞使用總量並且把它存在一個單獨的查找表會顯著的節省時間。同樣的,將單詞使用量保存在單獨的數據庫/文件中,然後建立第一列的索引,會消減掉幾乎所有的處理時間。
這次探索 確實 展示了,使用 numpy 和 初出茅廬的 pytubes 以及標準的商用硬件和 Python,在合理的時間內從十億行數據的數據集中加載,處理和提取任意的統計信息是可行的,
結果:
對比谷歌 ( 沒有任何的基準線調整 ):
更多的過濾邏輯 - Tube.skip_unless() 是一個比較簡單的過濾行的方法,但是缺少組合條件(AND/OR/NOT)的能力。這可以在一些用例下更快地減少加載數據的體積。
更好的字符串匹配 —— 簡單的測試如下:startswith, endswith, contains, 和 is_one_of 可以輕易的添加,來明顯地提升加載字符串數據是的有效性。
謝謝閱讀!!是不是超級叼,14億啊 這可不是一個小數目!
如何利用Python分析14億條數據!資深程序員手把手教你!過億級!