是什么让这个组合一些平面文件的代码运行得更快?

时间:2017-12-31 01:09:31

标签: python python-3.x optimization

我是Python的新手,还没有进入任何优化工作。我试图拿出一堆本身已经非常大的文件并将它们组合成一个大文件,可能会接近50-100GB,这是我的猜测。无论如何,记忆力比我多。我得到了下面的代码,它适用于小文件。当我尝试在我的用例的实际文件上运行它时,它将完全锁定我的计算机。

我知道熊猫很快。我猜测数据帧存储在内存中。如果是这种情况,那么这可能是破坏这里的东西。是否存在任何类型或机制溢出到磁盘或可能写入现有文件而不是在写入磁盘之前尝试将整个事物保存在数据帧中?或者可能是我没有想到的其他选择?

import pandas as pd
import os

file_masks = ['fhv', 'green', 'yellow']


def combine_files(file_mask):

    csvfiles = []
    for path, directories, files in os.walk('TaxiDriveData/'):
        csvfiles.extend([os.path.join(path, fn) for fn in files if fn.startswith(file_mask)])

    df = pd.concat((pd.read_csv(fn) for fn in csvfiles))
    df.to_csv(os.path.join('TaxiDriveCombinedData', file_mask + '_trip_data.csv'), index=False)

for m in file_masks:
    combine_files(m)

2 个答案:

答案 0 :(得分:1)

这是一个非熊猫解决方案,不会将所有内容加载到内存中。我没有测试过,但它应该可以工作。

import os

file_masks = ['fhv', 'green', 'yellow']


def combine_files(file_mask):

    with open(os.path.join('TaxiDriveCombinedData', file_mask + '_trip_data.csv'),'w') as fout:
        csvfiles = []
        for path, directories, files in os.walk('TaxiDriveData/'):
            csvfiles.extend([os.path.join(path, fn) for fn in files if fn.startswith(file_mask)])

        for in_file in csvfiles:
            with open(in_file,'r') as fin:
                # f.next() # comment this out if you want to remove the headers
                for line in fin:
                    fout.write(line)


for m in file_masks:
    combine_files(m)

答案 1 :(得分:0)

你不需要Python来做到这一点。 Linux系统中有很多工具可以连接文件并进行优化或具有参数来非常有效地执行此操作:join,cat,dd ......

这不是最有效的选择,但是,例如:

cat input/*.csv > output/combined.csv

如果您需要高性能的Python版本,我建议您以块的形式读取和写入文件,而不是逐行读取文件。

您最大的问题是I / O,您可以通过读取和写入硬盘的更大信息块来优化它。如果您读取和写入硬盘和文件系统的最佳大小,您会发现差异。 例如,较新HDD的公共块大小为4096字节(4 KiB)。

您可以尝试以下内容:

NEW_LINE = '\n'

def read_in_chunks(f, chunksize=4096):
    while True:
        chunk = f.read(chunksize)
        if not chunk:
            break
        yield chunk

(...)

fout = open('output.csv', 'w') 

for fname in files:
    with open(fname) as fin:
        buffer = ''
        for chunk in read_in_chunks(fin):
           buffer += chunk
           lines, tmp_buffer = buffer.rsplit(NEW_LINE, 1) 
           lines += NEW_LINE  # rsplit removes the last new-line char. I re-add it
           fout.write(lines)
           buffer = tmp_buffer

fout.close()