【问题标题】:Programmatically merge rows of a huge file for NLP以编程方式合并 NLP 大文件的行
【发布时间】:2017-11-26 10:09:43
【问题描述】:

我需要使用谷歌 ngram 语料库 (http://storage.googleapis.com/books/ngrams/books/datasetsv2.html),其中有 n-gram 的频率数据逐年出现在一本书中。

文件格式:以下每个文件都是压缩的制表符分隔数据,行格式如下:

ngram TAB year TAB match_count TAB volume_count NEWLINE.

我写了一个代码来检索我的输入 ngram 的频率

代码写成:

file = 'D:\Chrome Downloads\googlebooks-eng-all-4gram-20120701-aj\googlebooks-eng-all-4gram-20120701-aj'

z = []
counter = 0
freq = 0
with open(file, 'rt', encoding='UTF8') as input:

    for line in input:
        if(counter == 150):
            break
        if('Ajax and Achilles ?' == (line.strip().split('\t')[0])):
        #else:
           print(line.strip().split('\t'))
           freq += int((line.strip().split('\t')[2]))

print('Frequency :', freq)

这很好用只是因为Ajax and Achilles 出现在语料库的顶部(计数器停止它)。当我尝试搜索稍后出现的 ngram 时,它需要很长时间。

使用这个语料库来获取 n-gram 的频率的问题是我必须查看整个语料库。

所以,我正在考虑合并行忽略年份并总结频率。

这是一个有效的想法吗?如果是这样,我该如何以编程方式执行此操作?

不是,有什么更好的方法?

【问题讨论】:

    标签: python nlp


    【解决方案1】:

    您确实多次拆分行,当然,为您要检查的每个 ngram 读取整个文件并不理想。为什么不将每个 ngram 的总频率写到另一个文件中。猜测您的这个 google 文件非常庞大,您可能无法在写出之前轻松地将计数收集到单个数据结构中。依靠已经被 ngram 排序的文件,您可以编写新文件而无需一次加载整个语料库:

    from csv import reader, writer
    from itertools import groupby
    from operator import itemgetter
    
    get_ngram = itemgetter(0)
    
    with open(file, 'rt', encoding='UTF8') as input, open('freq.txt', 'w', encoding='UTF8') as output:
        r = reader(input, delimiter='\t')
        w = writer(output, delimiter='\t')
        for ngram, rows in groupby(r, key=get_ngram):
        # for i, (ngram, rows) in enumerate(groupby(r, key=get_ngram)):
            # the i and enumerate is just for the loop not being too silent ...
            freq = sum(int(row[2]) for row in rows)
            w.writerow((ngram, freq))
            # if not i % 10000:   # ... and give you some idea what's happening
                # print('Processing ngram {}')
    

    csv 类只是接管了 csv 解析和写入部分。 csv.reader 是一个对字符串列表的惰性迭代器。 groupby 使用带有适当函数的 key 参数按第一个标记对 csv 读取器生成的行进行分组。这是使用itemgetter 完成的,只是为了避免一些笨拙的key=lambda x: x[0]groupby 产生成对的键值和具有所述值的分组迭代器的元素。然后它将这些分组行的频率相加,并使用csv.writer 仅将 ngram 和频率写入文件。

    【讨论】:

    • 首先感谢您的回答。我收到一个错误:w.writerow((ngram, freq)) UnsupportedOperation: not writable。我错过了什么吗?
    • 您是否在输出文件中使用了'w' 标志?
    • 是的,我只是直接复制了你的答案
    • 糟糕,我的错误。当然,您必须使用w writer 的输出文件。我编辑了我的答案。
    • 哇。我不敢相信解析这么大的语料库只需要一秒钟。太感谢了!你能解释一下代码是如何工作的吗?我不明白它如何试图消除“年份”而只解析 ngram 的“频率”。我也想知道是什么让它这么快。再次感谢!
    猜你喜欢
    • 2020-03-05
    • 2021-01-26
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    • 2011-01-17
    相关资源
    最近更新 更多