如何将这个ASCII数据读入Python列表或numpy数组?

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”方法来循环遍历记录,包括如何最好地将数据读入列表或数组?
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), ")"

关键函数是聪明的部分。它为每行数据返回一个键。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), ")"

1
这对我来说是一个很好的机会,可以尝试使用itertools.groupby。也可能通过简单的迭代器聚合数据并自己实现分组逻辑。 - Graeme Stuart
我现在将你的代码作为我的程序的一部分使用,它运行得非常好。非常感谢你的帮助,并帮助我更多地了解如何在Python中做好事情! - James Adams

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条记录,与您的问题相符。

1
这只会读取第一组数据。而且它不能区分日期行和数据行。最后,它不是很符合Python的风格,如果我需要跟踪行数,我会使用enumerate。请查看我的答案以获取更全面的方法。 - Graeme Stuart

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