使用Python将.csv文件分成多个部分

7
我有一个超过300GB的大型.csv文件。我想将它划分为每个100,000,000行的小文件(每行大约55-60字节)。
我编写了以下代码:
import pandas as pd
df = pd.read_csv('/path/to/really/big.csv',header=None,chunksize=100000000)
count = 1
for chunk in df:
    name = '/output/to/this/directory/file_%s.csv' %s count
    chunk.to_csv(name,header=None,index=None)
    print(count)
    count+=1

这段代码可以正常工作,我有足够的磁盘内存来一次性存储大约5.5-6 GB的数据,但速度很慢。是否有更好的方法?
编辑:
我已经编写了以下迭代解决方案:
with open('/path/to/really/big.csv', 'r') as csvfile:
    read_rows = csv.reader(csvfile)
    file_count = 1
    row_count = 1
    f = open('/output/to/this/directory/file_%s.csv' %s count,'w')
    for row in read_rows:
        f.write(''.join(row))
        row_count+=1
        if row_count % 100000000 == 0:
            f.close()
            file_count += 1
            f = open('/output/to/this/directory/file_%s.csv' %s count,'w')

编辑2:
我想提醒大家注意Vor的评论,他建议使用Unix/Linux分割命令,这是我找到的最快解决方案。

3
无需重复发明轮子,使用split命令http://linux.die.net/man/1/split即可。如果您一定要在Python中使用它,则可以将其放在`subprocess`模块中进行包装。 - Vor
我一定也会试试这个! - invoker
1
为什么要使用csv模块呢?你只是在读写行而已。行的输入和输出格式保持不变。此外,for row in read_rows可以改为for row_count, row in enumerate(read_rows, start=1),这样就不需要跟踪行号了。 - Steven Rumbalski
2个回答

12

在Unix/Linux中已经有现成的工具可供使用。

split -l 100000 -d source destination

将会为这些块的目标前缀添加两位数字后缀。


4
您真的不需要将所有数据读入pandas DataFrame中,只是为了拆分文件-您甚至不需要完全将数据读入内存。您可以搜索要拆分的近似偏移量,然后向前扫描,直到找到换行符,并在起始和结束偏移之间从源文件读取更小的块并写入目标文件中循环读取。(此方法假设您的CSV没有任何嵌入换行符的列值。)
SMALL_CHUNK = 100000

def write_chunk(source_file, start, end, dest_name):
    pos = start
    source_file.seek(pos)
    with open(dest_name, 'w') as dest_file:
        for chunk_start in range(start, end, SMALL_CHUNK):
            chunk_end = min(chunk_start + SMALL_CHUNK, end)
            dest_file.write(source_file.read(chunk_end - chunk_start))

实际上,一个中间解决方案是使用 csv 模块 - 它仍然会解析文件中的所有行,这并不是绝对必要的,但可以避免为每个块读取大量数组到内存中。


我猜Pandas本身就可以处理这个问题?我对Pandas一点也不熟悉。那么你认为我发表的使用生成器的解决方案在这种情况下是无效的,对吗? - idjaw
2
你的答案依赖于在内存中拥有所有行,这对于处理大文件的调用者来说是不可行的。 - babbageclunk
好的。看起来我也学到了一些东西。 :) 谢谢。我会删除我的解决方案。 - idjaw
我喜欢这个,你知道它的性能相对于读入内存或仅迭代如何吗?我刚刚写了另一个代码片段,现在正在迭代运行,我将把它放在上面的编辑中。 - invoker
我没有进行基准测试,但我预计它会快得多 - 它不需要将每行解析为列表,只需在每个大跳跃处扫描下一个行边界(这不会花费很长时间,因为每行只有约60个字节)。 - babbageclunk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接