上一章提到,Python是一门易用且强大的编程语言,所以本书将其作为示例语言使用,同时也提供了一套基础的Python文本分析的教程。

为什么要介绍这些Python技巧?原因是希望读者具有Python和高中数学方面的背景知识,然而也许有很多读者从来没有编写过Python代码。对编写过Python代码的读者来说,文本分析和字符串操作所用到的知识和Web开发(例如使用Python编写的Web框架Django来构建网站)所用到的知识也是截然不同的。本章介绍的主题如下:

  • 为什么用Python来做文本分析;
  • Python文本分析技巧。

2.1 为什么用Python来做文本分析

Python以字符串的形式表示文本,这些字符串对象对应的类是str。它是一种不可变序的UNICODE或字符。有一点必须仔细区分:Python 3中,所有字符串默认是UNICODE;但在Python 2中,str类限制为ASCII码,需要另外一个UNICODE类来专门处理UNICODE。

UNICODE仅仅是一种编码语言或处理文本的方式。例如,字母Z的UNICODE值是U+05A。从历史上看,Python中的许多编码类型需要开发人员自行处理,所有的底层操作都以字节为单位。事实上,从版本2到版本3的升级中,Python处理UNICODE的方式的转变在其社区内引发了很多讨论,有批评也有支持。目前,很多代码正在从Python 2迁移至Python 3,但关于UNICODE处理方式的争论一直没有停止。

字符串的底层操作是以字节为单位进行的。字节中存储的是数字,不同的数字组合起来表示不同的字符或符号。这就是UNICODE和ASCII采用不同的方式来表示字符的本质原因。因为在Python 2中,字符串被存储为字节;而在Python 3中,字符串被存储为UNICODE。

本书不会深入探讨编码的技术细节,以及在处理这些编码时遇到的问题。但建议读者在处理文本时使用Python 3和UNICODE。不推荐Python 2的原因是:它将被科学计算社区逐步淘汰,继续使用Python 2编写应用程序和代码是没有意义的。Python 3支持UNICODE,本书以Python 3来作为示例语言,即本书默认使用UNICODE来对文本进行操作。值得注意的是,为了确保使用的是UNICODE字符串,需要显式地在每个字符串开头加上u。

虽然字符串操作不是本书的重点内容,但我们会分享很多这方面的经验和技巧。例如,如果在数据集中遇到奇怪的字符,需要在文本分析之前把这些字符清理掉。适当的数据清洗会对分析结果产生正向影响,所以字符串操作是必备知识。

理解Python的基本数据结构同样有助于进行文本分析。例如,列表(list)和字典(dictionary)是文本分析中最常用的两种数据结构。

本章的目的是阐释如何使用字符串执行函数,以及如何在列表和字典中进行字符串操作。

到目前为止,我们仍然没有解释为什么优先选择Python作为示例语言。毕竟Java和Perl社区也有很多出色的文本分析库。但是Python的独特之处在于我们可以访问的社区和开源库。

上一章谈到了谷歌的TensorFlow和苹果的scikit-learn。开源代码已经拥有了与工业级代码相同的标准和效率,本书将重点介绍的spaCy库就是其中一种。Python中用来收集数据的库有tweepy(Twitter出品)、urllib(网页访问请求)和BeautifulSoup(从网页中提取HTML)。某种生态系统的参与者越多,就意味着它有更大的增长潜力(Stack Overflow上有一篇博客对这个观点进行了很好的点评),也预示着它将越来越多地应用于学术研究和工业界。在当下,使用Python就是在追赶潮流。

除了能从Python的各种库(特别是NLP库)中获得的外部技术支持外,还可以从其他多方面证明Python是一种极具吸引力的语言。其中之一是Python作为脚本语言的主要用途。脚本语言是一种支持脚本动态运行能力的语言;通常是为自动执行任务的运行环境编写的脚本。如果你想写几行代码来快速回复Facebook上来自各方好友的生日祝福,而且这是每年都要完成的,那么写脚本就是个很好的选择。脚本语言没有统一的定义,这只是平时用口语描述的一种编程方式。

