# 三、文本數據: 展開、過濾和分塊
> 譯者:[@kkejili](https://github.com/kkejili)
>
> 校對者:[@HeYun](https://github.com/KyrieHee)
如果讓你來設計一個算法來分析以下段落,你會怎么做?
```
Emma knocked on the door. No answer. She knocked again and waited. There was a large maple tree next to the house. Emma looked up the tree and saw a giant raven perched at the treetop. Under the afternoon sun, the raven gleamed magnificently. Its beak was hard and pointed, its claws sharp and strong. It looked regal and imposing. It reigned the tree it stood on. The raven was looking straight at Emma with its beady black eyes. Emma felt slightly intimidated. She took a step back from the door and tentatively said, “hello?”
```
該段包含很多信息。我們知道它談到了到一個名叫Emma的人和一只烏鴉。這里有一座房子和一棵樹,艾瑪正想進屋,卻看到了烏鴉。這只華麗的烏鴉注意到艾瑪,她有點害怕,但正在嘗試交流。
那么,這些信息的哪些部分是我們應該提取的顯著特征?首先,提取主要角色艾瑪和烏鴉的名字似乎是個好主意。接下來,注意房子,門和樹的布置可能也很好。關于烏鴉的描述呢?Emma的行為呢,敲門,退后一步,打招呼呢?
本章介紹文本特征工程的基礎知識。我們從詞袋(bags of words)開始,這是基于字數統計的最簡單的文本功能。一個非常相關的變換是 tf-idf,它本質上是一種特征縮放技術。它將被我在(下一篇)章節進行全面討論。本章首先討論文本特征提取,然后討論如何過濾和清洗這些特征。
## Bag of X:把自然文本變成平面向量
無論是構建機器學習模型還是特征工程,其結果應該是通俗易懂的。簡單的事情很容易嘗試,可解釋的特征和模型相比于復雜的更易于調試。簡單和可解釋的功能并不總是會得到最精確的模型。但從簡單開始就是一個好主意,僅在絕對必要時我們可以增加其復雜性。
對于文本數據,我們可以從稱為 BOW 的字數統計開始。字數統計表中并沒有特別費力來尋找`"Emma"`或烏鴉這樣有趣的實體。但是這兩個詞在該段落中被重復提到,并且它們在這里的計數比諸如`"hello"`之類的隨機詞更高。對于此類簡單的文檔分類任務,字數統計通常比較適用。它也可用于信息檢索,其目標是檢索與輸入文本相關的文檔集。這兩個任務都很好解釋詞級特征,因為某些特定詞的存在可能是本文檔主題內容的重要指標。
## 詞袋
在詞袋特征中,文本文檔被轉換成向量。(向量只是 n 個數字的集合。)向量包含詞匯表中每個單詞可能出現的數目。 如果單詞`"aardvark"`在文檔中出現三次,則該特征向量在與該單詞對應的位置上的計數為 3。 如果詞匯表中的單詞沒有出現在文檔中,則計數為零。 例如,“這是一只小狗,它是非常可愛”的句子具有如圖所示的 BOW 表示

圖 3-1 轉換詞成向量描述圖
BOW 將文本文檔轉換為平面向量。 它是“平面的”,因為它不包含任何原始的文本結構。 原文是一系列詞語。但是詞袋向量并沒有序列;它只是記得每個單詞在文本中出現多少次。 它不代表任何詞層次結構的概念。 例如,“動物”的概念包括“狗”,“貓”,“烏鴉”等。但是在一個詞袋表示中,這些詞都是矢量的相同元素。

圖 3-2 兩個等效的詞向量,向量中單詞的排序不重要,只要它在數據集中的個數和文檔中出現數量是一致的。
重要的是特征空間中數據的幾何形狀。 在一個詞袋矢量中,每個單詞成為矢量的一個維度。如果詞匯表中有 n 個單詞,則文檔將成為n維空間中的一個點。 很難想象二維或三維以外的任何物體的幾何形狀,所以我們必須使用我們的想象力。 圖3-3顯示了我們的例句在對應于“小狗”和“可愛”兩個維度的特征空間中的樣子。

圖 3-3 特征空間中文本文檔的圖示

圖 3-4 三維特征空間
圖 3-3 和圖 3-4 描繪了特征空間中的數據向量。 坐標軸表示單個單詞,它們是詞袋表示下的特征,空間中的點表示數據點(文本文檔)。 有時在數據空間中查看特征向量也是有益的。 特征向量包含每個數據點中特征的值。 軸表示單個數據點和點表示特征向量。 圖 3-5 展示了一個例子。 通過對文本文檔進行詞袋特征化,一個特征是一個詞,一個特征向量包含每個文檔中這個詞的計數。 這樣,一個單詞被表示為一個“一個詞向量”。正如我們將在第 4 章中看到的那樣,這些文檔詞向量來自詞袋向量的轉置矩陣。

## Bag-of-N-gram
Bag-of-N-gram 或者 bag-of-ngram 是 BOW 的自然延伸。 n-gram 是 n 個有序的記號(token)。一個詞基本上是一個 1-gram,也被稱為一元模型。當它被標記后,計數機制可以將單個詞進行計數,或將重疊序列計數為 n-gram。例如,`"Emma knocked on the door"`這句話會產生 n-gram,如`"Emma knocked"`,`"knocked on"`,`"on the"`,`"the door"`。
N-gram 保留了文本的更多原始序列結構,故 bag-of-ngram可以提供更多信息。但是,這是有代價的。理論上,用 k 個獨特的詞,可能有 k 個獨立的 2-gram(也稱為 bigram)。在實踐中,并不是那么多,因為不是每個單詞后都可以跟一個單詞。盡管如此,通常有更多不同的 n-gram(n > 1)比單詞更多。這意味著詞袋會更大并且有稀疏的特征空間。這也意味著 n-gram 計算,存儲和建模的成本會變高。n 越大,信息越豐富,成本越高。
為了說明隨著 n 增加 n-gram 的數量如何增加,我們來計算紐約時報文章數據集上的 n-gram。我們使用 Pandas 和 scikit-learn 中的`CountVectorizer`轉換器來計算前 10,000 條評論的 n-gram。
```python
>>> import pandas
>>> import json
>>> from sklearn.feature_extraction.text import CountVectorizer
# Load the first 10,000 reviews
>>> f = open('data/yelp/v6/yelp_dataset_challenge_academic_dataset/yelp_academic_dataset_review.json')
>>> js = []
>>> for i in range(10000):
... js.append(json.loads(f.readline()))
>>> f.close()
>>> review_df = pd.DataFrame(js)
# Create feature transformers for unigram, bigram, and trigram.
# The default ignores single-character words, which is useful in practice because it trims
# uninformative words. But we explicitly include them in this example for illustration purposes.
>>> bow_converter = CountVectorizer(token_pattern='(?u)\\b\\w+\\b')
>>> bigram_converter = CountVectorizer(ngram_range=(2,2), token_pattern='(?u)\\b\\w+\\b')
>>> trigram_converter = CountVectorizer(ngram_range=(3,3), token_pattern='(?u)\\b\\w+\\b')
# Fit the transformers and look at vocabulary size
>>> bow_converter.fit(review_df['text'])
>>> words = bow_converter.get_feature_names()
>>> bigram_converter.fit(review_df['text'])
>>> bigram = bigram_converter.get_feature_names()
>>> trigram_converter.fit(review_df['text'])
>>> trigram = trigram_converter.get_feature_names()
>>> print (len(words), len(bigram), len(trigram))
26047 346301 847545
# Sneak a peek at the ngram themselves
>>> words[:10]
['0', '00', '000', '0002', '00am', '00ish', '00pm', '01', '01am', '02']
>>> bigram[-10:]
['zucchinis at',
'zucchinis took',
'zucchinis we',
'zuma over',
'zuppa di',
'zuppa toscana',
'zuppe di',
'zurich and',
'zz top',
'à la']
>>> trigram[:10]
['0 10 definitely',
'0 2 also',
'0 25 per',
'0 3 miles',
'0 30 a',
'0 30 everything',
'0 30 lb',
'0 35 tip',
'0 5 curry',
'0 5 pork']
```

圖3-6 Number of unique n-gram in the first 10,000 reviews of the Yelp dataset
### 過濾清洗特征
我們如何清晰地將信號從噪聲中分離出來? 通過過濾,使用原始標記化和計數來生成簡單詞表或 n-gram 列表的技術變得更加可用。 短語檢測,我們將在下面討論,可以看作是一個特別的 bigram 過濾器。 以下是執行過濾的幾種方法。
### 停用詞
分類和檢索通常不需要對文本有深入的理解。 例如,在`"Emma knocked on the door"`一句中,`"on"`和`"the"`這兩個詞沒有包含很多信息。 代詞、冠詞和介詞大部分時間并沒有顯示出其價值。流行的 Python NLP 軟件包 NLTK 包含許多語言的語言學家定義的停用詞列表。 (您將需要安裝 NLTK 并運行`nltk.download()`來獲取所有的好東西。)各種停用詞列表也可以在網上找到。 例如,這里有一些來自英語停用詞的示例詞
```
Sample words from the nltk stopword list
a, about, above, am, an, been, didn’t, couldn’t, i’d, i’ll, itself, let’s, myself, our, they, through, when’s, whom, ...
```
請注意,該列表包含撇號,并且這些單詞沒有大寫。 為了按原樣使用它,標記化過程不得去掉撇號,并且這些詞需要轉換為小寫。
### 基于頻率的過濾
停用詞表是一種去除空洞特征常用詞的方法。還有其他更統計的方法來理解“常用詞”的概念。在搭配提取中,我們看到依賴于手動定義的方法,以及使用統計的方法。同樣的想法也適用于文字過濾。我們也可以使用頻率統計。
### 高頻詞
頻率統計對濾除語料庫專用常用詞以及通用停用詞很有用。例如,紐約時報文章數據集中經常出現“紐約時報”和其中單個單詞。“議院”這個詞經常出現在加拿大議會辯論的Hansard語料庫中的“眾議院”一詞中,這是一種用于統計機器翻譯的流行數據集,因為它包含所有文檔的英文和法文版本。這些詞在普通語言中有意義,但不在語料庫中。手動定義的停用詞列表將捕獲一般停用詞,但不是語料庫特定的停用詞。
表 3-1 列出了 Yelp 評論數據集中最常用的 40 個單詞。在這里,頻率被認為是它們出現在文件(評論)中的數量,而不是它們在文件中的數量。正如我們所看到的,該列表涵蓋了許多停用詞。它也包含一些驚喜。`"s"`和`"t"`在列表中,因為我們使用撇號作為標記化分隔符,并且諸如`"Mary's"`或`"did not"`之類的詞被解析為`"Mary s"`和`"didn t"`。詞`"good"`,`"food"`和`"great"`分別出現在三分之一的評論中。但我們可能希望保留它們,因為它們對于情感分析或業務分類非常有用。

最常用的單詞最可以揭示問題,并突出顯示通常有用的單詞通常在該語料庫中曾出現過多次。 例如,紐約時報語料庫中最常見的詞是“時代”。實際上,它有助于將基于頻率的過濾與停用詞列表結合起來。還有一個棘手的問題,即何處放置截止點。 不幸的是這里沒有統一的答案。在大多數情況下截斷還需手動確定,并且在數據集改變時可能需要重新檢查。
### 稀有詞
根據任務的不同,可能還需要篩選出稀有詞。對于統計模型而言,僅出現在一個或兩個文檔中的單詞更像噪聲而非有用信息。例如,假設任務是根據他們的 Yelp 評論對企業進行分類,并且單個評論包含`"gobbledygook"`這個詞。基于這一個詞,我們將如何說明這家企業是餐廳,美容院還是一間酒吧?即使我們知道在這種情況下的這種生意發生在酒吧,它也會對于其他包含`"gobbledygook"`這個詞的評論來說,這可能是一個錯誤。
不僅稀有詞不可靠,而且還會產生計算開銷。這套 160 萬個 Yelp 評論包含 357,481 個獨特單詞(用空格和標點符號表示),其中 189,915 只出現在一次評論中,41,162 次出現在兩次評論中。超過 60% 的詞匯很少發生。這是一種所謂的重尾分布,在現實世界的數據中非常普遍。許多統計機器學習模型的訓練時間隨著特征數量線性地變化,并且一些模型是二次的或更差的。稀有詞匯會產生大量的計算和存儲成本,而不會帶來額外的收益。
根據字數統計,可以很容易地識別和修剪稀有詞。或者,他們的計數可以匯總到一個特殊的垃圾箱中,可以作為附加功能。圖3-7展示了一個短文檔中的表示形式,該短文檔包含一些常用單詞和兩個稀有詞`"gobbledygook"`和`"zylophant"`。通常單詞保留自己的計數,可以通過停用詞列表或其他頻率進一步過濾方法。這些難得的單詞會失去他們的身份并被分組到垃圾桶功能中.

由于在計算整個語料庫之前不會知道哪些詞很少,因此需要收集垃圾桶功能作為后處理步驟。
由于本書是關于特征工程的,因此我們將重點放在特征上。但稀有概念也適用于數據點。如果文本文檔很短,那么它可能不包含有用的信息,并且在訓練模型時不應使用該信息。
應用此規則時必須謹慎。維基百科轉儲包含許多不完整的存根,可能安全過濾。另一方面,推文本身就很短,并且需要其他特征和建模技巧。
### 詞干解析(Stemming)
簡單解析的一個問題是同一個單詞的不同變體會被計算為單獨的單詞。例如,`"flower"`和`"flowers"`在技術上是不同的記號,`"swimmer"`,`"swimming"`和`"swim"`也是如此,盡管它們的含義非常接近。如果所有這些不同的變體都映射到同一個單詞,那將會很好。
詞干解析是一項 NLP 任務,試圖將單詞切分為基本的語言詞干形式。有不同的方法。有些基于語言規則,其他基于觀察統計。被稱為詞形化的算法的一個子類將詞性標注和語言規則結合起來。
Porter stemmer 是英語中使用最廣泛的免費詞干工具。原來的程序是用 ANSI C 編寫的,但是很多其他程序包已經封裝它來提供對其他語言的訪問。盡管其他語言的努力正在進行,但大多數詞干工具專注于英語。
以下是通過 NLTK Python 包運行 Porter stemmer 的示例。正如我們所看到的,它處理了大量的情況,包括將`"sixties"`和`"sixty"`轉變為同一根`"sixti"`。但這并不完美。單詞`"goes"`映射到`"goe"`,而`"go"`映射到它自己。
```python
>>> import nltk
>>> stemmer = nltk.stem.porter.PorterStemmer()
>>> stemmer.stem('flowers')
u'lemon'
>>> stemmer.stem('zeroes')
u'zero'
>>> stemmer.stem('stemmer')
u'stem'
>>> stemmer.stem('sixties')
u'sixti'
>>> stemmer.stem('sixty')
u'sixty'
>>> stemmer.stem('goes')
u'goe'
>>> stemmer.stem('go')
u'go'
```
詞干解析的確有一個計算成本。 最終收益是否大于成本取決于應用程序。
### 含義的原子:從單詞到 N-gram 到短語
詞袋的概念很簡單。但是,一臺電腦怎么知道一個詞是什么?文本文檔以數字形式表示為一個字符串,基本上是一系列字符。也可能會遇到 JSON blob 或 HTML 頁面形式的半結構化文本。但即使添加了標簽和結構,基本單位仍然是一個字符串。如何將字符串轉換為一系列的單詞?這涉及解析和標記化的任務,我們將在下面討論。
### 解析和分詞
當字符串包含的不僅僅是純文本時,解析是必要的。例如,如果原始數據是網頁,電子郵件或某種類型的日志,則它包含額外的結構。人們需要決定如何處理日志中的標記,頁眉,頁腳或無趣的部分。如果文檔是網頁,則解析器需要處理 URL。如果是電子郵件,則可能需要特殊字段,例如 From,To 和 Subject 需要被特別處理,否則,這些標題將作為最終計數中的普通單詞統計,這可能沒有用處。
解析后,文檔的純文本部分可以通過標記。這將字符串(一系列字符)轉換為一系列記號。然后可以將每個記號計為一個單詞。分詞器需要知道哪些字符表示一個記號已經結束,另一個正在開始。空格字符通常是好的分隔符,正如標點符號一樣。如果文本包含推文,則不應將井號(`#`)用作分隔符(也稱為分隔符)。
有時,分析需要使用句子而不是整個文檔。例如,n-gram 是一個句子的概括,不應超出句子范圍。更復雜的文本特征化方法,如 word2vec 也適用于句子或段落。在這些情況下,需要首先將文檔解析為句子,然后將每個句子進一步標記為單詞。
### 字符串對象
字符串對象有各種編碼,如 ASCII 或 Unicode。純英文文本可以用 ASCII 編碼。 一般語言需要 Unicode。 如果文檔包含非 ASCII 字符,則確保分詞器可以處理該特定編碼。否則,結果將不正確。
### 短語檢測的搭配提取
連續的記號能立即被轉化成詞表和 n-gram。但從語義上講,我們更習慣于理解短語,而不是 n-gram。在計算自然語言處理中,有用短語的概念被稱為搭配。用 Manning 和 Schütze(1999:141)的話來說:“搭配是一個由兩個或兩個以上單詞組成的表達,它們對應于某種常規的說話方式。”
搭配比其部分的總和更有意義。例如,`"strong tea"`具有超越`"great physical strength"`和`"tea"`的不同含義,因此被認為是搭配。另一方面,“可愛的小狗”這個短語恰恰意味著它的部分總和:“可愛”和“小狗”。因此,它不被視為搭配。
搭配不一定是連續的序列。`"Emma knocked on the door"`一詞被認為包含搭配`"knock door"`,因此不是每一個搭配都是一個 n-gram。相反,并不是每個 n-gram 都被認為是一個有意義的搭配。
由于搭配不僅僅是其部分的總和,它們的含義也不能通過單個單詞計數來充分表達。作為一種表現形式,詞袋不足。袋子的 ngram 也是有問題的,因為它們捕獲了太多無意義的序列(考慮`"this is in the bag-of-ngram example"`),而沒有足夠的有意義的序列。
搭配作為功能很有用。但是,如何從文本中發現并提取它們呢?一種方法是預先定義它們。如果我們努力嘗試,我們可能會找到各種語言的全面成語列表,我們可以通過文本查看任何匹配。這將是非常昂貴的,但它會工作。如果語料庫是非常特定領域的并且包含深奧的術語,那么這可能是首選的方法。但是這個列表需要大量的手動管理,并且需要不斷更新語料庫。例如,分析推文,博客和文章可能不太現實。
自從統計 NLP 過去二十年出現以來,人們越來越多地選擇用于查找短語的統計方法。統計搭配提取方法不是建立固定的短語和慣用語言列表,而是依賴不斷發展的數據來揭示當今流行的語言。
### 基于頻率的方法
一個簡單的黑魔法是頻繁發生的 n-gram。這種方法的問題是最常發生的,這種可能不是最有用的。 表 3-2 顯示了整個 Yelp 評論數據集中最流行的 bigram(`n=2`)。 正如我們所知的,按文件計數排列的最常見的十大常見術語是非常通用的術語,并不包含太多含義。

### 用于搭配提取的假設檢驗
原始流行度計數(Raw popularity count)是一個比較粗糙的方法。我們必須找到更聰慧的統計數據才能夠輕松挑選出有意義的短語。關鍵的想法是看兩個單詞是否經常出現在一起。回答這個問題的統計機制被稱為假設檢驗。
假設檢驗是將噪音數據歸結為“是”或“否”的答案。它涉及將數據建模為從隨機分布中抽取的樣本。隨機性意味著人們永遠無法 100% 的確定答案;總會有異常的機會。所以答案附在概率上。例如,假設檢驗的結果可能是“這兩個數據集來自同一分布,其概率為 95%”。對于假設檢驗的溫和介紹,請參閱可汗學院關于假設檢驗和 p 值的教程。
在搭配提取的背景下,多年來已經提出了許多假設檢驗。最成功的方法之一是基于似然比檢驗(Dunning,1993)。對于給定的一對單詞,該方法測試兩個假設觀察的數據集。假設 1(原假設)表示,詞語 1 獨立于詞語 2 出現。另一種說法是說,看到詞語1對我們是否看到詞語2沒有影響。假設 2(備選假設)說,看到詞 1 改變了看到單詞 2 的可能性。我們采用備選假設來暗示這兩個單詞形成一個共同的短語。因此,短語檢測(也稱為搭配提取)的似然比檢驗提出了以下問題:給定文本語料庫中觀察到的單詞出現更可能是從兩個單詞彼此獨立出現的模型中生成的,或者模型中兩個詞的概率糾纏?
這是有用的。讓我們算一點。(數學非常精確和簡潔地表達事物,但它確實需要與自然語言完全不同的分析器。)

似然函數`L(Data; H)`表示在單詞對的獨立模型或非獨立模型下觀察數據集中詞頻的概率。為了計算這個概率,我們必須對如何生成數據做出另一個假設。最簡單的數據生成模型是二項模型,其中對于數據集中的每個單詞,我們拋出一個硬幣,并且如果硬幣朝上出現,我們插入我們的特殊單詞,否則插入其他單詞。在此策略下,特殊詞的出現次數遵循二項分布。二項分布完全由詞的總數,詞的出現次數和詞首概率決定。
似然比檢驗分析常用短語的算法收益如下。
1. 計算所有單體詞的出現概率:`p(w)`。
2. 計算所有唯一雙元的條件成對詞發生概率:`p(W2 × W1)`
3. 計算所有唯一的雙對數似然比對數。
4. 根據它們的似然比排序雙字節。
5. 以最小似然比值作為特征。
### 掌握似然比測試
關鍵在于測試比較的不是概率參數本身,而是在這些參數(以及假設的數據生成模型)下觀察數據的概率。可能性是統計學習的關鍵原則之一。但是在你看到它的前幾次,這絕對是一個令人困惑的問題。一旦你確定了邏輯,它就變得直觀了。
還有另一種基于點互信息的統計方法。但它對真實世界文本語料庫中常見的罕見詞很敏感。因此它不常用,我們不會在這里展示它。
請注意,搭配抽取的所有統計方法,無論是使用原始頻率,假設測試還是點對點互信息,都是通過過濾候選詞組列表來進行操作的。生成這種清單的最簡單和最便宜的方法是計算 n-gram。它可能產生不連續的序列,但是它們計算成本頗高。在實踐中,即使是連續 n-gram,人們也很少超過 bi-gram 或 tri-gram,因為即使在過濾之后,它們的數量也很多。為了生成更長的短語,還有其他方法,如分塊或與詞性標注相結合。
### 分塊(Chunking)和詞性標注(part-of-Speech Tagging)
分塊比 n-gram 要復雜一點,因為它基于詞性,基于規則的模型形成了記號序列。
例如,我們可能最感興趣的是在問題中找到所有名詞短語,其中文本的實體,主題最為有趣。 為了找到這個,我們使用詞性標記每個作品,然后檢查該標記的鄰域以查找詞性分組或“塊”。 定義單詞到詞類的模型通常是語言特定的。 幾種開源 Python 庫(如 NLTK,Spacy 和 TextBlob)具有多種語言模型。
為了說明 Python 中的幾個庫如何使用詞性標注非常簡單地進行分塊,我們再次使用 Yelp 評論數據集。 我們將使用 spacy 和 TextBlob 來評估詞類以找到名詞短語。
```python
>>> import pandas as pd
>>> import json
# Load the first 10 reviews
>>> f = open('data/yelp/v6/yelp_dataset_challenge_academic_dataset/yelp_academic_dataset_review.json')
>>> js = []
>>> for i in range(10):
js.append(json.loads(f.readline()))
>>> f.close()
>>> review_df = pd.DataFrame(js)
## First we'll walk through spaCy's functions
>>> import spacy
# preload the language model
>>> nlp = spacy.load('en')
# We can create a Pandas Series of spaCy nlp variables
>>> doc_df = review_df['text'].apply(nlp)
# spaCy gives you fine grained parts of speech using: (.pos_)
# and coarse grained parts of speech using: (.tag_)
>>> for doc in doc_df[4]:
print([doc.text, doc.pos_, doc.tag_])
Got VERB VBP
a DET DT
letter NOUN NN
in ADP IN
the DET DT
mail NOUN NN
last ADJ JJ
week NOUN NN
that ADJ WDT
said VERB VBD
Dr. PROPN NNP
Goldberg PROPN NNP
is VERB VBZ
moving VERB VBG
to ADP IN
Arizona PROPN NNP
to PART TO
take VERB VB
a DET DT
new ADJ JJ
position NOUN NN
there ADV RB
in ADP IN
June PROPN NNP
. PUNCT .
SPACE SP
He PRON PRP
will VERB MD
be VERB VB
missed VERB VBN
very ADV RB
much ADV RB
. PUNCT .
SPACE SP
I PRON PRP
think VERB VBP
finding VERB VBG
a DET DT
new ADJ JJ
doctor NOUN NN
in ADP IN
NYC PROPN NNP
that ADP IN
you PRON PRP
actually ADV RB
like INTJ UH
might VERB MD
almost ADV RB
be VERB VB
as ADV RB
awful ADJ JJ
as ADP IN
trying VERB VBG
to PART TO
find VERB VB
a DET DT
date NOUN NN
! PUNCT .
# spaCy also does some basic noun chunking for us
>>> print([chunk for chunk in doc_df[4].noun_chunks])
[a letter, the mail, Dr. Goldberg, Arizona, a new position, June, He, I, a new doctor, NYC, you, a date]
#####
## We can do the same feature transformations using Textblob
>>> from textblob import TextBlob
# The default tagger in TextBlob uses the PatternTagger, which is fine for our example.
# You can also specify the NLTK tagger, which works better for incomplete sentences.
>>> blob_df = review_df['text'].apply(TextBlob)
>>> blob_df[4].tags
[('Got', 'NNP'),
('a', 'DT'),
('letter', 'NN'),
('in', 'IN'),
('the', 'DT'),
('mail', 'NN'),
('last', 'JJ'),
('week', 'NN'),
('that', 'WDT'),
('said', 'VBD'),
('Dr.', 'NNP'),
('Goldberg', 'NNP'),
('is', 'VBZ'),
('moving', 'VBG'),
('to', 'TO'),
('Arizona', 'NNP'),
('to', 'TO'),
('take', 'VB'),
('a', 'DT'),
('new', 'JJ'),
('position', 'NN'),
('there', 'RB'),
('in', 'IN'),
('June', 'NNP'),
('He', 'PRP'),
('will', 'MD'),
('be', 'VB'),
('missed', 'VBN'),
('very', 'RB'),
('much', 'JJ'),
('I', 'PRP'),
('think', 'VBP'),
('finding', 'VBG'),
('a', 'DT'),
('new', 'JJ'),
('doctor', 'NN'),
('in', 'IN'),
('NYC', 'NNP'),
('that', 'IN'),
('you', 'PRP'),
('actually', 'RB'),
('like', 'IN'),
('might', 'MD'),
('almost', 'RB'),
('be', 'VB'),
('as', 'RB'),
('awful', 'JJ'),
('as', 'IN'),
('trying', 'VBG'),
('to', 'TO'),
('find', 'VB'),
('a', 'DT'),
('date', 'NN')]
>>> print([np for np in blob_df[4].noun_phrases])
['got', 'goldberg', 'arizona', 'new position', 'june', 'new doctor', 'nyc'
```
你可以看到每個庫找到的名詞短語有些不同。spacy 包含英語中的常見單詞,如`"a"`和`"the"`,而 TextBlob 則刪除這些單詞。這反映了規則引擎的差異,它驅使每個庫都認為是“名詞短語”。 你也可以寫你的詞性關系來定義你正在尋找的塊。使用 Python 進行自然語言處理可以深入了解從頭開始用 Python 進行分塊。
## 總結
詞袋模型易于理解和計算,對分類和搜索任務很有用。但有時單個單詞太簡單,不足以將文本中的某些信息封裝起來。為了解決這個問題,人們寄希望于比較長的序列。Bag-of-ngram 是 BOW 的自然概括,這個概念仍然容于理解,而且它的計算開銷這就像 BOW 一樣容易。
Bag of-ngram 生成更多不同的 ngram。它增加了特征存儲成本,以及模型訓練和預測階段的計算成本。雖然數據點的數量保持不變,但特征空間的維度現在更大。因此數據密度更為稀疏。n 越高,存儲和計算成本越高,數據越稀疏。由于這些原因,較長的 n-gram 并不總是會使模型精度的得到提高(或任何其他性能指標)。人們通常在`n = 2`或 3 時停止。較少的 n-gram 很少被使用。
防止稀疏性和成本增加的一種方法是過濾 n-gram 并保留最有意義的短語。這是搭配抽取的目標。理論上,搭配(或短語)可以在文本中形成非連續的標記序列。然而,在實踐中,尋找非連續詞組的計算成本要高得多并且沒有太多的收益。因此搭配抽取通常從一個候選人名單中開始,并利用統計方法對他們進行過濾。
所有這些方法都將一系列文本標記轉換為一組斷開的計數。與一個序列相比,一個集合的結構要少得多;他們導致平面特征向量。
在本章中,我們用簡單的語言描述文本特征化技術。這些技術將一段充滿豐富語義結構的自然語言文本轉化為一個簡單的平面向量。我們討論一些常用的過濾技術來降低向量維度。我們還引入了 ngram 和搭配抽取作為方法,在平面向量中添加更多的結構。下一章將詳細介紹另一種常見的文本特征化技巧,稱為 tf-idf。隨后的章節將討論更多方法將結構添加回平面向量。
## 參考文獻
Dunning, Ted. 1993. “Accurate methods for the statistics of surprise and
coincidence.” ACM Journal of Computational Linguistics, special issue on using large corpora , 19:1 (61—74).
“Hypothesis Testing and p-Values.” Khan Academy, accessed May 31,
2016,<https://www.khanacademy.org/math/probability/statistics-inferential/hypothesis-testing/v/hypothesis-testing-and-p-values>.
Manning,Christopher D. and Hinrich Schütze. 1999. Foundations of StatisticalNatural Language Processing . Cambridge, Massachusettes: MIT Press.
Sometimes people call it the document “vector.” The vector extends from the original and ends at the specified point. For our purposes, “vector” and “point” are the same thing.