Эффективность использования памяти .txt при добавлении Python - PullRequest
0 голосов
/ 12 сентября 2018

Я создал список каталогов TXT-файлов в Python, а затем написал функцию для их объединения.

def combine_directory_txt(FilePaths):
    """
    This function will combine all files in a directory by importing each,
    and appending them to a single output. It only works for csv's (.txt) with
    a delimeter of "|"
    """
    Output = pd.DataFrame() # Dataframe which will store the final table
    Increment = 0
    Total = len(FilePaths)

    # Import each file and join them together
    for file in FilePaths:
        Increment += 1
        Import = pd.read_csv(file, sep = '|', error_bad_lines = False,
                                   low_memory = False, encoding='mbcs' )
        Output = Output.append(Import)
        print (Increment, " of ", Total, " joined")
        del Import
    return Output

Это прекрасно работает, за исключением того, что мой компьютер борется с MemoryErrors.Есть ли более эффективный способ сделать это?Я понимаю, что использовал «low_memory = false», этот процесс должен повторяться ежемесячно, поэтому я не могу знать, как будут выглядеть столбцы, и мой код очень рано не выполнялся из-за всех предупреждений dtype.Это правильный подход?Должен ли я написать код, чтобы выяснить, что такое dtypes, затем назначить их для сокращения памяти?

Ответы [ 2 ]

0 голосов
/ 13 сентября 2018

Примечание: не тестировалось. Используйте на свой страх и риск.

Основная идея состоит в том, чтобы прочитать данные кусками (количество строк) и добавить их в файл, передав аргумент chunksize в read_csv. Этот аргумент может быть необязательно передан в to_csv для той же цели. Хотя я не профилировал этот код, в целом чтение в чанах и запись в чанках может улучшить производительность ввода-вывода, особенно для больших файлов.

def combine_directory_txt(file_paths, output_filename, chunksize):
    """Merge collection of files.
    :param file_paths: Collection of paths of files to merge.
    :param output_filename: Path of output file (i.e., merged file).
    :param chunksize: Number of lines to read in at one time.    
    """
    with open(output_filename, "wb") as outfile:
        chunk_transfer(file_paths[0], outfile, chunksize, append=False)
        for path in file_paths[1:]:
            chunk_transfer(path, outfile, chunksize, append=True)

def chunck_transfer(path, outfile, chunksize, append, include_index=False):
    """Transfer file at path to outfile in chunks.
    :param path: Path of file to transfer.
    :param outfile: File handler for output file.
    :param chunksize: Number of lines to read at a time.
    :param append: Whether to append to file or write new file.
    :param include_index: Whether to include index of dataframe.
    """

    with open(path, "rb") as infile:
        df = pd.read_csv(infile, 
                         sep='|', 
                         error_bad_lines=False,
#                          low_memory=False,
                         encoding='mbcs',
                         chunksize=chunksize)

        if append:
            include_header = False
            mode = 'a'
        else:
            include_header = True
            mode = 'w'

        # Possible to pass chunksize as an argument to to_csv
        df.to_csv(outfile, mode=mode, header=include_header, index=include_index)
0 голосов
/ 12 сентября 2018

Ваш подход заключается в чтении каждого CSV-файла в память, объединении их всех и возвращении результирующего кадра данных.Вместо этого вам следует обрабатывать файлы CSV по одному, каждый раз записывая результаты в файл output.csv.

Сценарий ниже показывает, как это можно сделать.Это добавляет имя файла, чтобы использовать для вывода.Предполагается, что все файлы в цикле имеют одинаковый формат и каждый из них имеет одинаковый заголовок.Заголовок записывается один раз в выходной файл CSV, а затем пропускается во время чтения.

import csv

def combine_directory_txt(file_paths, output_filename):
    # Get the header from the first CSV file passed
    with open(file_paths[0], "rb") as f_input:
        header = next(csv.reader(f_input, delimiter="|"))

    with open(output_filename, "wb") as f_output:
        csv_output = csv.writer(f_output, delimiter="|")
        csv_output.writerow(header)     # Write the header once

        for file_name in file_paths:
            with open(file_name, "rb") as f_input:
                csv_input = csv.reader(f_input, delimiter="|")
                next(csv_input)     # Skip header
                csv_output.writerows(csv_input)

combine_directory_txt(["mbcs_1.txt", "mbcs_2.txt"], "output.csv")

При использовании этого подхода требования к памяти будут значительно снижены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...