Python是一种非常有用的脚本语言,因为开发人员可以快速地编写脚本来操作文本文件。它不仅易于阅读,而且处理速度也足够快。同时它也是一种解释型语言,这意味着我们在运行代码之前不需要编译代码。Python是动态类型的,即开发人员不需要在编写代码时定义数据类型。

除了其优越的技术因素,我们更感兴趣的是Python的易用性。它灵活、可读,并且具有高度抽象性,使开发工作更有效率,它能够帮助开发人员更多地关注问题本身,而不是编程技巧和代码排错。当然,这并不是说编写Python代码时不会出现错误,而是它提供的报错信息更多,出现的错误也更容易解决,例如段错误(Segmentation Fault)。

接下来将介绍用于字符串操作和文本分析的Python命令。已经熟悉Python和掌握文本基础的读者不必运行本节中的所有示例代码,但是可以快速浏览作为参考。

2.2 用Python进行文本操作

本章在前面提到,Python通过字符串表示文本。那么,应该如何指定对象是字符串呢?

word = "Bonjour World!"

word变量包含文本“Bojur World!”。注意,需要使用双引号限定文本(单引号作用等同于双引号);但如果要在字符串内部使用单引号,则需要使用双引号限定该字符串​[1]​​。在控制台输出字符串非常简单,要做的就是使用print函数。需要注意的是,在Python 3中调用print函数时,一定要将函数参数列表用括号括起来​[2]​!

print(word)
Bonjour World!

除使用变量来打印字符串外,也可以这样做:

print("Bonjour World!")
Bonjour World!

注意,不要在变量前后加引号,示例如下:

print("word")
word

这个例子将直接输出单词“word”,而不是word的变量值。

前文中提到的字符串其实是一个字符序列,那么如何访问字符串的第一个字符呢?

print(word[0])
B

可以通过访问字符数组下标做到。如何计算一个字符串的长度?

print(len(word))
14

现在我们来快速浏览更多的字符串函数,比如查找字符、计算字符以及更改单词中某一下标位置上的字母。

word.count("o")
3

word变量中包含3个字符‘o’,所以上面的代码运行结果为3。

word.find("j")
3

字符‘j’在word变量中的第一个下标位置是3。

word.index("World")
8

同理,字符串“World”在word变量中第一次出现的下标位置如上面的代码所示。

word.upper()
'BONJOUR WORLD!'

upper函数可以把字符串中的全部字符转换为大写字母。

word.lower()
'bonjour world!'

lower函数可以把字符串中的全部字符全部转换为小写字母。

word.title()
'Bonjour World!'

title函数可以把字符串中每个单词的首字母转换成大写字母。

word.capitalize()
'Bonjour world!

capitalize只把字符串中第一个字母转换成大写字母。

word.swapcase()
'bONJOUR wORLD!'

顾名思义,swapcase函数可以反转字符串中每个字母的大小写。

Python区别于其他编程语言的地方是Pythonic,算术运算符也可以用于字符串变量:

将单词“Fromage”(法语里cheese的意思)添加到word变量的末尾,只需简单地使用算术运算符中的加号即可。

print(word + " Fromage!")
'Bonjour World! Fromage!'

同样地,算术运算符中的乘号也可以用于处理字符串。

print("hello " * 5)
hello hello hello hello hello

字符串函数还可以帮助我们轻松地反转字符串或在每个字符之间添加空格符。

print( ''.join(reversed(word)))
!dlroW ruojnoB

reversed函数返回值类型是生成器(generator),我们可以对其返回值直接使用join函数。下面是使用join来添加空格符的例子:

print( " ".join(word))
B o n j o u r W o r l d !

需要查看字符串的属性时,可以调用下面这些函数:

word.isalnum()

isalnum函数用于判断字符串是否全部由数字或字母组成。

word.isalpha()

isalpha函数用于判断字符串是否全部由字母组成。

word.isdigit()

isdigit函数用于判断字符串是否全部由数字组成。

word.istitle()

istitle函数用于判断字符串中每个单词是否都以大写字母开头。

word.isupper()

isupper函数用于判断字符串中每个字符是否都是大写字母。

word.islower()

islower函数用于判断字符串中每个字符是否都是小写字母。

word.isspace()

isspace函数用于判断字符串中是否全部是空格字符​[3]​。

word.endswith('f')

