首先简单介绍一下N-Gram,N-Gram是大词汇连续语音识别中常用的一种语言模型,对中文而言,我们称之为汉语语言模型(CLM, Chinese Language Model)。在做自然语言处理时,通常会根据句子中的固定搭配把句子划分为小片段,这里的固定搭配有2个词组成(2-gram),也有三个词组成(3-gram)的,甚至更多。
from urllib import urlopen
from bs4 import BeautifulSoup
def ngrams(input,n):
input = input.split(' ')
output = []
for i in range(len(input)-n+1):
output.append(input[i:i+n])
return output
html = urlopen("http://en.wikipedia.org/wiki/Python_(programming_language)")
bsObj = BeautifulSoup(html,'html.parser')
content = bsObj.find("div",{"id":"mw-content-text"}).get_text()
ngrams = ngrams(content,2)
print ngrams
print ("2-grams count is : "+str(len(ngrams)))
运行代码后得到摘取的数据1,数据2是加入去空格代码后摘取的结果,如下:
数据1:
[u'Specification', u'Promise\nRevolution'], [u'Promise\nRevolution', u'OS\n\n\n\n\n\n\n\n\n\n\n\n'],
[u'OS\n\n\n\n\n\n\n\n\n\n\n\n', u'Book\n'], [u'Book\n', u'Category\n'],
[u'Category\n', u'Commons\n'], [u'Commons\n', u'Portal\n\n\n\n\n\n\n\n\n\n\n\n']
数据2:
[u'Python', u'(2'], [u'(2', u'ed.).'], [u'ed.).', u'ISBN\xa0978-0-9821060-1-3.'],
[u'ISBN\xa0978-0-9821060-1-3.', u'Retrieved'], [u'Retrieved', u'20'],
[u'20', u'February'], [u'February', u'2014.\xa0\n^'],
[u'2014.\xa0\n^', u'van'], [u'van', u'Rossum,'], [u'Rossum,', u'Guido'], [u'Guido', u'(22'],
[u'(22', u'April'], [u'April', u'2009).'], [u'2009).', u'"Tail']
在数据1中我们发现大量不必要的空格,因此要除去,另外不符合utf-8的编码数据也要除去,使用的当然是正则表达式了,在ngrams函数中加入:
content = re.sub('\n+', " ", content)
content = re.sub(' +', " ", content)
content = bytes(content, "UTF-8")
content = content.decode("ascii", "ignore")
再次运行后得到数据2,发现有大量不需要的数字,甚至会有单个英文字母(“i”和“a”除外)和特殊字符(string.punctuation),这些东西在绝大多数数据清洗工作中都是要被清洗掉的,很幸运可以再次通过编写代码去除。便于扩展,去除脏数据的代码和ngrams代码分开编写:
def cleanInput(input):
input = re.sub('\n+', " ", input) input = re.sub('\[[0-9]*\]', "", input)
input = re.sub(' +', " ", input)
#下面两句被我注释掉的原因是在python 2版本bytes是关键字,只接受一个参数,显然作者写的是python 3代码,
#input = bytes(input, "UTF-8")
#input = input.decode("ascii", "ignore")
cleanInput = []
input = input.split(' ')
for item in input:
item = item.strip(string.punctuation)
if len(item) > 1 or (item.lower() == 'a' or item.lower() == 'i'):
cleanInput.append(item)
return cleanInput
def ngrams(input, n):
input = cleanInput(input)
output = []
for i in range(len(input)-n+1):
output.append(input[i:i+n])
return output
数据标准化也即数据归一化,它是数据挖掘的一项基础工作,不同评价指标往往具有不同的量纲和量纲单位,这样的情况会影响到数据分析的结果,为了消除指标之间的量纲影响,需要进行数据标准化处理,以解决数据指标之间的可比性。本文并未涉及到那么深,只是进行一些简单的标准化处理,举个例子,电话号码会有“(555)123-4567”、“555.123.4567”、“555-1234567”等不同的写法,而我们要的就是5551234567这种格式,所以要以此为标准进行处理。又比如在“Cleaning in code”小节中我们得到的结果很多都是重复的,”[‘Software’, ‘Foundation’]”这个2-grams就出现的40次之多,类似这样重复的进行合并一方面减少数据存储的压力另一方面便于分析。
针对上小节的处理方法,由于Python的字典是无序的,我们需要用到OrderedDict,来自Python的collections library:
from collections import OrderedDict
...
ngrams = ngrams(content, 2)
ngrams = OrderedDict(sorted(ngrams.items(), key=lambda t: t[1], reverse=True))
print(ngrams)
部分结果:
("['Software', 'Foundation']", 40), ("['Python', 'Software']", 38), ("['of', 'th
e']", 35), ("['Foundation', 'Retrieved']", 34), ("['of', 'Python']", 28), ("['in
', 'the']", 21), ("['van', 'Rossum']", 18)
除此之外还有一些特殊情况需要我们处理:2-grams中“Python 1st”和“Python first”意义一样,需要合并,单个词“co-ordinated”和“coordinated”也是一样的,也要作同一个词处理。
本小节主要介绍了一款数据清洗的开源软件OpenRefine,使用它之前你需要将你的数据保存为CSV格式。需要了解更多请访问:OpenRefine’s GitHub page
注:本文为读书笔记,内容基本来自Web Scraping with Python(Ryan Mitchell著),部分代码有所改动,版权归作者所有,转载请注明出处