文本数据分析(三):用Python实现文本数据预处理

2018 年 4 月 12 日 论智 Matthew Mayo
来源:KDnuggets
编译:Bing

编者按:在前两篇文章中,我们首先讨论了处理文本数据的基本框架,然后详细说明了文本数据预处理的步骤。今天,作者Matthew Mayo将为大家带来用Python进行实际预处理的案例。

相关阅读:文本数据分析(一):基本框架

文本数据分析(二):文本数据预处理的方法

文本预处理在整个框架中的位置

我们的目标是从文本的主体(一个冗长、未经处理的单一字符串)中,得到一个或几个经过清洗的tokens列表,用于进一步的文本挖掘或自然语言处理任务。

首先,我们输入以下代码。

  
    
    
    
  1. import re, string, unicodedata

  2. import nltk

  3. import contractions

  4. import inflect

  5. from bs4 import BeautifulSoup

  6. from nltk import word_tokenize, sent_tokenize

  7. from nltk.corpus import stopwords

  8. from nltk.stem import LancasterStemmer, WordNetLemmatizer

除了标准的Python库外,我们还用了以下工具:

  • NLTK:自然语言工具箱是Python生态系统中最著名、最广泛的NLP库之一,它能用于各种任务,比如标记化、词干提取、词性标注等等。

  • BeautifulSoup:这款工具在从HTML和XML文件中提取数据中非常有用。

  • Inflect:这是一个简单的库,用于复数、单数名词、序数词和不定冠词的生成以及将数字转换为单词等任务。

  • Contractions:这个库也很简单,只是用于展开缩写。

如果你只安装了NLTK,没有下载其他数据的话,点击:https://www.nltk.org/data.html。

我们需要一些文本样本,刚开始我们选用一些小型、自制的文本输入进去,从而能轻易地了解每一步的结果。

  
    
    
    
  1. sample = """<h1>Title Goes Here</h1>

  2. <b>Bolded Text</b>

  3. <i>Italicized Text</i>

  4. <img src="this should all be gone"/>

  5. <a href="this will be gone, too">But this will still be here!</a>

  6. I run. He ran. She is running. Will they stop running?

  7. I talked. She was talking. They talked to them about running. Who ran to the talking runner?

  8. [Some text we don't want to keep is in here]

  9. ¡Sebastián, Nicolás, Alejandro and Jéronimo are going to the store tomorrow morning!

  10. something... is! wrong() with.,; this :: sentence.

  11. I can't do this anymore. I didn't know them. Why couldn't you have dinner at the restaurant?

  12. My favorite movie franchises, in order: Indiana Jones; Marvel Cinematic Universe; Star Wars; Back to the Future; Harry Potter.

  13. Don't do it.... Just don't. Billy! I know what you're doing. This is a great little house you've got here.

  14. [This is some other unwanted text]

  15. John: "Well, well, well."

  16. James: "There, there. There, there."

  17. There are a lot of reasons not to do this. There are 101 reasons not to do it. 1000000 reasons, actually.

  18. I have to go get 2 tutus from 2 different stores, too.

  19. 22    45   1067   445

  20. {{Here is some stuff inside of double curly braces.}}

  21. {Here is more stuff in single curly braces.}

  22. [DELETE]

  23. </body>

  24. </html>"""

这虽然是个小数据集,但是没有出错。我们在这里预处理的步骤是完全可以转移的。

噪声消除

在这里,我们简单地吧噪声消除定义成在标记化之前进行的特定文本的归一化。我们通常所说的标记化和归一化是与任务无关的,而噪声消除与任务的联系更紧密。其中的任务包括:

  • 删除文件的标题、页脚

  • 删除HTML、XML等标记和元数据

  • 从其他格式(如JSON)或数据库中提取有价值的数据

正如你所认为的,噪声消除和数据收集之间的界线很模糊,由于噪声消除与其他步骤联系紧密,因此它必须在其他步骤之前进行。例如,从JSON结构中获取的文本显然要在标记化之前消除噪音。

在我们的数据预处理过程中,我们会用BeautifulSoup库清除HTML标记,并用正则表达式删除打开和封闭的双括号以及它们之间的任何内容(通过样本我们认为这是必要的)。

  
    
    
    
  1. def strip_html(text):

  2.    soup = BeautifulSoup(text, "html.parser")

  3.    return soup.get_text()

  4. def remove_between_square_brackets(text):

  5.    return re.sub('\[[^]]*\]', '', text)

  6. def denoise_text(text):

  7.    text = strip_html(text)

  8.    text = remove_between_square_brackets(text)

  9.    return text

  10. sample = denoise_text(sample)

  11. print(sample)

尽管没有强制要在标记化前的阶段做这个(你会发现这种表示适合相对顺序相对灵活的文本数据预处理任务),这时将缩写替换成原型更有帮助,因为我们的词语标注器会把“didnt”这样的单词分成“did”和“n’t”。虽然在稍后也可以补做这种标记化,但提前完成更容易也更直接。

  
    
    
    
  1. def replace_contractions(text):

  2.    """Replace contractions in string of text"""

  3.    return contractions.fix(text)

  4. sample = replace_contractions(sample)

  5. print(sample)

下面是样本消除噪音之后的结果。

  
    
    
    
  1. Title Goes Here

  2. Bolded Text

  3. Italicized Text

  4. But this will still be here!

  5. I run. He ran. She is running. Will they stop running?

  6. I talked. She was talking. They talked to them about running. Who ran to the talking runner?

  7. ¡Sebastián, Nicolás, Alejandro and Jéronimo are going to the store tomorrow morning!

  8. something... is! wrong() with.,; this :: sentence.

  9. I cannot do this anymore. I did not know them. Why could not you have dinner at the restaurant?

  10. My favorite movie franchises, in order: Indiana Jones; Marvel Cinematic Universe; Star Wars; Back to the Future; Harry Potter.

  11. do not do it.... Just do not. Billy! I know what you are doing. This is a great little house you have got here.

  12. John: "Well, well, well."

  13. James: "There, there. There, there."

  14. There are a lot of reasons not to do this. There are 101 reasons not to do it. 1000000 reasons, actually.

  15. I have to go get 2 tutus from 2 different stores, too.

  16. 22    45   1067   445

  17. {{Here is some stuff inside of double curly braces.}}

  18. {Here is more stuff in single curly braces.}

标记化

标记化是将文本中较长的字符串分割成较小的部分,或者tokens。大段文字会被分成句子,句子被标记成单词等等,只有这样才能进行下一步处理。标记化也被称为文本分割或语义分析,在我们的任务中,我们将把样本分割成单词列表。这是用NTLK的word_tokenize( )功能实现的。

  
    
    
    
  1. words = nltk.word_tokenize(sample)

  2. print(words)

以下是我们的单词tokens:

  
    
    
    
  1. ['Title', 'Goes', 'Here', 'Bolded', 'Text', 'Italicized', 'Text', 'But', 'this', 'will', 'still',

  2. 'be', 'here', '!', 'I', 'run', '.', 'He', 'ran', '.', 'She', 'is', 'running', '.', 'Will', 'they',

  3. 'stop', 'running', '?', 'I', 'talked', '.', 'She', 'was', 'talking', '.', 'They', 'talked', 'to', 'them',

  4. 'about', 'running', '.', 'Who', 'ran', 'to', 'the', 'talking', 'runner', '?', '¡Sebastián', ',',

  5. 'Nicolás', ',', 'Alejandro', 'and', 'Jéronimo', 'are', 'going', 'tot', 'he', 'store', 'tomorrow',

  6. 'morning', '!', 'something', '...', 'is', '!', 'wrong', '(', ')', 'with.', ',', ';', 'this', ':', ':',

  7. 'sentence', '.', 'I', 'can', 'not', 'do', 'this', 'anymore', '.', 'I', 'did', 'not', 'know', 'them', '.',

  8. 'Why', 'could', 'not', 'you', 'have', 'dinner', 'at', 'the', 'restaurant', '?', 'My', 'favorite',

  9. 'movie', 'franchises', ',', 'in', 'order', ':', 'Indiana', 'Jones', ';', 'Star', 'Wars', ';', 'Marvel',

  10. 'Cinematic', 'Universe', ';', 'Back', 'to', 'the', 'Future', ';', 'Harry', 'Potter', '.', 'do', 'not',

  11. 'do', 'it', '...', '.', 'Just', 'do', 'not', '.', 'Billy', '!', 'I', 'know', 'what', 'you', 'are',

  12. 'doing', '.', 'This', 'is', 'a', 'great', 'little', 'house', 'you', 'have', 'got', 'here', '.', 'John',

  13. ':', '``', 'Well', ',', 'well', ',', 'well', '.', "''", 'James', ':', '``', 'There', ',', 'there', '.',

  14. 'There', ',', 'there', '.', "''", 'There', 'are', 'a', 'lot', 'of', 'reasons', 'not', 'to', 'do', 'this',

  15. '.', 'There', 'are', '101', 'reasons', 'not', 'to', 'do', 'it', '.', '1000000', 'reasons', ',',

  16. 'actually', '.', 'I', 'have', 'to', 'go', 'get', '2', 'tutus', 'from', '2', 'different', 'stores', ',',

  17. 'too', '.', '22', '45', '1067', '445', '{', '{', 'Here', 'is', 'some', 'stuff', 'inside', 'of', 'double',

  18. 'curly', 'braces', '.', '}', '}', '{', 'Here', 'is', 'more', 'stuff', 'in', 'single', 'curly', 'braces',

  19. '.', '}']

