私のタスクは比較的単純です。入力ファイルの各行について、その行が特定の条件セットを満たしているかどうかをテストし、満たしていれば、その行の特定の列を新しいファイルに書き込みます。私はこれを行う python スクリプトを作成しましたが、1) 速度の向上、2) 列名に関して作業するための最良の方法 (列番号はファイルごとに異なる可能性があるため)、および 3 について助けてください。 ) フィルター条件と目的の出力列を指定する最良の方法です。
1) 私が扱っているファイルには、天体画像の測光が含まれています。各ファイルは約 1e6 行×150 列の float であり、通常、サイズは 1GB を超えます。このようなファイルを約 1 分で処理する古い AWK スクリプトがあります。私の python スクリプトには 5 ~ 7 分かかります。出力ファイルが目的のものになるまで、フィルタリング条件を微調整して数回再実行する必要があることがよくあるため、速度は間違いなく望ましいものです。for ループは非常に高速であることがわかりました。ループを遅くするのは、ループ内での処理方法です。itemgetter を使用して必要な列だけを選択することは、行全体をメモリに読み込むよりも大幅に改善されましたが、さらに速度を上げるために何ができるかわかりません。これは AWK と同じくらい高速ですか?
2) 特定の量 (フォトン数、バックグラウンド、シグナル対ノイズなど) の列番号はファイル間で変わる可能性があるため、列番号ではなく列名で作業したいと思います。私の AWK スクリプトでは、フィルタリングと出力が同じ量に適用される場合でも、条件と出力列が指定されている場所で列番号が正しいことを常に確認する必要があります。Python での私の解決策は、各数量に列番号を割り当てる辞書を作成することでした。ファイルに異なる列がある場合、新しい辞書を指定するだけで済みます。おそらくこれを行うためのより良い方法がありますか?
3) 理想的には、入力ファイルと出力ファイルの名前、フィルタリング条件、および出力する目的の列を指定するだけでよく、それらはスクリプトの先頭にあるため、検索する必要はありません。何かを微調整するためだけのコード。私の主な問題は、未定義の変数にありました。たとえば、一般的な条件は「SNR > 4」ですが、「SNR」(信号対ノイズ) には、測光ファイルからラインの読み取りが開始されるまで、実際には値が割り当てられません。私の解決策は、文字列と eval/exec の組み合わせを使用することでした。繰り返しますが、もっと良い方法があるのではないでしょうか?
私はコンピューター サイエンスの訓練を受けていません (私は天文学の大学院生です)。通常、何かを一緒にハックして、それが機能するまでデバッグします。しかし、上記の 3 点に関する最適化は、私の研究にとって非常に重要になってきました。長文で申し訳ありませんが、詳しく教えていただけると助かります。クリーンアップ/コーディングスタイルに加えて、あなたが私に持っているすべてのアドバイスをいただければ幸いです。
どうもありがとう、ジェイク
#! /usr/bin/env python2.6
from operator import itemgetter
infile = 'ugc4305_1.phot'
outfile = 'ugc4305_1_filt.phot'
# names must belong to dicitonary
conditions = 'OBJ <= 2 and SNR1 > 4 and SNR2 > 4 and FLAG1 < 8 and FLAG2 < 8 and (SHARP1 + SHARP2)**2 < 0.075 and (CROWD1 + CROWD2) < 0.1'
input = 'OBJ, SNR1, SNR2, FLAG1, FLAG2, SHARP1, SHARP2, CROWD1, CROWD2'
# should contain all quantities used in conditions
output = 'X, Y, OBJ, COUNTS1, BG1, ACS1, ERR1, CHI1, SNR1, SHARP1, ROUND1, CROWD1, FLAG1, COUNTS2, BG2, ACS2, ERR2, CHI2, SNR2, SHARP2, ROUND2, CROWD2, FLAG2'
# dictionary of col. numbers for the more important qunatities
columns = dict(EXT=0, CHIP=1, X=2, Y=3, CHI_GL=4, SNR_GL=5, SHARP_GL=6, ROUND_GL=7, MAJAX_GL=8, CROWD_GL=9, OBJ=10, COUNTS1=11, BG1=12, ACS1=13, STD1=14, ERR1=15, CHI1=16, SNR1=17, SHARP1=18, ROUND1=19, CROWD1=20, FWHM1=21, ELLIP1=22, PSFA1=23, PSFB1=24, PSFC1=25, FLAG1=26, COUNTS2=27, BG2=28, ACS2=29, STD2=30, ERR2=31, CHI2=32, SNR2=33, SHARP2=34, ROUND2=35, CROWD2=36, FWHM2=37, ELLIP2=38, PSFA2=39, PSFB2=40, PSFC2=41, FLAG2=42)
f = open(infile)
g = open(outfile, 'w')
# make string that extracts values for testing
input_items = []
for i in input.replace(',', ' ').split():
input_items.append(columns[i])
input_items = ', '.join(str(i) for i in input_items)
var_assign = '%s = [eval(i) for i in itemgetter(%s)(line.split())]' % (input, input_items)
# make string that specifies values for writing
output_items = []
for i in output.replace(',', ' ').split():
output_items.append(columns[i])
output_items = ', '.join(str(i) for i in output_items)
output_values = 'itemgetter(%s)(line.split())' % output_items
# make string that specifies format for writing
string_format = []
for i in output.replace(',', ' ').split():
string_format.append('%s')
string_format = ' '.join(string_format)+'\n'
# main loop
for line in f:
exec(var_assign)
if eval(conditions):
g.write(string_format % tuple(eval(output_values)))
f.close()
g.close()