Python Pandas:读取具有多个表的csv重复的序言


问题内容

有没有一种Python方式可以找出CSV文件中的哪些行包含标题和值,哪些行包含垃圾,然后将标题/值行放入数据帧?

我是python的新手,并且一直使用它来读取从科学仪器的数据记录中导出的多个CSV,并且到目前为止,在处理其他任务的CSV时,我始终默认使用该pandas库。但是,这些CSV导出可能会有所不同,具体取决于每种仪器上记录的“测试”数量。

仪器之间的列标题和数据结构相同,但是有一个“前导”分隔每个可以更改的测试。因此,我得到的备份看起来像这样(在此示例中,有两个测试,但是可能有任意数量的测试):

blah blah here's a test and  
here's some information  
you don't care about  
even a little bit  
header1, header2, header3  
1, 2, 3  
4, 5, 6

oh you have another test  
here's some more garbage  
that's different than the last one  
this should make  
life interesting  
header1, header2, header3  
7, 8, 9  
10, 11, 12  
13, 14, 15

如果每次我只是使用skiprow参数,它都是固定长度的前同步码,但该前同步码是可变长度的,并且每个测试中的行数是可变长度的。

我的最终目标是能够合并所有测试,并得到如下结果:

header1, header2, header3  
1, 2, 3  
4, 5, 6  
7, 8, 9  
10, 11, 12  
13, 14, 15

然后我可以像往常一样用大熊猫操纵它。

我已经尝试了以下方法来查找具有预期标题的第一行:

import csv
import pandas as pd

with open('my_file.csv', 'rb') as input_file:    
    for row_num, row in enumerate(csv.reader(input_file, delimiter=',')):
        # The CSV module will return a blank list []
        # so added the len(row)>0 so it doesn't error out
        # later when searching for a string
        if len(row) > 0:
            # There's probably a better way to find it, but I just convert
            # the list to a string then search for the expected header
            if "['header1', 'header2', 'header3']" in str(row):
                header_row = row_num

    df = pd.read_csv('my_file.csv', skiprows = header_row, header=0)
    print df

如果我只有一个测试,则此方法有效,因为它找到了具有标头的第一行,但是当然,header_row变量每次找到标头时都会进行更新,因此在上面的示例中,我最终输出:

   header1   header2   header3  
0        7         8           9
1       10        11          12
2       13        14          15

在继续搜索标题/数据集的下一个实例之前,我迷失了如何弄清楚如何将标题/数据集的每个实例附加到数据帧。

而且,当处理大量文件时,必须先通过csv模块打开一次,然后再使用一次打开,这可能不是超级有效pandas


问题答案:

该程序可能会有所帮助。本质上,它是围绕csv.reader()对象的包装器,该包装器可以收集出良好的数据。

import pandas as pd
import csv
import sys


def ignore_comments(fp, start_fn, end_fn, keep_initial):
    state = 'keep' if keep_initial else 'start'
    for line in fp:
        if state == 'start' and start_fn(line):
            state = 'keep'
            yield line
        elif state == 'keep':
            if end_fn(line):
                state = 'drop'
            else:
                yield line
        elif state == 'drop':
            if start_fn(line):
                state = 'keep'

if __name__ == "__main__":

    df = open('x.in')
    df = csv.reader(df, skipinitialspace=True)
    df = ignore_comments(
        df,
        lambda x: x == ['header1', 'header2', 'header3'],
        lambda x: x == [],
        False)

    df = pd.read_csv(df, engine='python')
    print df