归一化

归一化指的是将所有文本放在同一水平上,例如将所用文本转换成同样的格式(小写或大写),删除标点符号,将数字转换成对应的文字等等。归一化的目的就是统一对文本进行处理。

在我们之前的文章中提到,归一化涉及3个必要的步骤:词干提取、词形还原和其他。记住,在标记化完成之后,我们就不是将文本作为工作对象了,而是单词。以下是归一化功能的效果,功能的名称和评论应该表明它的目的。

  
    
    
    
  1. def remove_non_ascii(words):

  2.    """Remove non-ASCII characters from list of tokenized words"""

  3.    new_words = []

  4.    for word in words:

  5.        new_word = unicodedata.normalize('NFKD', word).encode('ascii', 'ignore').decode('utf-8', 'ignore')

  6.        new_words.append(new_word)

  7.    return new_words

  8. def to_lowercase(words):

  9.    """Convert all characters to lowercase from list of tokenized words"""

  10.    new_words = []

  11.    for word in words:

  12.        new_word = word.lower()

  13.        new_words.append(new_word)

  14.    return new_words

  15. def remove_punctuation(words):

  16.    """Remove punctuation from list of tokenized words"""

  17.    new_words = []

  18.    for word in words:

  19.        new_word = re.sub(r'[^\w\s]', '', word)

  20.        if new_word != '':

  21.            new_words.append(new_word)

  22.    return new_words

  23. def replace_numbers(words):

  24.    """Replace all interger occurrences in list of tokenized words with textual representation"""

  25.    p = inflect.engine()

  26.    new_words = []

  27.    for word in words:

  28.        if word.isdigit():

  29.            new_word = p.number_to_words(word)

  30.            new_words.append(new_word)

  31.        else:

  32.            new_words.append(word)

  33.    return new_words

  34. def remove_stopwords(words):

  35.    """Remove stop words from list of tokenized words"""

  36.    new_words = []

  37.    for word in words:

  38.        if word not in stopwords.words('english'):

  39.            new_words.append(word)

  40.    return new_words

  41. def stem_words(words):

  42.    """Stem words in list of tokenized words"""

  43.    stemmer = LancasterStemmer()

  44.    stems = []

  45.    for word in words:

  46.        stem = stemmer.stem(word)

  47.        stems.append(stem)

  48.    return stems

  49. def lemmatize_verbs(words):

  50.    """Lemmatize verbs in list of tokenized words"""

  51.    lemmatizer = WordNetLemmatizer()

  52.    lemmas = []

  53.    for word in words:

  54.        lemma = lemmatizer.lemmatize(word, pos='v')

  55.        lemmas.append(lemma)

  56.    return lemmas

  57. def normalize(words):

  58.    words = remove_non_ascii(words)

  59.    words = to_lowercase(words)

  60.    words = remove_punctuation(words)

  61.    words = replace_numbers(words)

  62.    words = remove_stopwords(words)

  63.    return words

  64. words = normalize(words)

  65. print(words)

进行归一化之后:

  
    
    
    
  1. ['title', 'goes', 'bolded', 'text', 'italicized', 'text', 'still', 'run', 'ran', 'running', 'stop',

  2. 'running', 'talked', 'talking', 'talked', 'running', 'ran', 'talking', 'runner', 'sebastian', 'nicolas',

  3. 'alejandro', 'jeronimo', 'going', 'store', 'tomorrow', 'morning', 'something', 'wrong', 'sentence',

  4. 'anymore', 'know', 'could', 'dinner', 'restaurant', 'favorite', 'movie', 'franchises', 'order',

  5. 'indiana', 'jones', 'marvel', 'cinematic', 'universe', 'star', 'wars', 'back', 'future', 'harry',

  6. 'potter', 'billy', 'know', 'great', 'little', 'house', 'got', 'john', 'well', 'well', 'well', 'james',

  7. 'lot', 'reasons', 'one hundred and one', 'reasons', 'one million', 'reasons', 'actually', 'go', 'get',

  8. 'two', 'tutus', 'two', 'different', 'stores', 'twenty-two', 'forty-five', 'one thousand and sixty-seven',

  9. 'four hundred and forty-five', 'stuff', 'inside', 'double', 'curly', 'braces', 'stuff', 'single',

  10. 'curly', 'braces']

进行词干提取和词形变化之后:

  
    
    
    
  1. def stem_and_lemmatize(words):

  2.    stems = stem_words(words)

  3.    lemmas = lemmatize_verbs(words)

  4.    return stems, lemmas

  5. stems, lemmas = stem_and_lemmatize(words)

  6. print('Stemmed:\n', stems)

  7. print('\nLemmatized:\n', lemmas)

