簡體   English   中英

在每個類別的文件中對文本文件的行進行分組-最有效的方法

[英]Group lines of a text file in files per category - Most efficient way

我有一個巨大的文本文件(足以填滿我的計算機的內存),需要將其分成較小的文件。

該文件包含CSV行,其中第一行是ID:

ID1, val11, val12, val13
ID2, val21, val22, val23
ID1, val31, val32, val33
ID3, val41, val42, val43

我想從源文件中讀取每一行或幾行,並創建將每個ID的行分組的較小文件:

File1:
    val11, val12, val13
    val31, val32, val33
File2:
    val21, val22, val23
File3:
    val41, val42, val43

到目前為止,我可以使用以下代碼來完成此操作,但是這花了很多時間(我沒有10天這樣做)。

def groupIDs(fileName,folder):
    loadedFile = open(fileName, 'r')
    firstLine = loadedFile.readline() #skip titles

    folder += "/"

    count = 0;

    for line in loadedFile:

        elems = line.split(',')
        id = elems[0]

        rest = ""
        for elem in elems[1:]:
            rest+=elem + ","

        with open(folder+id,'a') as f:
            f.write(rest[:-1])

        #printing progress
        count+=1
        if count % 50000 == 0:
            print(count)

    loadedFile.close()

如資源監視器所示,瓶頸似乎是高清性能(CPU使用率低於20%,幾乎沒有占用內存)

我該如何改善它以獲得最佳性能?

您可以將其保留在柱塞中,並且每隔幾千行才沖洗一次,也可以將柱塞填充到您可以選擇的程度。

您還應該將上下文管理器與文件一起使用,並使用std lib中的os.pathpathlib模塊,而不是手動使用字符串作為路徑。

這是一個解決方案,每10,000行保存一次,根據您的問題進行調整:

import os
from glob import iglob
from collections import defaultdict


def split_files_into_categories(inputfiles, outputdir):
    count = 0
    categories = defaultdict(bytearray)

    for inputfile in inputfiles:
        with open(inputfile, 'rb')  as f:
            next(f) # skip first line

            for line in f:

                if count % 10000 == 0:
                    save_results(categories, outputdir)
                    categories.clear()

                category, _, rest = line.partition(b',')

                categories[category] += rest
                count += 1

    save_results(categories, outputdir)


def save_results(categories, outputdir):
    for category, data in categories.items():
        with open(os.path.join(outputdir, category.decode() + '.csv'), 'ab') as f:
            f.write(data)


if __name__ == '__main__':
    # run on all csvs in the data folder
    split_files_into_categories(iglob('data/*.csv'), 'by_category')

一些解釋:

  • 我以二進制模式打開文件並使用bytearray ,這可以防止復制數據。 在python中,字符串是不可變的,因此+=創建一個新字符串並重新分配它。

  • 第一次訪問defaultdict(bytearray)它將為每個新類別創建一個空的bytearray

  • 您可以將if count % 100000 == 0替換為檢查內存消耗,如下所示:

     import os import psutil process = psutil.Process(os.getpid()) 

    然后檢查

     # save results if process uses more than 1GB of ram if process.memory_info().rss > 1e9: 

暫無
暫無

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

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