按列迭代csv

时间:2015-08-18 14:36:52

标签: python csv pandas dataframe

我有一堆大的(约400万个值)csv文件,我需要获取每个列并创建一个文件,以一种可以由不同程序解释的方式组织这些值。列的长度差异很大(介于200万到1000之间),每个csv可能有4到100列。

我可以将整个内容加载到pandas.DataFrame然后遍历整个系列,但它很慢:

import pandas as pd
import re
import os
for f in os.listdir(folder):
    gc = pd.read_csv('{}/{}'.format(folder, f))
    strain = f[:-7] # files have regular name structure, this just gets the name

    with open('{}.txt'.format(strain), 'w+') as out_handle:
        for column in gc:
            series = gc[column]
            for i in range(len(series))[::10]:
                pos = i + 1
                gc_cont = s[i]
                if pd.isnull(gc_cont):
                    continue
                out_handle.write('{} {}'.format(pos, gc_cont) 
                # I'm writing other info, but it's not important here 

使用百万+ NaN值填充较小的列并将整个内容加载到内存中可能会产生很大的性能成本?无论如何,我认为逐列阅读会更有效率,但我无法找到办法。

Pandas可以chunk sizedocs),但是那个分块行。如果我逐行写,我要么必须一次打开4-100个文件,要么多次遍历原始文件来编写每个单独的列。这些方法中的任何一种都是适当的还是我缺少的东西?

3 个答案:

答案 0 :(得分:1)

如何将整个文件读入字符串并将其包装在StringIO(或BytesIO,取决于Python 2/3)中?然后将其用作csv文件并按列迭代一次。

这样的事情:

with open('{}/{}'.format(folder, f)) as in_file:
    data = in_file.read()

for index in number_of_columns: # not sure how to derive this
    csv_file = csv.reader(StringIO.StringIO(data))
    for data_row in csv_file:
        # do what you want with data_row[index]

编辑:

这似乎没有解决性能问题。根据您的意见,我认为最佳的性能方法是一次打开所有4到100个文件,并在阅读时写入。我不认为现代操作系统会有任何问题。这在算法上是最简单的,并且奖励也最小化了内存使用。任何版本都需要在读取,解析和编写方面所做的工作。我认为可能存在争用磁盘磁头的风险,但我猜这不会是一个问题。

我认为只有测试会显示它是否更快 - 它并不明显。

这就像

with open('{}/{}'.format(folder, f)) as in_file:
    csv_file = csv.reader(in_file)

    # open up the files needed and put them into file_list 

    for data_row in csv_file:
        for index,datum in data_row:
            if datum != "":
                file_list[index].write(datum)

我还没有完全模仿你的写作方案,但我确信你明白我的意思。显然你需要一种机制来找到合适数量的文件(可能看第一行?),然后关闭它们等等。

答案 1 :(得分:1)

最简单的方法可能是将整个文件读入pandas df并将每列写入自己的文件。

import pandas as pd
import os

for f in os.listdir(folder):
    gc = pd.read_csv('{}/{}'.format(folder, f))
    strain = f[:-7]

    for col in gc.columns:
        temp = gc.col
        temp.to_csv('new_path'+strain+col)

这样,即使你有一个内存消耗操作,你只需将较大的帧拆分成列并创建自己的文件,这将更容易使用。

答案 2 :(得分:1)

usecols的{​​{1}}选项怎么样?此外,您可以考虑使用read_csv选项返回squeeze,如果您只使用单列,则可能会更快。像

这样的东西
pandas.Series

以下是文档

  

usecols :类似数组

     
    

返回列的子集。结果是解析时间更快,内存使用率更低。

  
     

挤压:布尔值,默认为False

     
    

如果解析的数据只包含一列,则返回一个Series