我有一个我还没能解决的问题。我有4个.txt文件,每个在30-70 30之间。每个文件包含如下n元语法条目:
blabla1/blabla2/blabla3
word1/word2/word3
...我要做的是计算每一项出现的次数,并将这些数据保存到一个新文件中,例如:
blabla1/blabla2/blabla3 : 1
word1/word2/word3 : 3
...到目前为止,我的尝试只是保存字典中的所有条目并对它们进行计数,即
entry_count_dict = defaultdict(int)
with open(file) as f:
for line in f:
entry_count_dict[line] += 1然而,使用这种方法我遇到了内存错误(我有8 8GB的RAM可用)。数据遵循zipfian分布,例如,大多数项目只出现一次或两次。条目总数尚不清楚,但粗略估计大约有15,000,000个条目。
除此之外,我还尝试了h5py,其中所有条目都保存为包含数组[1]的h5py数据集,然后对其进行更新,例如:
import h5py
import numpy as np
entry_count_dict = h5py.File(filename)
with open(file) as f:
for line in f:
if line in entry_count_dict:
entry_count_file[line][0] += 1
else:
entry_count_file.create_dataset(line,
data=np.array([1]),
compression="lzf")然而,这种方法很慢。写入速度变得越来越慢。因此,除非可以提高写入速度,否则这种方法是不可信的。此外,分块处理数据和打开/关闭每个块的h5py文件在处理速度上没有显示出任何显著的差异。
我一直在考虑将以特定字母开头的条目保存在单独的文件中,即所有以a开头的条目都保存在a.txt中,依此类推(使用defaultdic(int)应该可以做到这一点)。然而,要做到这一点,文件必须为每个字母迭代一次,考虑到文件大小(max =69 is ),这是不可信的。也许在迭代文件时,可以打开一个pickle并将条目保存在字典中,然后关闭该pickle。但是,由于打开、加载和关闭pickle文件所需的时间较长,因此为每个项目执行此操作会大大减慢进程。
解决这个问题的一种方法是在一次遍历中对所有条目进行排序,然后迭代排序后的文件并按字母顺序对条目进行计数。但是,即使使用linux命令对文件进行排序也会非常慢:
sort file.txt > sorted_file.txt
而且,我真的不知道如何使用python来解决这个问题,因为将整个文件加载到内存中进行排序会导致内存错误。我对不同的排序算法有一些肤浅的了解,但是它们似乎都需要将要排序的整个对象加载到内存中。
任何关于如何接近这一点的技巧都将非常感谢。
发布于 2018-07-02 18:15:15
有许多算法可以执行这种类型的操作。它们都属于External Sorting的一般标题。
您在其中所做的“将以某些字母开头的条目保存在单独的文件中”实际上被称为存储桶排序,从理论上讲,它应该更快。在切片数据集上尝试它。
或者,试试Dask,这是一个由DARPA + Anaconda支持的分布式计算库,它的接口与numpy、pandas相似,其工作方式类似于Apache-Spark。(也可以在单机上运行)顺便说一句,它可以扩展
我建议尝试dask.array,它将大数组分成许多小数组,并使用阻塞算法实现numpy ndarray接口,以便在计算这些大于内存的数据时利用所有内核。
发布于 2018-07-04 11:45:15
我一直在考虑将以某些字母开头的条目保存在单独的文件中,即所有以a开头的条目都保存在a.txt中,依此类推(这应该可以使用defaultdic(int))。然而,要做到这一点,文件必须为每个字母迭代一次,考虑到文件大小(max =69 is ),这是不可信的。
有了这样的思路,你就快到了。您要做的是根据前缀拆分文件-您不必为每个字母迭代一次。这在awk中是微不足道的。假设您的输入文件位于一个名为input的目录中
mkdir output
awk '/./ {print $0 > ( "output/" substr($0,0,1))}` input/*这会将每一行附加到以该行的第一个字符命名的文件中(注意,如果您的行可以以空格开头,这会很奇怪;因为这些是ngram,我假设这是不相关的)。您也可以在Python中做到这一点,但是管理文件的打开和关闭有点单调乏味。
因为文件已经被拆分了,所以它们现在应该更小了。你可以对它们进行排序,但真的没有必要--你可以逐个读取这些文件,并使用如下代码获得计数:
from collections import Counter
ngrams = Counter()
for line in open(filename):
ngrams[line.strip()] += 1
for key, val in ngrams.items():
print(key, val, sep='\t')如果文件仍然太大,您可以增加用于存储行的前缀的长度,直到文件足够小。
https://stackoverflow.com/questions/51132716
复制相似问题