最后生成两种新的列表,其中一个是提取了词干的tokens,另一个是只有对应的动词的tokens。根据接下来的NLP任务,你可以选择其中一个进行处理。

  
    
    
    
  1. Stemmed:

  2. ['titl', 'goe', 'bold', 'text', 'it', 'text', 'stil', 'run', 'ran', 'run', 'stop', 'run', 'talk',

  3. 'talk', 'talk', 'run', 'ran', 'talk', 'run', 'sebast', 'nicola', 'alejandro', 'jeronimo', 'going',

  4. 'stor', 'tomorrow', 'morn', 'someth', 'wrong', 'sent', 'anym', 'know', 'could', 'din', 'resta',

  5. 'favorit', 'movy', 'franch', 'ord', 'indian', 'jon', 'marvel', 'cinem', 'univers', 'star', 'war', 'back',

  6. 'fut', 'harry', 'pot', 'bil', 'know', 'gre', 'littl', 'hous', 'got', 'john', 'wel', 'wel', 'wel', 'jam',

  7. 'lot', 'reason', 'one hundred and on', 'reason', 'one million', 'reason', 'act', 'go', 'get', 'two',

  8. 'tut', 'two', 'diff', 'stor', 'twenty-two', 'forty-five', 'one thousand and sixty-seven', 'four hundred

  9. and forty-five', 'stuff', 'insid', 'doubl', 'cur', 'brac', 'stuff', 'singl', 'cur', 'brac']

  10. Lemmatized:

  11. ['title', 'go', 'bolded', 'text', 'italicize', 'text', 'still', 'run', 'run', 'run', 'stop', 'run',

  12. 'talk', 'talk', 'talk', 'run', 'run', 'talk', 'runner', 'sebastian', 'nicolas', 'alejandro', 'jeronimo',

  13. 'go', 'store', 'tomorrow', 'morning', 'something', 'wrong', 'sentence', 'anymore', 'know', 'could',

  14. 'dinner', 'restaurant', 'favorite', 'movie', 'franchise', 'order', 'indiana', 'jones', 'marvel',

  15. 'cinematic', 'universe', 'star', 'war', 'back', 'future', 'harry', 'potter', 'billy', 'know', 'great',

  16. 'little', 'house', 'get', 'john', 'well', 'well', 'well', 'jam', 'lot', 'reason', 'one hundred and one',

  17. 'reason', 'one million', 'reason', 'actually', 'go', 'get', 'two', 'tutus', 'two', 'different', 'store',

  18. 'twenty-two', 'forty-five', 'one thousand and sixty-seven', 'four hundred and forty-five', 'stuff',

  19. 'inside', 'double', 'curly', 'brace', 'stuff', 'single', 'curly', 'brace']

关于到底是采用词干提取还是词形变化的结果,这里有个讨论:https://nlp.stanford.edu/IR-book/html/htmledition/stemming-and-lemmatization-1.html

这就是用Python进行简单的文本数据预处理的方法,我建议你动手试一试。在下篇文章中,我们会用同样方法进行预处理,然后继续实际文本数据的任务介绍。敬请期待!

原文地址:https://www.kdnuggets.com/2018/03/text-data-preprocessing-walkthrough-python.html

登录查看更多
7

相关内容

Natural Language Toolkit,自然语言处理工具包,在NLP领域中,最常使用的一个Python库。
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】从Excel中学习数据挖掘,223页pdf
专知会员服务
90+阅读 · 2020年6月28日
【干货书】用于概率、统计和机器学习的Python,288页pdf
专知会员服务
287+阅读 · 2020年6月3日
Python地理数据处理,362页pdf,Geoprocessing with Python
专知会员服务
113+阅读 · 2020年5月24日
【经典书】Python数据数据分析第二版,541页pdf
专知会员服务
192+阅读 · 2020年3月12日
【Amazon】使用预先训练的Transformer模型进行数据增强
专知会员服务
56+阅读 · 2020年3月6日
强化学习最新教程,17页pdf
专知会员服务
174+阅读 · 2019年10月11日
基于知识图谱的文本挖掘 - 超越文本挖掘
专知
38+阅读 · 2019年8月18日
基于PyTorch/TorchText的自然语言处理库
专知
28+阅读 · 2019年4月22日
Python用于NLP :处理文本和PDF文件
Python程序员
4+阅读 · 2019年3月27日
文本挖掘中特征选择(附python实现)
七月在线实验室
4+阅读 · 2018年5月22日
文本数据分析(一):基本框架
论智
6+阅读 · 2018年4月9日
干货 | 自然语言处理(5)之英文文本挖掘预处理流程
机器学习算法与Python学习
7+阅读 · 2018年4月5日
文本挖掘之特征选择(python 实现)
数据挖掘入门与实战
4+阅读 · 2017年7月19日
Arxiv
4+阅读 · 2019年4月17日
Arxiv
3+阅读 · 2018年12月18日
VIP会员
相关VIP内容
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】从Excel中学习数据挖掘,223页pdf
专知会员服务
90+阅读 · 2020年6月28日
【干货书】用于概率、统计和机器学习的Python,288页pdf
专知会员服务
287+阅读 · 2020年6月3日
Python地理数据处理,362页pdf,Geoprocessing with Python
专知会员服务
113+阅读 · 2020年5月24日
【经典书】Python数据数据分析第二版,541页pdf
专知会员服务
192+阅读 · 2020年3月12日
【Amazon】使用预先训练的Transformer模型进行数据增强
专知会员服务
56+阅读 · 2020年3月6日
强化学习最新教程,17页pdf
专知会员服务
174+阅读 · 2019年10月11日
相关资讯
基于知识图谱的文本挖掘 - 超越文本挖掘
专知
38+阅读 · 2019年8月18日
基于PyTorch/TorchText的自然语言处理库
专知
28+阅读 · 2019年4月22日
Python用于NLP :处理文本和PDF文件
Python程序员
4+阅读 · 2019年3月27日
文本挖掘中特征选择(附python实现)
七月在线实验室
4+阅读 · 2018年5月22日
文本数据分析(一):基本框架
论智
6+阅读 · 2018年4月9日
干货 | 自然语言处理(5)之英文文本挖掘预处理流程
机器学习算法与Python学习
7+阅读 · 2018年4月5日
文本挖掘之特征选择(python 实现)
数据挖掘入门与实战
4+阅读 · 2017年7月19日
Top
微信扫码咨询专知VIP会员