繁体   English   中英

如何根据第一列的内容拆分一个巨大的 csv 文件?

[英]How to split a huge csv file based on content of first column?

  • 我有一个 250MB+ 巨大的 csv 文件要上传
  • 文件格式为group_id, application_id, reading和数据可能看起来像
1, a1, 0.1 1, a1, 0.2 1, a1, 0.4 1, a1, 0.3 1, a1, 0.0 1, a1, 0.9 2, b1, 0.1 2, b1, 0.2 2, b1, 0.4 2, b1, 0.3 2, b1, 0.0 2, b1, 0.9..... n, x, 0.3(lets say)
  • 我想根据group_id划分文件,所以 output 应该是 n 个文件,其中n=group_id

Output

 File 1 1, a1, 0.1 1, a1, 0.2 1, a1, 0.4 1, a1, 0.3 1, a1, 0.0 1, a1, 0.9

File2 2, b1, 0.1 2, b1, 0.2 2, b1, 0.4 2, b1, 0.3 2, b1, 0.0 2, b1, 0.9.....

File nn, x, 0.3(lets say)

我怎样才能有效地做到这一点?

awk有能力:

 awk -F "," '{print $0 >> ("FILE" $1)}' HUGE.csv

如果文件已经按group_id排序,您可以执行以下操作:

import csv
from itertools import groupby

for key, rows in groupby(csv.reader(open("foo.csv")),
                         lambda row: row[0]):
    with open("%s.txt" % key, "w") as output:
        for row in rows:
            output.write(",".join(row) + "\n")

Sed单线:

sed -e '/^1,/wFile1' -e '/^2,/wFile2' -e '/^3,/wFile3' ... OriginalFile 

唯一的缺点是你需要输入n -e语句(由省略号表示,不应出现在最终版本中)。 所以这个单线可能是一个很长的路线。

但是,好处是它只会传递一个文件,不会进行排序,也不需要python。 此外,它是一个一个惊人的班轮!

如果行按group_id排序,那么itertools.groupby在这里很有用。 因为它是一个迭代器,所以你不必将整个文件加载到内存中; 你仍然可以逐行编写每个文件。 使用csv加载文件(如果您还不知道它)。

如果它们按组ID排序,则可以使用csv模块迭代文件中的行并输出它。 您可以在此处找到有关该模块的信息

怎么样:

  • 一次读取一行输入文件
  • split()每行打开,得到group_id
  • 对于您找到的每个新group_id,打开一个输出文件
    • 在找到它们时将每个groupid添加到一个set / dict中,这样你就可以跟踪
  • 将该行写入适当的文件
  • 完成!

这里有一些食物虽然适合你:

import csv
from collections import namedtuple

csvfile = namedtuple('scvfile',('file','writer'))

class CSVFileCollections(object):

    def __init__(self,prefix,postfix):
        self.prefix = prefix
        self.files = {}

    def __getitem__(self,item):
        if item not in self.files:
            file = open(self.prefix+str(item)+self.postfix,'wb')
            writer = csv.writer(file,delimiter = ',', quotechar = "'",quoting=csv.QUOTE_MINIMAL)
            self.files[item] = csvfile(file,writer) 
        return self.files[item].writer

    def __enter__(self): pass

    def __exit__(self, exc_type, exc_value, traceback):
        for csvfile in self.files.values() : csvfile.file.close()


with open('huge.csv') as readFile, CSVFileCollections('output','.csv') as output:
    reader = csv.reader(readFile, delimiter=",", quotechar="'")
    for row in reader:
        writer = output[row[0]]
        writer.writerow(row)

这是一个适用于已排序或未排序 ID 的解决方案。 未排序版本的唯一开销是多次打开目标(组 ID)CSV:

import csv

reader = csv.reader(open("test.csv", newline=""))

prev_id = None
out_file = None
writer = None

for row in reader:
    this_id = row[0]

    if this_id != prev_id:
        if out_file is not None:
            out_file.close()

        fname = f"file_{this_id}.csv"
        out_file = open(fname, "a", newline="")
        writer = csv.writer(out_file)
        prev_id = this_id

    writer.writerow(row)

这是测试输入,但现在 1 和 2 交错:

1, a1, 0.1
2, b1, 0.1
1, a1, 0.2
2, b1, 0.2
1, a1, 0.4
2, b1, 0.4
1, a1, 0.3
2, b1, 0.3
1, a1, 0.0
2, b1, 0.0
1, a1, 0.9
2, b1, 0.9

当我运行它时,我看到:

./main.py
opening file_1.csv for appending...
opening file_2.csv for appending...
opening file_1.csv for appending...
opening file_2.csv for appending...
opening file_1.csv for appending...
opening file_2.csv for appending...
opening file_1.csv for appending...
opening file_2.csv for appending...
opening file_1.csv for appending...
opening file_2.csv for appending...
opening file_1.csv for appending...
opening file_2.csv for appending...

我的 output 文件如下所示:

1, a1, 0.1
1, a1, 0.2
1, a1, 0.4
1, a1, 0.3
1, a1, 0.0
1, a1, 0.9

2, b1, 0.1
2, b1, 0.2
2, b1, 0.4
2, b1, 0.3
2, b1, 0.0
2, b1, 0.9

我还创建了一个假的大文件,289MB,有 100 个 ID 组(每个 ID 250_000 行),我的解决方案运行了大约 12 秒。 作为比较,使用groupby()的公认答案在大 CSV 上运行大约 10 秒; 高评级 awk 脚本运行大约一分钟。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM