删除巨大的csv中已知的确切行

时间:2016-04-21 20:12:29

标签: python r csv

我有一个~2亿行,7列csv文件。我需要删除第2636759行。 这个文件是7.7GB,超过内存容量。我对R最熟悉,但也可以在python或bash中执行此操作。

我无法在一次操作中读取或写入此文件。在磁盘上逐步构建此文件的最佳方法是什么,而不是尝试在内存中全部执行此操作?

我试图在SO上找到它,但只能找到如何使用足够小的文件来读取/写入内存,或者使用位于文件开头的行。

3 个答案:

答案 0 :(得分:7)

一个python解决方案:

import os
with open('tmp.csv','w') as tmp:

    with open('file.csv','r') as infile:
        for linenumber, line in enumerate(infile):
            if linenumber != 10234:
                tmp.write(line)

# copy back to original file. You can skip this if you don't
# mind (or prefer) having both files lying around           
with open('tmp.csv','r') as tmp:
    with open('file.csv','w') as out:
        for line in tmp:
            out.write(line)

os.remove('tmp.csv') # remove the temporary file

这会复制数据,如果磁盘空间有问题,这可能不是最佳数据。在没有将整个文件首先加载到RAM中的情况下,写入会更复杂

关键是python自然支持处理files as iterables。这意味着它可以进行延迟评估,并且您永远不需要一次将整个事物保存在内存中

我喜欢这个解决方案,如果您的主要关注点不是原始速度,因为您可以使用任何条件测试替换行linenumber != VALUE,例如,过滤掉包含特定日期的行

test = lambda line : 'NOVEMBER' in line
with open('tmp.csv','w') as tmp:
    ...
    if test(line):
    ...

In-place read-writesmemory mapped file objects(可能相当快)将需要更多的簿记

答案 1 :(得分:2)

使用sed '2636759d' file.csv > fixedfile.csv

作为40,001行1.3G csv的测试,以40,000方式删除行0m35.710s。来自@en_Knight的python解决方案的内容(只是剥离行并写入临时文件)对于同一个文件来说快了大约2秒。

修改确定sed(或某些实施)可能不起作用(根据提问者的反馈)

您可以通过简单的bash从nN的文件中删除行file.csv,您可以执行head -[n-1] file.csv > file_fixed.csvtail -[N-n] file.csv >> file_fixed.csv(在这两个中,括号中的表达式都用普通数字代替。

要做到这一点,尽管你需要知道N。 python解决方案更好......

答案 2 :(得分:1)

您也可以R中的readLines一行阅读一行,然后使用writeLines

写一行以外的其他行,也可以python执行此操作

对于与con <- file('test.csv', 'r') out_con <- file('tmp.csv', 'w') bad_line <- 2636759 ctr <- 1 while (length(line <- readLines(con, n=1, warn=FALSE)) > 0){ if (ctr != bad_line) writeLines(line, out_con) ctr <- ctr + 1 } 中的解决方案类似的解决方案:

sed

但请注意, MUCH 比python慢​​(在40,000行文件中需要~3m40s n需要30秒)。可能会增加块大小sed会加快速度,但pythonsTHead += @"<TH>" + col.ColumnName + @"</TH>"; 似乎更容易。