# \[1-2]文本预处理

### 数据导入

数据源有CSV，HTML, XML, 数据库, Json, PDF, NoSQL等。

对应的Python解析器有csv, HTMLparser、 SAX Parser、 DOM Parser, XMLParser, PYODBC, json, PDFminer等。

例如

```python
# csv load 
>>>import csv
>>>with open('example.csv','rb') as f:
>>>    reader=csv.reader(f,delimiter=',',quotechar='"')
>>> for line in reader :
>>> print line[1] # assuming the second field is the raw sting

# json load 
>>>import json
>>>jsonfile=open('example.json')
>>>data=json.load(jsonfile)
>>>print data['string']
```

### 句子拆分

一个典型的句子拆分器可以根据字符串中的`.`进行拆分，也可以使用预测式分类器识别句子边界。

```python
>>>inputstring = ' This is an example sent. The sentence splitter will split on sent markers. Ohh really !!'
>>>from nltk.tokenize import sent_tokenize
>>>all_sent=sent_tokenize(inputstring)
>>>print all_sent
[' This is an example sent', 'The sentence splitter will split on markers.','Ohh really !!']
```

函数`sent_tokenize`内部使用了NLTK中构建的句子边界检测算法。

如果需要自定义句子拆分器，可以用下列的方式训练自己的句子拆分器：

```python
>>>import nltk.tokenize.punkt
>>>tokenizer =nltk.tokenize.punkt.PunktSentenceTokenizer(text)
```

### 分词

```python
# word tokenizer
>>>s ="Hi Everyone !    hola gr8" # simplest tokenizer
>>>print s.split()

>>>from nltk.tokenize import word_tokenize
>>>word_tokenize(s)

>>>from nltk.tokenize import regexp_tokenize, wordpunct_tokenize, blankline_tokenize
>>>regexp_tokenize(s, pattern='\w+')

>>>regexp_tokenize(s, pattern='\d+')

>>>wordpunct_tokenize(s)
>>>blankline_tokenize(s)
```

NLTK有两个最常用的分词器，`word_tokenize`是一种通用和健壮的分词方法，在大部分情况下都可以正常使用。另一个是`regexp_tokenize`，是相对自定义的分词器，可以满足用户的特定需求。大多数分词器派生自`regexp_tokenize`。

### 词干提取

词干提取(Stemming)表示将树的分支削减得到主干的过程。使用一些基本规则可以有效地将任何token进行削减，得到其主干。词干提取是基于规则、相对原始的处理，通过这个处理，可以将token的不同变体集合起来。例如，eat具有eating, eaten, eats等不同变体。在某些应用中，在eat和eaten之间作出区分是没有意义的，因此使用词干提取将两个经过语法变型的单词归结到单词的根。

```python
#Porter stemmer
>>>from nltk.stem import PorterStemmer # import Porter stemmer
>>>from nltk.stem.lancaster import LancasterStemmer
>>>from nltk.stem.Snowball import SnowballStemmer
>>>pst=PorterStemmer()   # create obj of the PorterStemmer
>>>lst = LancasterStemmer() # create obj of LancasterStemmer
>>>lst.stem("eating")
eat
>>>pst.stem("shopping")
shop
```

使用基本的词干提取器，如消除-s/es或-ing或-ed，可以达到70%以上的精度，而波特(Porter)词干提取器使用了更多的规则，获得了更高的准确率。

在英语上，使用波特词干提取器就足够了。

有一系列的Snowball词干提取器可以适用于荷兰语、英语、法语、德语、意大利语、葡萄牙语、罗马尼亚语、俄语等。

是否使用词干提取器通常取决于应用和领域。如果希望使用一些NLP标注器，如词性标注器(POST)、NER或依存解析器，由于词干提取将会修改token而导致不同的结果，因此应该避免使用词干提取。

### 词形还原

词形还原（lemmatization）转换单词词根的所有语法/折叠形式。

词形还原使用上下文和词性，确定单词的折叠形式，根据每个单词的词性，应用不同的标准化规则，得到词根单元（词元）。

```python
#Lemmatizer
>>>from nltk.stem import WordNetLemmatizer
>>>wlem=WordNetLemmatizer()
>>>wlem.lemmatize("ate")
eat
```

WordNetLemmatizer方法接受一个单词，在语义词典wordnet中搜索这个单词。这种方法还使用形态分析，将单词削减到词根，搜素特定词元（单词的变体）。

这里如果使用词干提取是得不到eat的。

**词干提取和词形还原之间的区别**

词干提取更多地使用基于规则的方法，获得单词语法形式的词根。但是词形还原同时考虑了给定单词的上下文和词性，然后应用语法变体的特定规则。词干提取器更容易实现，其处理速度也比词形还原器更快。

### 停用词删除

移除在语料库的所有文档中通常都会出现的一些单词。

```python
# stop word 

>>>from nltk.corpus import stopwords
>>>stoplist=stopwords.words('english') # config the language name
>>>text = "This is just a test"
>>>cleanwordlist=[word for word in text.split() if word not in stoplist]
```

`stopwords.fileids()`可以看到所有语言的停用词列表。

### 生僻字删除

一些单词，如名称、品牌、产品名称以及一些嘈杂的字符（如在处理HTML时剩下的一些遗漏字符），在性质上非常独特，因此根据不同的NLP任务，这些单词或字符也要删除。

也可以使用单词的长度作为标准，删除非常短或非常长的单词。

```python
# rare word removal 

>>>freq_dist=nltk.FreqDist(token)
>>>rarewords =freq_dist.keys()[-50:]
>>>after_rare_words= [ word for word in token not in rarewords]
```

使用FreqDist()函数，获得了语料库中术语的频率分布，选择最生僻的术语并删除。

### 拼写校正

可以使用字典查找创建一个非常基本的拼写检查器。

```python
# spell check

>>>from nltk.metrics import edit_distance
>>>edit_distance(“rain”,”shine”)
3
```

关于拼写检查，可以访问Norvig网站了解更多信息。
