Моя задача относительно проста: для каждой строки во входном файле проверить, удовлетворяет ли строка заданному набору условий, и, если это так, записать определенные столбцы этой строки в новый файл.Я написал скрипт на Python, который делает это, но мне нужна помощь: 1) улучшение скорости, 2) лучший способ работы с именами столбцов (так как номера столбцов могут варьироваться от файла к файлу), и 3) лучший способ указать мои условия фильтрации и желаемые выходные столбцы.
1) Файлы, с которыми я работаю, содержат фотометрию для астрономических изображений.Каждый файл занимает около 1e6 строк на 150 столбцов с плавающей запятой, обычно размером более 1 ГБ.У меня есть старый скрипт AWK, который обрабатывает такие файлы примерно за 1 минуту;Мой скрипт на python занимает от 5 до 7 минут.Мне часто приходится подстраивать условия фильтрации и перезапускать несколько раз, пока выходной файл не будет таким, каким я хочу, поэтому скорость определенно желательна.Я обнаружил, что цикл for достаточно быстрый;это то, как я делаю вещи внутри цикла, которые замедляют его.Использование itemgetter для выбора нужных столбцов было большим улучшением по сравнению с чтением всей строки в память, но я не уверен, что могу сделать для дальнейшего увеличения скорости.Может ли это быть так же быстро, как AWK?
2) Я бы хотел работать с именами столбцов, а не с номерами столбцов, так как номер столбца определенной величины (количество фотонов, фон, сигнал кшум и т. д.) может меняться между файлами.В моем скрипте AWK мне всегда нужно проверять правильность номеров столбцов, если указаны условия и выходные столбцы, даже если фильтрация и вывод применяются к одним и тем же количествам.Мое решение в Python было создать словарь, который присваивает номер столбца для каждой величины.Когда файл имеет разные столбцы, мне нужно только указать новый словарь.Возможно, есть лучший способ сделать это?
3) В идеале, мне нужно только указать имена входных и выходных файлов, условия фильтрации и желаемые столбцы для вывода, и они будут найденыв верхней части моего сценария, чтобы мне не пришлось искать код, чтобы просто что-то настроить.Моя главная проблема была с неопределенными переменными.Например, типичным условием является «SNR> 4», но «SNR» (сигнал-шум) фактически не присваивается значение до тех пор, пока строки не начнут считываться из файла фотометрии.Мое решение было использовать комбинацию строк и eval / exec.Опять же, может быть, есть лучший способ?
Я совсем не обучаюсь информатике (я аспирант по астрономии) - обычно я просто взламываю что-то вместе и отлаживаю, пока это не работает.Тем не менее, оптимизация в отношении моих трех пунктов выше стала чрезвычайно важной для моего исследования.Я прошу прощения за длинный пост, но я чувствовал, что детали будут полезны.Любой совет, который вы мне дадите, в дополнение к простой очистке / стилю кодирования, будет очень признателен.
Большое спасибо, Джейк
#! /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()