根据条件从超大 (48GB) CSV 文件中提取行

Posted

技术标签:

【中文标题】根据条件从超大 (48GB) CSV 文件中提取行【英文标题】:Extracting rows from an extremely large (48GB) CSV file based on condition 【发布时间】:2016-12-06 13:46:00 【问题描述】:

我有一个非常大的 CSV 文件,其中包含超过 5 亿行。

但是我只需要根据特定条件从中提取几千行。 我目前正在使用:

with open('/home/Documents/1681.csv', 'rb') as f:
    reader = csv.DictReader(f)
    rows = [row for row in reader if row['flag_central'] == 1]

这里的条件是如果flag_central == 1,我需要该行。

但是,由于文件非常大,我无法执行上述代码。我相信这是因为我使用的for 循环导致了这个问题。

我是否可以根据上述条件从 CSV 文件中提取这些特定行?

【问题讨论】:

使用 grep 并过滤您想要的内容并将其通过管道传输到 python 并以 csv 格式读取。 @YOU:你能举个例子作为答案吗? 上面的代码到底发生了什么?吃掉内存?无限执行?因错误而崩溃? @deceze:比方说无限执行!!已经运行了1个多小时了!! 它将花费 500'000'000 /(每行时间),因此要低于 1 小时,您必须处理 500'000'000 / 3600 = 138'888 行/秒。不确定这是否可以通过任何方法以串行方式轻松实现。 【参考方案1】:

如果这是一个重复的过程和/或您有更复杂的条件要处理,这里有一种快速、低内存的 Python 方法,可以让您快速完成:

#!/usr/bin/env python
# put this in parsecsv.py, then chmod +x parsecsv.py
import sys
output = lambda l: sys.stdout.write(l)
for line in sys.stdin:
    fields = line.split(',')
    # add your conditions below
    # call output(line) to output
    if fields[0] == "foo":
         output(line)

这旨在用作命令行中的管道过滤器:

$ cat file | parsecsv > extract.csv

其实我写了更多generic & maintainable template,你可能会觉得有用。

【讨论】:

【参考方案2】:

如果这是一次性任务,我建议先使用 unix 命令,然后处理提取:

cat file | awk -F , ' if ($5 == "1") print $0 ' > extract.csv

其中 -F 指定列分隔符,5 是列号。首先通过

解决这个问题
cat file | head -n 1 | tr ',' '\n' | nl | grep flag_central
=>
5   flag_central
^ this is the field number ($5)

这样您就不会产生先将 csv 文件转换为 python 对象的成本。取决于您的用例 YMMV。

【讨论】:

如何对多个命令执行上述操作?即如果我想添加另一个条件 if 语句的一般形式是if (expression) action,其中expression 是产生真(非零)或假(零)的任何操作组合。因此,您可以使用布尔运算符组合多个条件,例如if ($5 =="1" && $1 == "foo") ...。如需更复杂的示例,请查看here。请注意条件逻辑是否超出了几个术语,例如嵌套条件甚至解析,我建议将其作为 Python 中的第二步,而不是编写复杂的 awk 脚本。【参考方案3】:

您可以使用Pandas。我唯一需要注意的是,对于这么大的文件,您需要分批导入文件。

import pandas as pd
tp = pd.read_csv('/home/Documents/1681.csv', iterator=True, chunksize=10000)
df = pd.concat(tp, ignore_index=True)

然后您可以从那里提取您感兴趣的行:

rows = df[df['flag-central'] == 1]

如果您想将此返回到 csv 文件,则可以使用 to_csv:

rows.to_csv('filename.csv')

【讨论】:

【参考方案4】:

您可以使用pandas

import pandas as pd

chunk_list=[]
for chunk in pd.read_csv('/home/Documents/1681.csv', chunksize=10000):
    chunk_list.append(chunk[chunk['flag_central'] == 1]`

final_df = pd.concat(chunk_list)

基本上,这将一次读取 10000 行并过滤不符合条件的行,这些行被附加到一个列表中,当完成时,这些块被连接到一个最终的数据帧中

【讨论】:

我得到了错误,TypeError: parser_f() got an unexpected keyword argument 'mode' OK mode 无关紧要,你可以删除它 final_df,会是一个什么样的数组? 它将是熊猫dataframe

以上是关于根据条件从超大 (48GB) CSV 文件中提取行的主要内容,如果未能解决你的问题,请参考以下文章

如何从 300GB 文件中提取一列到另一个文件

4GB以上超大文件上传和断点续传服务器的源码

Snapde一个全新的CSV超大文件编辑软件

在 R 中处理大型 csv 文件时避免挂断

PHP快速按行读取CSV大文件的封装类分享(也适用于其它超大文本文件)

百万行超大csv如何快速导入mysql