【问题标题】:Creating tokens from list of sentences is returning characters instead of words从句子列表创建标记是返回字符而不是单词
【发布时间】:2016-07-07 07:07:48
【问题描述】:
from nltk.tokenize import sent_tokenize

text = open(path).read().lower().decode("utf8")
sent_tokenize_list = sent_tokenize(text)

tokens = [w for w in itertools.chain(*[sent for sent in sent_tokenize_list])]

最后一行“tokens”返回字符而不是单词。

为什么会这样?如何让它返回单词?特别是考虑根据句子列表来做。

【问题讨论】:

  • 先解码,后小写。否则你会得到非 ascii 字符的错误行为。

标签: python text nlp nltk tokenize


【解决方案1】:

因为sent_tokenize 返回一个字符串列表,而itertools.chain 将可迭代对象链接到一个可迭代对象,每次返回一个项,直到它们用完为止。实际上,您已将句子重新组合为单个字符串并在列表理解中对其进行迭代。

要从句子列表中创建单个单词列表,您可以例如拆分和展平:

tokens = [word for sent in sent_tokenize_list for word in sent.split()]

这不处理标点符号,但您最初的尝试也不会。您的原件也适用于拆分:

tokens = [w for w in itertools.chain(*(sent.split()
                                       for sent in sent_tokenize_list))]

请注意,您可以使用生成器表达式而不是列表推导式作为解包的参数。更好的是,使用chain.from_iterable

tokens = [w for w in itertools.chain.from_iterable(
    sent.split() for sent in sent_tokenize_list)]

对于标点处理使用nltk.tokenize.word_tokenize 而不是str.split。它会将单词和标点符号作为单独的项目返回,例如将I's 拆分为I's(这当然是一件好事,因为它们实际上是单独的单词,只是缩略了)。

【讨论】:

  • 使用nltk.word_tokenize(),而不是split()。标点和单词是不同的标记。
【解决方案2】:

首先,如果文件是'utf8'并且你使用的是Python2,最好在io.open()中使用encoding='utf8'参数:

import io

from nltk import word_tokenize, sent_tokenize

with io.open('file.txt', 'r', encoding='utf8') as fin:
    document = []
    for line in fin:
        tokens += [word_tokenize(sent) for sent in sent_tokenize(line)]

如果是 Python3,只需这样做:

from nltk import word_tokenize 

with open('file.txt', 'r') as fin:
    document = []
    for line in fin:
        tokens += [word_tokenize(sent) for sent in sent_tokenize(line)]

看看http://nedbatchelder.com/text/unipain.html


至于分词,如果我们假设每一行都包含某种可能由一个或多个句子组成的段落,我们希望首先初始化一个列表来存储整个文档:

document = []

然后我们遍历行并将行拆分成句子:

for line in fin:
    sentences = sent_tokenize(line)

然后我们将句子拆分为标记:

token = [word_tokenize(sent) for sent in sent_tokenize(line)]

由于我们要更新文档列表以存储标记化的句子,我们使用:

document = []
for line in fin:
    tokens += [word_tokenize(sent) for sent in sent_tokenize(line)]

不推荐!!!(但仍然可以一行):

alvas@ubi:~$ cat file.txt
this is a paragph. with many sentences.
yes, hahaah.. wahahha... 
alvas@ubi:~$ python
Python 2.7.11+ (default, Apr 17 2016, 14:00:29) 
[GCC 5.3.1 20160413] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import io
>>> from itertools import chain
>>> from nltk import sent_tokenize, word_tokenize
>>> list(chain(*[[word_tokenize(sent) for sent in sent_tokenize(line)] for line in io.open('file.txt', 'r', encoding='utf8')]))
[[u'this', u'is', u'a', u'paragph', u'.'], [u'with', u'many', u'sentences', u'.'], [u'yes', u',', u'hahaah..', u'wahahha', u'...']]

【讨论】:

    【解决方案3】:

    您是否应该使用word_tokenize 而不是sent_tokenize

    from nltk.tokenize import word_tokenize
    
    text = open(path).read().lower().decode("utf8")
    tokens = word_tokenize(text)
    

    http://www.nltk.org/api/nltk.tokenize.html#nltk.tokenize.word_tokenize

    【讨论】:

    • 如果你想要的只是一个不考虑句子边界的标记的平面列表,这是最好的方法。
    猜你喜欢
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多