endswith函数用于判断父字符串是否是由某一子字符串结尾。

word.startswith('H')

startswith函数用于判断父字符串是否由某一子字符串开头。

还可以替换字符串中的字符,或者将字符串切片(slice);实际上,为字符串切片是文本操作中非常有用且最基本的部分。

word.replace("World", "Pizza")
'Bonjour Pizza!'

replace函数在上例中把字符串中所有单词“World”替换成“Pizza”。

切片(slice)是获取字符串的一部分的过程。其语法如下:

New_string = old_string[startloc:endloc]

如果只想要获取word变量中的第二个单词,且这个单词在变量中的起止下标分别为8和16,可以使用以下代码:

word[8:16]
'World!'

如果只想获取word变量中的第一个单词,则可以使用以下代码:

word[:7]
'Bonjour'

上例中,冒号之前的部分是空白,默认起始下标从0开始计数。

2.3 总结

根据本章所介绍的功能和策略,文本分析的准备工作终于完成了。要注意的是,在进行大规模文本分析时,经常会由于微小的输入错误,导致模型产出一个完全无意义的结果(请复习1.3节)。

下面给出一些关于文本操作的参考文献。

  • Printing and Manipulating Text:介绍文本的基本操作和打印,建议对以不同的方式显示文本感兴趣的读者阅读。
  • Manipulating Strings:介绍基本字符串函数,包含习题,有利于读者对字符串操作的进一步实践。
  • Manipulating Strings in Python:内容类似于前面两个文献,包含一个关于转义序列的章节。
  • Text Processing in Python:与前面的文献不同,这是一本书,涵盖了Python中文本和字符串操作的基本原理,还包括本书未涵盖的一些主题(如正则表达式)。
  • An Introduction to Text Analysis in Python:如果想对Python和文本分析之间的关系有一个宏观的了解,本书将提供更好的帮助。如果是初学者,在阅读之前需要补充更多的基础知识。

理解Python语言中的字符串行为,能够帮助你快速地掌握文本分析的基本操作,贯穿本书出现多次的这些基本技巧是灵活运用Python语言的基础。


[1] 反之亦然,如果要在字符串内部使用双引号,则使用单引号限定该字符串,建议统一使用双引号的转义符,避免形式上的不统一。——译者注

[2] Python 2中的print函数可以不用括号,Python 3中则必须使用括号。——译者注

[3] 空格除了\s,还包括\n、\t、\v、\f和\r。——译者注

本文摘自《自然语言处理与计算语言学》

Python文本分析技巧_NLP

Python开源社区资深供稿人撰写

计算语言学领域为数不多的作品之一

一本侧重于技术细节实现的文本分析实用指南,提供源码下载

使用Python和开源工具可以非常方便地进行现代文本分析,因此,在这个文本数据时代有必要掌握现代文本分析的方法。

本书介绍了如何使用自然语言处理和计算语言学算法对所拥有的数据进行推理并获得洞察力。这些算法以统计机器学习和人工智能技术为基础。现在,使用了这些算法的工具唾手可得,并可在Python、Gensim和spaCy等工具中使用。

本书从数据清理开始介绍,然后介绍了计算语言学的相关概念。在掌握了这些内容之后,接下来就可以使用真实的语言和文本,并借助Python来探索统计NLP和深度学习的更复杂领域。你将学到如何使用合适的工具来标注、解析和建模文本,并掌握相应框架工具的使用知识,还将知道何时选为主题模型选择Gensim这样的工具,以及何时使用Keras进行深度学习。

本书很好地平衡了理论与实战案例之间的关系,因此你可以在掌握理论知识的同时,执运行自己的自然语言处理项目。你将发现Python这一自然语言处理工具所具有的丰富的生态系统,并将进入现代文本分析的有趣世界。

本书内容:

文本分析为什么在当今时代如此重要;

理解NLP术语并了解各种Python工具与数据集;

如何预处理以及清理文本数据;

将文本数据转换为矢量空间表示;

使用spaCy处理文本; 针对计算语言学训练自己的NLP模型;

借助于Gensim和scikit-learn,针对文本使用统计学习和主题建模算法;

借助于Keras,使用各种深度学习技术进行文本分析。