加快约 50GB CSV 文件的轻量级处理

Posted

技术标签:

【中文标题】加快约 50GB CSV 文件的轻量级处理【英文标题】:Speeding up the light processing of ~50GB CSV file 【发布时间】:2016-11-28 12:10:14 【问题描述】:

我有一个 ~50GB 的 csv 文件,我必须使用它

获取 CSV 列的几个子集 对 CSV 的每个列子集应用不同的格式字符串规范。 为每个具有自己的格式规范的子集输出一个新的 CSV。

我选择使用 Pandas,并有一种通用的方法来迭代一个方便的块大小(超过 50 万行)的块以生成一个 DataFrame,并将该块附加到每个输出 CSV。所以是这样的:

_chunk_size = 630100

column_mapping = 
    'first_output_specification' : ['Scen', 'MS', 'Time', 'CCF2', 'ESW10'],
    # ..... similar mappings for rest of output specifications

union_of_used_cols = ['Scen', 'MS', 'Time', 'CCF1', 'CCF2', 'VS', 'ESW 0.00397', 'ESW0.08',
                    'ESW0.25', 'ESW1', 'ESW 2', 'ESW3', 'ESW 5', 'ESW7', 'ESW 10', 'ESW12',
                    'ESW 15', 'ESW18', 'ESW 20', 'ESW22', 'ESW 25', 'ESW30', 'ESW 35', 
                    'ESW40']

chnk_iter = pd.read_csv('my_big_csv.csv', header=0, index_col=False,
                        iterator=True, na_filter=False, usecols=union_of_used_cols)

cnt = 0
while cnt < 100:
    chnk = chnk_iter.get_chunk(_chunk_size)
    chnk.to_csv('first_output_specification', float_format='%.8f',
                columns=column_mapping['first_output_specification'],
                mode='a',
                header=True,
                index=False)
    # ..... do the same thing for the rest of the output specifications

    cnt += 1

我的问题是这真的很慢。每个块需要大约一分钟来生成附加到 CSV 文件,因此我正在寻找近 2 个小时来完成任务。

我尝试通过在读取 CSV 时仅使用列子集的并集以及设置 na_filter=False 来进行一些优化,但这仍然是不可接受的。

我想知道是否有更快的方法在 Python 中对 CSV 文件进行这种轻量级处理,或者通过优化或更正我的方法,或者可能只是有一个更好的工具适合这种工作Pandas... 对我(一个没有经验的 Pandas 用户)来说,这看起来和 Pandas 一样快,但我很可能弄错了。

【问题讨论】:

是否可以切换到数据库方法?这是一个大的 csv 文件! @Jylo 我真的希望是这样,但不是。 chunksize 是否包含您希望在每个块中拥有的行数? 有有趣信息的相关线程:softwarerecs.stackexchange.com/questions/7463/… @albert 看起来瓶颈肯定是用to_csv 写入csv:简单地将输入分块到数据帧中并且对它们不做任何事情非常快,。我现在找到了。所以我不确定 PowerShell 文件拆分是否会有所不同。 【参考方案1】:

我认为您不会从 Panda 的数据帧中获得任何优势,所以它只是增加了开销。相反,您可以使用 python 自己的CSV module,它易于使用并且在 C 中进行了很好的优化。

考虑将更大的块读入内存(一次可能 10MB),然后在进入下一个块之前写出每个重新格式化的列子集。这样,输入文件只会被读取和解析一次。

您可以尝试的另一种方法是使用 Unix cut 命令预处理数据以仅提取相关列(这样 Python 就不必为未使用列中的数据创建对象和分配内存):@ 987654324@

最后,尝试在PyPy 下运行代码,以便脚本的 CPU 绑定部分通过其跟踪 JIT 得到优化。

【讨论】:

【参考方案2】:

我会尝试使用 python csv 模块和生成器。

我发现生成器在解析大量服务器日志等方面比其他方法快得多。

import csv

def reader(csv_filename):
    with open(csv_filename, 'r') as f:
        csvreader = csv.reader(f, delimiter=',', quotechar="'")
        for line in csvreader:
            yield line  # line is a tuple

def formatter(lines):
    for line in lines:
        # format line according to specs
        yield formatted_line

def write(lines, csv_filename):
    with open(csv_filename, 'w') as f:
        writer = csv.writer(f)
        for line in lines:
            writer.writerow(line)

 lines = reader('myfile.in.csv')
 formatted_lines = formatter(lines)
 write(formatted_lines, 'myfile.out.csv')

这只是为了读取将单个输入 csv 转换为单个输出 csv,但您可以编写格式化程序和编写器来输出多个文件。

(我现在看到这个问题已经有一个月了 - 不确定你是否已经解决了你的问题 - 如果没有,如果你想要更详细的解释/示例,请告诉我。)

【讨论】:

【参考方案3】:

CPU 比磁盘访问快。一个技巧是压缩你的文件并从中读取。

import gzip

with gzip.open('input.gz','r') as fin:
    for line in fin:
        print('got line', line)

【讨论】:

以上是关于加快约 50GB CSV 文件的轻量级处理的主要内容,如果未能解决你的问题,请参考以下文章

如何操作一个巨大的 csv 文件(> 12GB)?

使用 Spark 和 Scala 清理大小约为 40GB 的 CSV/Dataframe

Android平台实现mp4文件实时推送RTMP|轻量级RTSP服务|GB28181平台

计算两个 csv 文件之间差异的更快方法

将 csv 导入 SQL Server 表

如何使用 fsspec+adlfs 加快从 adl:// 读取 CSV/Parquet 文件的速度?