Я написал программу на Python, которая тратит много времени на поиск атрибутов объектов и значений из ключей словаря. Я хотел бы знать, могу ли я каким-либо образом оптимизировать это время поиска, возможно, с расширением C, чтобы сократить время выполнения, или мне нужно просто повторно реализовать программу на скомпилированном языке.
В программе реализованы некоторые алгоритмы с использованием графа. Он работает невероятно медленно на наших наборах данных, поэтому я профилировал код с помощью cProfile с использованием сокращенного набора данных, который можно было бы на самом деле завершить. подавляющее время тратится на одну функцию, а именно на два оператора, генераторные выражения внутри функции:
Выражение генератора в строке 202:
neighbors_in_selected_nodes = (neighbor for neighbor in
node_neighbors if neighbor in selected_nodes)
и выражение генератора в строке 204:
neighbor_z_scores = (interaction_graph.node[neighbor]['weight'] for
neighbor in neighbors_in_selected_nodes)
Исходный код этой функции контекста предоставлен ниже.
selected_nodes — это set узлов в interaction_graph, который является экземпляром NetworkX Graph. node_neighbors – это итератор из Graph.neighbors_iter(). .
Graph сам использует словари для хранения узлов и ребер. Его атрибут Graph.node представляет собой словарь, в котором хранятся узлы и их атрибуты (например, 'weight') в словарях, принадлежащих каждому узлу.
Каждый из этих поисков должен амортизироваться за постоянное время (т. е. O (1)), однако я все еще плачу большой штраф за поиск. Есть ли способ, которым я могу ускорить эти поиски (например, написав части этого как расширение C), или мне нужно переместить программу на скомпилированный язык?
Ниже приведен полный исходный код функции, предоставляющей контекст; подавляющее большинство времени выполнения тратится на эту функцию.
def calculate_node_z_prime(
node,
interaction_graph,
selected_nodes
):
"""Calculates a z'-score for a given node.
The z'-score is based on the z-scores (weights) of the neighbors of
the given node, and proportional to the z-score (weight) of the
given node. Specifically, we find the maximum z-score of all
neighbors of the given node that are also members of the given set
of selected nodes, multiply this z-score by the z-score of the given
node, and return this value as the z'-score for the given node.
If the given node has no neighbors in the interaction graph, the
z'-score is defined as zero.
Returns the z'-score as zero or a positive floating point value.
:Parameters:
- `node`: the node for which to compute the z-prime score
- `interaction_graph`: graph containing the gene-gene or gene
product-gene product interactions
- `selected_nodes`: a `set` of nodes fitting some criterion of
interest (e.g., annotated with a term of interest)
"""
node_neighbors = interaction_graph.neighbors_iter(node)
neighbors_in_selected_nodes = (neighbor for neighbor in
node_neighbors if neighbor in selected_nodes)
neighbor_z_scores = (interaction_graph.node[neighbor]['weight'] for
neighbor in neighbors_in_selected_nodes)
try:
max_z_score = max(neighbor_z_scores)
# max() throws a ValueError if its argument has no elements; in this
# case, we need to set the max_z_score to zero
except ValueError, e:
# Check to make certain max() raised this error
if 'max()' in e.args[0]:
max_z_score = 0
else:
raise e
z_prime = interaction_graph.node[node]['weight'] * max_z_score
return z_prime
Вот пара лучших звонков по версии cProfiler, отсортированных по времени.
ncalls tottime percall cumtime percall filename:lineno(function)
156067701 352.313 0.000 642.072 0.000 bpln_contextual.py:204(<genexpr>)
156067701 289.759 0.000 289.759 0.000 bpln_contextual.py:202(<genexpr>)
13963893 174.047 0.000 816.119 0.000 {max}
13963885 69.804 0.000 936.754 0.000 bpln_contextual.py:171(calculate_node_z_prime)
7116883 61.982 0.000 61.982 0.000 {method 'update' of 'set' objects}
neighbors_in_selected_nodesиneighbor_z_scores? Почему не одна петля? Двухэтапная формулировка, кажется, не вводит ничего нового. Зачем это делать? Можете ли вы обновить вопрос, чтобы объяснить, почему используются два понимания вместо одного? - person S.Lott   schedule 05.04.2010selected_nodes). Для этого я использую два выражения генератора:neighbors_in_selected_nodesфильтры для выбранных узлов; это связано сneighbor_z_scoresдля получения весов. Цепочки итераторов должны делать их одним циклом, а не двумя; цикл оценивается в пределахmax(). - person gotgenes   schedule 05.04.2010if neighbor in selected_nodes:, а второе выражение представляетneighbor_z_scores.append(interaction_graph.node[neighbor]['weight']). Используя выражения генератора, я избегаю создания списка и операций добавления. От выборки соседей до оценкиmax(neighbor_z_scores)я полностью работаю с цепочкой итераторов. - person gotgenes   schedule 05.04.2010