【问题标题】:Randomly Select Sentences from Text File, Find Coresponding ID Number从文本文件中随机选择句子,找到对应的ID号
【发布时间】:2016-07-09 22:57:11
【问题描述】:

我正在帮助我的一位教授完成一个研究项目,该项目涉及从一组 20 个文本文件中随机抽取一千个句子。这是来自当代美国英语语料库的所有数据,如果有人熟悉使用它的话。在这些文本文件中,数据是这样排列的:

Blockquote ##4000348 我必须首先这样说:为了准备本次讲座,我阅读(或在某些情况下重读)Sidney Hook 的一些著作。我阅读它们只是为了给我一个正确的起点,让我为纪念 Sidney Hook 的演讲提供一个正确的起点。但相反,我发现自己被灌输了一组与不同环境、不同场合相关的想法。

##4000349 我想我最出名的是我的智慧和学识,但事实上,我这样的名声源于我是一位著名的保守派,也是耶鲁学院的院长。这就是我被任命的消息出现在《华尔街日报》和《国家评论》上的原因,这通常不会发生在耶鲁学院的院长身上,而且一旦发生也对他们没有多大帮助。

块引用>

因此,有数百个段落,每个段落都以“##”开头的六位数字开头。该数字对应于句子的来源。我需要从这些文件中提取随机句子,并获得六位数字来识别它们的来源。所以理想情况下,我会得到类似的东西:

Blockquote ##4000348 我阅读它们只是为了给我一个正确的起点,以纪念 Sidney Hook 的演讲

##4000349 我想我最出名的是我的智慧和学识,但事实上,我的名声来源于我是一位著名的保守派,也是耶鲁学院的院长。

我已经成功地从文件中获取了随机句子(在 * 的好心人的帮助下),但我不知道如何获取附加到它们的数字(例如,如果我从在段落的中间,我怎么能从段落的开头得到数字)。谁能帮我想办法做到这一点?这是我目前的代码,成功提取句子。

# -*- coding: utf-8 -*-

import re
from random import sample

sentences = []
for i in range(1990,2013):
    with open('w_acad_{}.txt'.format(i)) as f:
        sentences += re.findall(r".*?[\.\!\?]+", f.read())

selected = sample(sentences, 2000)
with open('out.txt', 'w') as f:
    f.write('\n'.join(selected))

【问题讨论】:

    标签: python regex random linguistics


    【解决方案1】:

    一般来说,为了避免一次将(可能很大的)文件加载到内存中,您可以使用a reservoir sampling algorithm——只需传递一个迭代器,该迭代器会产生标记(带有##-数字)句子:

    #!/usr/bin/env python
    import re
    import nltk  # $ pip install nltk
    
    def paragraphs(file):
        """Yield blank-line separated paragraphs labeled with ##-numbers."""
        lines = []
        for line in file:
            if line.strip():
                lines.append(line)
            elif lines:  # blank line, the end of a non-empty paragraph
                paragraph = ''.join(lines)
                numbers = re.findall(r'##([0-9]+)', paragraph)  # only ASCII-digits
                assert len(numbers) == 1  # only one ##-number per paragraph
                yield int(numbers[0]), paragraph
                del lines[:]
    
    def sentences(filenames):
        for filename in filenames:
            with open(filename) as file:
                for number, paragraph in paragraphs(file):
                    for sentence in nltk.sent_tokenize(paragraph):
                        yield number, sentence
    
    filenames = ('w_acad_%d.txt' % n for n in range(1990, 2013))
    print(reservoir_sample(sentences(filenames), 2000))
    

    reservoir_sample() is defined here.

    nltk.sent_tokenize() 可能是比r".*?[\.\!\?]+" 正则表达式更强大的解决方案。

    【讨论】:

    • 嘿,这个答案太棒了!很抱歉,我花了这么长时间才回复,我有点忙,没有在这个项目上工作。我使用了你的代码,包括你给我的reservoir_sample()定义,代码编译了,但打印出来的只是:'[]' 你知道这是为什么吗?
    • @K.Swan 代码期望的输入格式可能与实际不同。您应该修改 paragraphs() 函数以匹配文件的实际格式。如果你不能;创建一个最小的示例输入,描述假设(例如,段落之间有一个空行是否正确?每个段落只有一个##-number 是否正确?),如果您将其作为一个新问题发布有兴趣(在实践中,一个简单的基于正则表达式的解决方案,例如@pzelasko 答案就足够了)。
    【解决方案2】:

    也许您可以使用正则表达式提取每个段落及其源 ID,然后从段落中提取句子,类似于您目前的操作方式。这应该可以帮助您抓住段落:

    # with open... etc.
    for source_id, paragraph in re.findall(r"(##\d+)([^#]+)", f.read()):
        sentences += [(source_id, sentence) for sentence in re.findall(r".*?[\.\!\?]+", paragraph)]
    

    现在,sentences 应该是像 ('##123', 'A sentence.') 这样的元组列表,您可以像以前一样从中采样。

    【讨论】: