Печать на Python невероятно медленно

Я сталкиваюсь с проблемой, с которой я никогда не сталкивался, и это чертовски расстраивает меня. я использую rpy2 взаимодействовать с R из скрипта Python и нормализовать массив. По какой-то причине, когда я собираю свои выходные данные вместе и печатаю в файл, на печать уходит целая вечность. Он также замедляется по мере продолжения, пока не будет сброшено, возможно, несколько килобайт данных для вывода в минуту.

Мой входной файл большой (366 МБ), но он работает на высокопроизводительном вычислительном кластере с почти неограниченными ресурсами. Не должно быть никаких проблем с этим.

Вот где я на самом деле делаю нормализацию:

matrix = sample_list  # two-dimensional array
v = robjects.FloatVector([ element for col in matrix for element in col ])
m = robjects.r['matrix'](v, ncol = len(matrix), byrow=False)
print("Performing quantile normalization.")
Rnormalized_matrix = preprocessCore.normalize_quantiles(m)
normalized_matrix = np.array(Rnormalized_matrix)

Как видите, я в конечном итоге numpy.array объект, содержащий мои теперь нормализованные данные. У меня есть еще один список, содержащий другие строки, которые я хочу вывести на вывод, каждый элемент соответствует элементу массива numpy. Поэтому я перебираю, объединяя каждую строку массива в строку, и печатаю обе на выходе.

for thing in pos_list:  # List of strings corresponding with each row of array.
    thing_index = pos_list.index(thing)

    norm_data = normalized_matrix[thing_index]
    out_data = "\t".join("{0:.2f}".format(piece) for piece in norm_data)

    print(thing + "\t" + out_data, file=output)

Я не профессионал, но я понятия не имею, почему все так сильно замедляется. Любое понимание или предложения будут очень и очень признательны. Я могу опубликовать больше / остальную часть сценария, если кто-то считает, что это может быть полезно.

Обновление: спасибо @lgautier за предложение по профилированию. С использованием line_profiler модуль, я смог определить свою проблему в строке:thing_index = pos_list.index(thing)

Это имеет смысл, поскольку этот список очень длинный, а также объясняет замедление работы сценария. Простое использование счетчика вместо этого решило проблему.

Профилирование исходного кода (обратите внимание на% для указанной строки):

   Line #      Hits         Time  Per Hit   % Time  Line Contents
   115         1     16445761 16445761.0     15.5       header, pos_list, normalized_matrix = Quantile_Normalize(in
   117         1           54     54.0      0.0         print("Creating output file...")
   120         1         1450   1450.0      0.0         output = open(output_file, "w")
   122         1            8      8.0      0.0         print(header, file=output)
   124                                                  # Iterate through each position and print QN'd data
   125    100000        74600      0.7      0.1         for thing in pos_list:
   126     99999     85244758    852.5     80.3                 thing_index = pos_list.index(thing)
   129     99999       158741      1.6      0.1                 norm_data = normalized_matrix[thing_index]
   130     99999      3801631     38.0      3.6                 out_data = "\t".join("{0:.2f}".format(piece) for pi
   132     99999       384248      3.8      0.4                 print(thing + "\t" + out_data, file=output)
   134         1         3641   3641.0      0.0         output.close()

Профилирование нового кода:

   Line #      Hits         Time  Per Hit   % Time  Line Contents
   115         1     16177130 16177130.0     82.5       header, pos_list, normalized_matrix = Quantile_Normalize(input_file, data_start)
   116
   117         1           55     55.0      0.0         print("Creating output file...")
   118
   119
   120         1        26157  26157.0      0.1         output = open(output_file, "w")
   121
   122         1           11     11.0      0.0         print(header, file=output)
   123
   124                                                  # Iterate through each position and print QN'd data
   125         1            1      1.0      0.0         count = 0
   126    100000        62709      0.6      0.3         for thing in pos_list:
   127     99999        58587      0.6      0.3                 thing_index = count
   128     99999        67164      0.7      0.3                 count += 1
   131     99999        85664      0.9      0.4                 norm_data = normalized_matrix[thing_index]
   132     99999      2877634     28.8     14.7                 out_data = "\t".join("{0:.2f}".format(piece) for piece in norm_data)
   134     99999       240654      2.4      1.2                 print(thing + "\t" + out_data, file=output)
   136         1         1713   1713.0      0.0         output.close()

2 ответа

Решение

Если я правильно понимаю, все работает нормально и с хорошей производительностью вплоть до (и в том числе) строки:

normalized_matrix = np.array(Rnormalized_matrix)

В этой строке результирующая матрица превращается в пустой массив (буквально - это может быть даже быстрее, если избежать копирования данных, как в http://rpy2.readthedocs.io/en/version_2.8.x/numpy.html?from-rpy2-to-numpy).

Я не вижу проблем с производительностью в остальной части скрипта, связанной с rpy2.

Теперь может случиться так, что это не потому, что на этикетке написано "HPC", что он высокопроизводителен в любой ситуации со всем кодом. Вы рассматривали возможность запуска этого медленного последнего цикла через профилировщик кода? Это скажет вам, где время проведено.

Во-первых, я обычно использую генератор, чтобы избежать временного списка множества маленьких строк.

out_data = "\t".join("{0:.2f}".format(piece) for piece in norm_data)

Но трудно сказать, была ли эта часть медленной.

Другие вопросы по тегам