3

Python でデータをリストまたは配列に読み込む最善の方法に関して、なじみのない形式の ASCII データ ファイルがあります。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.>

上記を 1 つのレコード (1 か月分のすべてのデータ) と呼ぶと、ファイルには約 1200 のレコードがあります。月は 1 から 12 まで順次増加してから、年の値の増分で最初からやり直します。次のように、一度に 1 つずつレコードを読みたいと思います。

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 値レコードが見つかると、日付をキーとして新しいグループが開始されます。データはキーごとに 1 つの配列に集約され、値が 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 に答える