資源 | 十五分鐘完成Regex五天任務:FastText,語料庫數據快速清理利器

 2017-11-10 12:27:00.0

原標題:資源 | 十五分鐘完成Regex五天任務:FastText,語料庫數據快速清理利器

選自FreeCoderCamp

作者:Vikash Singh

參與:李澤南、劉曉坤

數據清理是很多機器學習任務上我們遇到的首要問題。本文介紹的 FastText 是一個開源 Python 庫,可用於快速進行大規模語料庫的文本搜索與替換。該項目的作者表示,使用正則表達式(Regex)需要 5 天的任務在新的方法中只需要 15 分鐘即可完成。

項目鏈接:https://github.com/vi3k6i5/flashtext

自然語言處理領域的開發者在處理文本之前必須對數據進行清理。有些時候,此類工作是由關鍵詞替換完成的,就像吧「Java」替換成「Java」。另一些時候,我們只需要知道文檔中是否提到了「Java」。

這類數據清理任務是大多數處理文本的數據科學項目必須要做的。

數據科學從清理數據開始

本文作者是 Belong.co 的一名數據科學家,需要從事有關自然語言處理的工作,於是遇到了這個問題。當我在自己的文檔語料庫中開始訓練 Word2Vec 模型時,它開始將同義詞歸爲同類項,「Javaing」被歸類爲「Java」的同類項。

爲了解決這個問題,我寫了一個正則表達式(Regex),用標準化命名來替換所有已知的同義詞。Regex 會將「Javaing」替換爲「Java」,這解決了一個問題,卻又帶來了另一個問題。

有些人遇到問題時會想:「沒關係,我們有正則表達式。」現在問題變成了兩個。

上文所述引自 Stack-exchange question,現在讓我遇到了。

事實證明,正則表達式的速度很快——如果要搜索和替換的關鍵詞數量是一百多個的話。但是面對超過 20k 個關鍵詞,300 萬個文件的語料庫,事情就會變得很糟。當我測試我的代碼時,我發現完全運行需要 5 天之久。

通常,面對這種情況我們的解決方案是並行運算。但在面對上千萬個文件中成百上千出現頻次的關鍵詞,並行的性能提升有限,我們必須找到更好的方法!

幸好,在 Stack Overflow 上我的疑問獲得了大家的關注,網友們和公司同事 Vinay Pandey、Suresh Lakshmanan 等人提到了一個名叫 Aho-Corasick 算法的神奇工具,以及前綴樹數據結構(Trie Data Structure)。然而目前網絡上還缺乏相關資源。

  • Aho-Corasick 算法:https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm

  • Trie Data Structure:https://en.wikipedia.org/wiki/Trie

所以我開始自己動手,FlashText 誕生了。

在介紹 FlashText 的結構和工作原理之前,先看看它的搜索性能表現:

下面的紅線是 FlashText 的搜索耗時

如上圖所示,Regex 算法和 FlashText 搜索同一篇文檔的耗時相差很大。隨着關鍵詞數量的增加,Regex 的耗時呈線性增長,而對於 FlashText 來說並沒有影響。

FlashText 可以把 5 天的工作縮短到 15 分鐘!

這是 FlashText 替換的速度:

同樣,下面的紅線是 FlashText 的替換速度。

所以,FlashText 是什麼?

FlashText 是我在 GitHub 上開源的一個 Python 庫,它能高效地提取和替換關鍵詞。

使用 FlashText 時,首先你需要發送一系列關鍵詞,這個列表將被用於在內部建立一個前綴樹字典。隨後你需要傳遞一個字符串,告訴它你需要執行替換還是搜索。

在替換時,它會創建一個新字符串來替換關鍵詞。在搜索時,它會返回一個關鍵詞列表。這一切都將在輸入字符串上進行。

有的用戶是這樣評價FastText的:

Radim Řehůřek 是著名 Python 庫 Gensim 的作者

FlashText 爲什麼那麼快?

我們用一個例子來嘗試和理解這一部分。假設我們有一個包含三個單詞的句子 I like Python,和一個有四個單詞的語料庫 {Python,Java,J2ee,Ruby}。

如果每次取出語料庫中的一個單詞,並檢查其在句子中是否出現,這需要四次操作。

  1. is'Python'insentence?

  2. is'Java'insentence?

  3. ...

如果語料庫有 n 個單詞,意味着需要做 n 次的循環操作,並且每一個時間步的搜索都是 is in sentence ? 這有點像正則表示式相配(Regex match)中的過程。

還有另一種和第一種相反的方法。對於句子中的每一個單詞,檢查其是否在語料庫中出現。

  1. is'I'incorpus?

  2. is'like'incorpus?

  3. is'python'incorpus?

如果句子 m 個單詞,意味着需要做 m 次的循環操作。在這個例子中所需的時間步取決於句子中的單詞數。而使用字典查詢進行 is in corpus ? 會快得多。

FlashText 基於第二種方法,由 Aho-Corasick 算法和前綴樹(Trie)數據結構所啓發。

它的工作方式爲:

首先由語料庫創建一個如下圖所示的前綴樹字典:

語料庫的前綴樹字典

Start 和 EOT(End Of Term,期末)表示單詞的邊界比如 space、period 和 new_line。只有兩側都有邊界的關鍵詞才能得到匹配,這可以防止把 apple 匹配到 pineapple。

下一步我們將取輸入字符串爲 I like Python,並按字符逐個對齊進行搜索。

  1. Step1: isI indictionary? No

  2. Step2: islike indictionary? No

  3. Step3: isPythonindictionary? Yes

Python 出現在字典中。

由於這是一個字符匹配過程,我們可以輕易地在進行到 l 的時候跳過整個 like ,因爲 start 並沒有和 l 相連。這使得跳過缺失單詞的過程變得非常快。

FlashText 算法只需要遍歷輸入字符串『I like Python』的每一個字符。即使字典有上百萬個關鍵詞,對運行時間也沒有任何影響。這是 FlashText 算法的真正威力。

什麼時候需要使用 FlashText?

簡單的回答是:當關鍵詞數量>500 的時候

當關鍵詞數量>500 的時候,FlashText 的搜索速度開始超過 Regex

完整的回答是:Regex 可以搜索基於特殊字符比如^、$、*、d 等的關鍵詞,而 FlashText 不支持這種搜索。

所以如果想要匹配部分單詞比如『worddvec』,使用 FlashText 並沒有好處,但其非常善於提取完整的單詞比如『word2vec』。

用於尋找關鍵詞的代碼

  1. # pip install flashtext

  2. fromflashtext.keyword importKeywordProcessor

  3. keyword_processor = KeywordProcessor()

  4. keyword_processor.add_keyword('Big Apple', 'New York')

  5. keyword_processor.add_keyword('Bay Area')

  6. keywords_found = keyword_processor.extract_keywords('I love Big Apple and Bay Area.')

  7. keywords_found

  8. # ['New York', 'Bay Area']

使用 FlashText 提取關鍵詞的簡單例子

用於替換關鍵詞的代碼

FlashText 不僅可以提取句子中的關鍵詞還可以對其進行替換。我們將此作爲數據處理管道的數據清理步驟。

  1. fromflashtext.keyword importKeywordProcessor

  2. keyword_processor = KeywordProcessor()

  3. keyword_processor.add_keyword('Big Apple', 'New York')

  4. keyword_processor.add_keyword('New Delhi', 'NCR region')

  5. new_sentence = keyword_processor.replace_keywords('I love Big Apple and new delhi.')

  6. new_sentence

  7. # 'I love New York and NCR region.'

使用 FlashText 替換關鍵詞的簡單例子

原文鏈接:https://medium.freecodecamp.org/regex-was-taking-5-days-flashtext-does-it-in-15-minutes-55f04411025f

本文爲機器之心編譯,轉載請聯繫本公衆號獲得授權。

責任編輯:

文章來源:機器之心