2012-10-18 65 views
4

所以我有50 - 60 .dat文件全部包含m行和n列數字。我需要取所有文件的平均值,並以相同的格式創建一個新文件。我必須在Python中執行此操作。誰能幫我這個?如何使用python來計算幾個.dat文件的平均值?

我寫了一些代碼.. 我意識到我有一些不兼容的類型在這裏,但我想不出替代品,所以我還沒有改變任何東西。

#! /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 
+5

文件平均值的含義不明顯。請發佈示例文件。 –

+0

將每個文件看作是相同尺寸的矩陣。我想確定矩陣中任何給定位置上所有數字的均值,然後將平均值置於此位置的平均值矩陣中。 – user1757550

+0

你有什麼特別的麻煩? – jdi

回答

4

這是一個相當耗費時間和資源,有效的方法讀出此值,並計算所有文件並行的平均水平,但只有在每個文件一行一次讀取 - 但它確實暫時讀整個第一個.dat文件到內存中,以確定每個文件中將有多少行和列的數字。

你沒有說如果你的「數字」是整數或浮點或什麼,所以這讀取他們作爲浮點(即使他們不工作,這將工作)。無論如何,平均值將被計算並輸出爲浮點數。

更新

我修改我原來的答覆也算值的總體標準偏差(sigma)每行和每列中,按您的評論。它在計算它們的平均值後立即執行此操作,因此不必重新讀取所有數據。另外,爲了響應評論中的建議,添加了上下文管理器以確保所有輸入文件都被關閉。

請注意,標準偏差只是打印出來的,並沒有寫入輸出文件,但是對同一個文件或單獨的文件應該很容易添加。

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') 
+0

謝謝!這太棒了。我永遠不會想到使用發電機。如果我要回去計算與平均值相同的標準偏差,你會建議我使用另一臺發電機嗎? – user1757550

+0

是的,使用發電機列表應該很好地計算每個單元的σ。不必在最後關閉每個文件,而是可以用'files [i] .seek(0)'將'files'列表中的每個文件解繞,然後創建一個新的'generators'列表。如果你有足夠的內存,那麼保存第一遍讀取的所有數據當然要快得多。 – martineau

+0

更好的主意:你可以在內部循環中計算σ正確值,通過使'values'成爲一個常規序列(列表或元組),而不是像上面那樣使用生成器表達式,只計算'average' 。這意味着能夠一次計算兩個指標。 – martineau

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) 
  • 注:我沒有處理例外情況,例如文件爲空併產生Divide By Zero情況。