У меня здесь двоякая проблема.
1) Моя первоначальная проблема - попытка улучшить время вычислений в моем алгоритме
2) Моя следующая проблема, которая является одним из моих «улучшений», по-видимому, потребляет более 500 ГБ оперативной памяти, и я не знаю, почему.
Я писал перестановку для конвейера биоинформатики. По сути, алгоритм запускает выборку 1000 нулевых вариантов для каждого имеющегося у меня варианта. Если определенное условие не выполняется, алгоритм на этот раз повторяет выборку с 10000 нулями. Если условие не выполняется снова, это масштабируется до 100000, а затем до 1000000 нулей для варианта.
Я сделал все, что мог придумать, чтобы оптимизировать это, и на данный момент я нахожусь в тупике для улучшений. У меня такое грубоватое понимание:
output_names_df, output_p_values_df = map(list, zip(*[random_sampling_for_variant(variant, options_tables, variant_to_bins, num_permutations, use_num) for variant in variant_list]))
По сути, все, что это делает, это вызывает мою функцию random_sampling_for_variants для каждого варианта в моем списке вариантов и помещает два выхода из этой функции в список списков (так что я получаю два списка списков, output_names_df и output_p_values_df ). Затем я превращаю эти списки обратно в DataFrames, переименовываю столбцы и делаю с ними все, что мне нужно. Вызываемая функция выглядит так:
def random_sampling_for_variant(variant, options_tables, variant_to_bins, num_permutations, use_num):
"""
Inner function to permute_null_variants_single
equivalent to permutation for 1 variant
"""
#Get nulls that are in the same bin as our variant
permuted_null_variant_table = options_tables.get_group(variant_to_bins[variant])
#If number of permutations > number of nulls, sample with replacement
if num_permutations >= len(permuted_null_variant_table):
replace = True
else:
replace = False
#Select rows for permutation, then add as columns to our temporary dfs
picked_indices = permuted_null_variant_table.sample(n=num_permutations, replace=replace)
temp_names_df = picked_indices['variant'].values[:use_num]
temp_p_values_df = picked_indices['GWAS_p_value'].values
return(temp_names_df, temp_p_values_df)
При определении permuted_null_variant_table я просто запрашиваю предварительно определенный сгруппированный DataFrame, чтобы определить соответствующую нулевую таблицу для выборки. Я обнаружил, что это быстрее, чем пытаться определить подходящие нули для выборки на лету. Логика, которая следует там, определяет, нужно ли мне брать сэмплы с заменой или без нее, и это занимает совсем немного времени. Определение selected_indices - это то, где фактически выполняется случайная выборка. temp_names_df и temp_p_values_df получают значения, которые я хочу, из пустой таблицы, а затем я отправляю свои результаты из функции.
Проблема здесь в том, что вышеописанное не очень хорошо масштабируется. Для 1000 перестановок приведенные выше строки кода занимают ~ 254 секунды на 7725 вариантах. Для 10 000 перестановок ~ 333 секунды. Для 100 000 перестановок ~ 720 секунд. За 1000000 перестановок, что является верхней границей, к которой я хотел бы добраться, мой процесс был убит, потому что он, очевидно, собирался занимать больше оперативной памяти, чем кластер.
Я в тупике о том, как действовать. Я превратил все целые числа в 8-битные, я превратил все свои поплавки в 16-битные. Я отбросил столбцы, которые мне не нужны, там, где они мне не нужны, поэтому я делаю выборки только из таблиц с нужными мне столбцами. Первоначально у меня было понимание в форме цикла, но вычислительное время на понимание составляет 3/5 времени цикла. Любые отзывы приветствуются.