3

我有一个 ASCII 数据文件,它的格式对我来说是不熟悉的,就我如何最好地将数据读入 Python 中的列表或数组而言。ASCII 数据文件的格式如下:

line 0:          <month> <year>
lines 1 - 217:   12 integer values per line, each value has seven spaces, the first is always a space

例如,文件中的第一条记录如下所示:

    1 1900
 -32768 -32768    790  -1457  -1367    -16   -575    116 -32768 -32768   1898 -32768
 -32768  -1289 -32768 -32768 -32768 -32768 -32768 -32768 -32768 -32768 -32768 -32768
 -32768 -32768    -92 -32768 -32768 -32768    125 -32768 -32768 -32768 -32768 -32768
 -32768 -32768 -32768 -32768 -32768  -1656 -32768   -764 -32768 -32768 -32768 -32768
 <212 more lines like the above for this record, same spacing/separators/etc.>

我将上面的称为单个记录(单个月份的所有数据),文件中大约有 1200 条记录。月份从 1 到 12 依次增加,然后随着年份值的增加重新开始。我想一次读取一个记录,如下所示:

with open(data_file, 'r') as dataFile:
    # while file still has unread records
        # read month and year to use to create a datetime object
        # read the next 216 lines of 12 values into a list (or array) of 2592 values
        # process the record's list (or array) of data

有人可以建议一种有效的“Pythonic”方式来对记录进行上述循环,包括如何最好地将数据读入列表或数组?

在此先感谢您的帮助!

4

2 回答 2

1

itertools.groupby 可以在这里使用。

from datetime import date
from itertools import groupby

def keyfunc(line):
    global key
    row = map(int, line.strip().split())
    if len(row) == 2:
        month, year = row
        key = date(year, month, 1)
    return key

def read_file(fname):
    with open(fname, 'r') as f:
        for rec_date, lines in groupby(f, keyfunc):
            data = []
            for line in lines:
                line = map(int, line.strip().split())
                if len(line) == 2:
                    continue
                data.extend(line)
            yield rec_date, data

for rec_date, data in read_file('data.txt'):
    print rec_date, data[:5], '... (', len(data), ")"

keyfunc 是聪明的一点。它返回每行数据的键。groupby 将为具有相同键的每组连续记录生成一个迭代器。keyfunc 使用全局来实现以跟踪最新的 2 值记录(转换为日期)。多想一下,这个全局可能是可以避免的。当找到一个新的 2 值记录时,它会开始一个以日期为键的新组。数据被聚合到每个键的单个数组中,在返回时忽略 2 值行。最终结果是一个迭代器,它为数据文件中的每个日期返回一个 2 元组的日期和数据数组。

编辑: 这是一个简单的选项,不使用 itertools.groupby

from datetime import date

def read_file2(fname):
    data = []
    with open(fname, 'r') as f:
        for line in f:
            row = map(int, line.strip().split())
            if len(row) == 2:
                if data:
                    yield key, data
                month, year = row
                key = date(year, month, 1)                
                data = []
            else:
                data.extend(row)
        if data:
            yield key, data


for rec_date, data in read_file2('data.txt'):
    print rec_date, data[:5], '... (', len(data), ")"
于 2013-09-11T23:30:48.400 回答
1

您可以尝试使用生成器函数构建您的 numpy 数组,例如:

import numpy
def read_input(input_file):
    line_count = 0
    format_line = lambda x : [float(i) for i in x.split()]

    for line in open(input_file):
        if line_count <= 216:
            yield format_line(line)
        else:
            break
        line_count += 1

data = numpy.array([i for i in read_input(input_file)])

这将根据您的问题返回(月、年)和前 216 条记录。

于 2013-09-11T20:55:24.747 回答