Итерационный панды дополнения подряд и подряд снижается


Я написал программу, которая использует pandas таблицы данных для быстрого доступа и фильтрации данных (ДНК строк). Приходите, чтобы узнать, pandas операции на самом деле узким местом в моей программе.

Программа

Я начну эту часть программы с ДФ я называю clust_prov. В clust_prov ДФ индексируется уникальных последовательностей ДНК все длины k. Самый важный столбец-это cluster, который содержит ДНК-последовательность, по меньшей мере, длины k+1. Другие столбцы, prefix, suffix, prefix_rcи suffix_rc содержать строки, полученные в результате cluster. Например, столбец может иметь кластер GATCATTACGACTGTACTGTACCGGAGAACGGTи будут иметь другие значения, как вы видите ниже. Для этого примера, давайте рассмотрим prefix и suffix_rc для простоты.

    GATCA                       ACGGT     < For this molecule, the vars are:
 5' GATCATTACGACTGTACTGTACCGGAGAACGGT 3'  < prefix    - GATCA
                                          < suffix_rc - ACGGT

Моя программа выглядит в кластере и спрашивает, если префикс или suffix_rc соответствует префиксы/suffix_rcs других кластеров, объединяет два кластера, и начинает весь процесс заново. Это делается итерационно, пока не сливает может быть выполнена.

Мой ДФ clust_provимеет около 70К строк в начале программы, и присоединяется редко, так что только около 20% кластеров, слияние-в состоянии. Несмотря на то, что операции объединения произойти только 20% времени, функция, которая обрабатывает его, update_by_addition()занимает около 60% времени.

Псевдокод функции реального контроля

def merge_clusters(clust_prov, try_to_merge_these):
    for cluster in try_to_merge_these:
        if cluster in clust_prov:   # make sure we haven't already removed it
            if cluster.prefix in clust_prov[, [prefix/suffix_rc]]:
                clust_prov = update_by_addition(clust_prov, 
                                       cluster, 
                                      <cluster that matches if condition above>)

Саму функцию я хочу ускорить

Код без профилирования метаданных:

def update_by_addition(clust_prov, new_cluster, old_index,
                       merge_index, fate_round):
    kmerlen = len(old_index)
    clust_prov.loc[old_index] += clust_prov.loc[merge_index, ]
    clust_prov.loc[old_index, "cluster"] = new_cluster
    clust_prov.loc[old_index, "prefix"] = new_cluster[0:kmerlen]
    clust_prov.loc[old_index, "suffix"] = seqpy.revcomp(new_cluster[-kmerlen:])
    clust_prov.loc[old_index, "prefix_rc"] = seqpy.revcomp(new_cluster[0:kmerlen])
    clust_prov.loc[old_index, "suffix_rc"] = new_cluster[-kmerlen:]
    try:
        clust_prov.loc[old_index, "merged_at"].append(fate_round)
    except:
        clust_prov.loc[old_index, "merged_at"] = [fate_round]

    #we only need this if we don't sum
    clust_prov = clust_prov.drop(merge_index)
    return clust_prov

Код проблемы

Самый медленный процесс из kernprof добавляет две строки вместе, а затем опуская одну строку.

Что я сделал до сих пор

Я пробовал несколько разных способов выброски (как ~ оператора). Я не пробовал ничего другого ряда кроме того, так как это выглядит как единственный вариант.

Цель

Мне просто нужно выяснить, если есть способ, что я могу сделать это быстрее, используя pandasили если я бы лучше Преобразуя все на дикт оф предсказывает, или некоторые другие структуры данных. Скорость действительно является проблемой здесь, так как в текущее время процесс этот модуль в моей программе 14ч за 70к строк.

Ограничения

  • Этот процесс является итеративным, поэтому я не могу векторизовать функцию, используйте частичный и так далее для увеличения скорости. Каждая операция зависит от сложения двух предыдущих строк и строк, которые были удалены.
  • Таблицы данных будут большими (>70к строк) и медленно становятся все меньше, а строк суммируются/модифицированных, потом убрали.
  • Не каждая строка будет в конечном итоге должны быть изменены. Например, я побежал моей родительской программы на 500 строк, и это только нужно, чтобы запустить этот update_by_addition метод 104 раз.

Результаты Профилирования

Профилирование кода с kernprof дает мне следующий результат:

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   780                                           @profile
   781                                           def update_by_addition(clust_prov, new_cluster, old_index,
   782                                                                  merge_index, fate_round):
   791       104          333      3.2      0.0      kmerlen = len(old_index)
   794       104     22786882 219104.6     40.8      clust_prov.loc[old_index] += clust_prov.loc[merge_index, ]
   795       104      2882801  27719.2      5.2      clust_prov.loc[old_index, "cluster"] = new_cluster
   796       104      3218409  30946.2      5.8      clust_prov.loc[old_index, "prefix"] = new_cluster[0:kmerlen]
   797       104      3194060  30712.1      5.7      clust_prov.loc[old_index, "suffix"] = seqpy.revcomp(new_cluster[-kmerlen:])
   798       104      3196542  30736.0      5.7      clust_prov.loc[old_index, "prefix_rc"] = seqpy.revcomp(new_cluster[0:kmerlen])
   799       104      3214856  30912.1      5.8      clust_prov.loc[old_index, "suffix_rc"] = new_cluster[-kmerlen:]
   800       104          477      4.6      0.0      try:
   801       104        29723    285.8      0.1          clust_prov.loc[old_index, "merged_at"].append(fate_round)
   802       104          126      1.2      0.0      except:
   803       104       971903   9345.2      1.7          clust_prov.loc[old_index, "merged_at"] = [fate_round]
   804
   805                                               #we only need this if we don't sum
   807       104     16298261 156714.0     29.2      clust_prov = clust_prov.drop(merge_index)
   808       104          321      3.1      0.0      return clust_prov


Комментарии