4

したがって、50〜60個の.datファイルがあり、すべてにm行n列の数値が含まれています。すべてのファイルの平均を取り、同じ形式で新しいファイルを作成する必要があります。私はこれをPythonで行わなければなりません。誰かがこれを手伝ってくれますか?

私はいくつかのコードを書きました。私はここにいくつかの互換性のないタイプがあることに気づきましたが、私は代替案を考えることができないので、まだ何も変更していません。

#! /usr/bin/python
import os

CC = 1.96

average = []
total = []
count = 0
os.chdir("./")
for files in os.listdir("."):
    if files.endswith(".dat"):
        infile = open(files)
        cur = []
        cur = infile.readlines()
        for i in xrange(0, len(cur)):
            cur[i] = cur[i].split()
        total += cur
        count += 1
average = [x/count for x in total]

#calculate uncertainty
uncert = []

for files in os.listdir("."):
    if files.endswith(".dat"):
        infile = open(files)
        cur = []
        cur = infile.readlines
        for i in xrange(0, len(cur)):
            cur[i] = cur[i].split()
        uncert += (cur - average)**2
uncert = uncert**.5
uncert = uncert*CC
4

2 に答える 2

4

これは、値を読み取り、すべてのファイルの平均を並行して計算する、かなり時間とリソース効率の高いアプローチですが、一度にファイルごとに1行しか読み取りませんが、最初の.datファイル全体を一時的にメモリに読み込みます。各ファイルに含まれる数値の行と列の数を決定するため。

「数値」が整数なのか浮動小数点なのかなどは言わなかったので、浮動小数点として読み込まれます(そうでない場合でも機能します)。とにかく、平均は計算され、浮動小数点数として出力されます。

アップデート

sigmaコメントに従って、各行と列の値の母標準偏差()も計算するように元の回答を変更しました。平均値を計算した直後にこれを行うため、すべてのデータを再読み取りするための2回目のパスは必要ありません。さらに、コメントで行われた提案に応じて、すべての入力ファイルが確実に閉じられるようにコンテキストマネージャーが追加されました。

標準偏差は印刷されるだけで、出力ファイルには書き込まれないことに注意してください。ただし、同じファイルまたは別のファイルに標準偏差を追加するのは簡単です。

from contextlib import contextmanager
from itertools import izip
from glob import iglob
from math import sqrt
from sys import exit

@contextmanager
def multi_file_manager(files, mode='rt'):
    files = [open(file, mode) for file in files]
    yield files
    for file in files:
        file.close()

# generator function to read, convert, and yield each value from a text file
def read_values(file, datatype=float):
    for line in file:
        for value in (datatype(word) for word in line.split()):
            yield value

# enumerate multiple egual length iterables simultaneously as (i, n0, n1, ...)
def multi_enumerate(*iterables, **kwds):
    start = kwds.get('start', 0)
    return ((n,)+t for n, t in enumerate(izip(*iterables), start))

DATA_FILE_PATTERN = 'data*.dat'
MIN_DATA_FILES = 2

with multi_file_manager(iglob(DATA_FILE_PATTERN)) as datfiles:
    num_files = len(datfiles)
    if num_files < MIN_DATA_FILES:
        print('Less than {} .dat files were found to process, '
              'terminating.'.format(MIN_DATA_FILES))
        exit(1)

    # determine number of rows and cols from first file
    temp = [line.split() for line in datfiles[0]]
    num_rows = len(temp)
    num_cols = len(temp[0])
    datfiles[0].seek(0)  # rewind first file
    del temp  # no longer needed
    print '{} .dat files found, each must have {} rows x {} cols\n'.format(
           num_files, num_rows, num_cols)

    means = []
    std_devs = []
    divisor = float(num_files-1)  # Bessel's correction for sample standard dev
    generators = [read_values(file) for file in datfiles]
    for _ in xrange(num_rows):  # main processing loop
        for _ in xrange(num_cols):
            # create a sequence of next cell values from each file
            values = tuple(next(g) for g in generators)
            mean = float(sum(values)) / num_files
            means.append(mean)
            means_diff_sq = ((value-mean)**2 for value in values)
            std_dev = sqrt(sum(means_diff_sq) / divisor)
            std_devs.append(std_dev)

print 'Average and (standard deviation) of values:'
with open('means.txt', 'wt') as averages:
    for i, mean, std_dev in multi_enumerate(means, std_devs):
        print '{:.2f} ({:.2f})'.format(mean, std_dev),
        averages.write('{:.2f}'.format(mean))  # note std dev not written
        if i % num_cols != num_cols-1:  # not last column?
             averages.write(' ')  # delimiter between values on line
        else:
            print  # newline
            averages.write('\n')
于 2012-10-19T13:47:50.987 に答える
1

プロセスのどの側面が問題を引き起こしているのかわかりませんが、すべてのdatファイルの平均を取得することについて具体的に答えます。

このようなデータ構造を想定すると、次のようになります。

72 12 94 79 76  5 30 98 97 48 
79 95 63 74 70 18 92 20 32 50 
77 88 60 98 19 17 14 66 80 24 
...

ファイルの平均を取得する:

import glob
import itertools

avgs = []

for datpath in glob.iglob("*.dat"):
    with open(datpath, 'r') as f:
        str_nums = itertools.chain.from_iterable(i.strip().split() for i in f)
        nums = map(int, str_nums)
        avg = sum(nums) / len(nums)
        avgs.append(avg)

print avgs

各ファイルをループし.dat、読み取りて行を結合します。それらをintに変換し(必要に応じてfloatにすることもできます)、平均を追加します。

これらのファイルが巨大で、それらを読み込むときにメモリの量が心配な場合は、元の例のように、各行をより明示的にループしてカウンターのみを保持できます。

for datpath in glob.iglob("*.dat"):
    with open(datpath, 'r') as f:
        count = 0
        total = 0
        for line in f:
            nums = [int(i) for i in line.strip().split()]
            count += len(nums)
            total += sum(nums)
        avgs.append(total / count)
  • 注:ファイルが空で、ゼロ除算の状況が発生するなどの例外的なケースは処理していません。
于 2012-10-18T21:09:24.383 に答える