簡體   English   中英

總結大量數據

[英]Summarizing huge amounts of data

我有一個問題,我無法解決。 我有4個.txt文件,每個文件在30-70GB之間。 每個文件包含n-gram條目,如下所示:

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

但是,使用這種方法我遇到內存錯誤(我有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 = 69GB)是不可信的。 也許在迭代文件時,可以打開一個pickle並將條目保存在dict中,然后關閉pickle。 但是,由於打開,加載和關閉pickle文件所需的時間,為每個項目執行此操作會使進程大大減慢。

解決此問題的一種方法是在一次傳遞期間對所有條目進行排序,然后迭代排序的文件並按字母順序計算條目。 但是,即使使用linux命令對文件進行排序也非常慢:

sort file.txt > sorted_file.txt

並且,我真的不知道如何使用python解決這個問題,因為將整個文件加載到內存中進行排序會導致內存錯誤。 我對不同的排序算法有一些膚淺的了解,但是它們似乎都要求整個待排序的對象需要加載到內存中。

任何有關如何處理此問題的提示都將非常感激。

有許多算法用於執行這種類型的操作。 它們都屬於外部排序的總標題。

你在那里用“保存以單獨文件中的某些字母開頭的條目”實際上稱為桶排序,理論上應該更快。 嘗試使用切片數據集。

或者,嘗試使用DARPA + Anaconda支持的分布式計算庫Dask ,其界面與numpy,pandas相似,並且像Apache-Spark一樣工作。 (也適用於單機)btw它可以擴展

我建議嘗試使用dask.array ,它將大型數組切割成許多小數組,並使用阻塞算法實現numpy ndarray接口,以便在計算這些大於內存的數據時利用所有內核。

我一直在考慮保存以單獨文件中的某些字母開頭的條目,即以a開頭的所有條目都保存在a.txt中,依此類推(這應該可以使用defaultdic(int))。 但是,為了做到這一點,文件必須為每個字母迭代一次,這對於文件大小(max = 69GB)是不可信的。

你幾乎就是這種思路。 你想要做的是根據前綴分割文件 - 你不必為每個字母迭代一次。 這在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')

如果文件仍然太大,您可以增加用於存儲行的前綴的長度,直到文件足夠小。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM