Улучшение производительности кода, который использует циклы for - PullRequest
1 голос
/ 16 февраля 2020

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

Вот объяснение кода:

Вы можете представить эту проблему как список игр ( list_type), каждая из которых содержит список участвующих команд и оценки для каждой команды в игре (list_xx). Для каждой из пар в текущей игре сначала рассчитывается сумма различий в результатах предыдущих соревнований (win_comp_past_difs); включая только пары в текущей игре. Затем он обновляет каждую пару в текущей игре с разницей в баллах. Использование defaultdict отслеживает оценки для каждой пары в каждой игре и обновляет этот счет при каждой игре.

В приведенном ниже примере, на основе некоторых данных, существуют циклы for, используемые для создайте новую переменную list_zz.

Данные и код for-l oop:

import pandas as pd
import numpy as np
from collections import defaultdict
from itertools import permutations

list_type = [['A', 'B'], ['B'], ['A', 'B', 'C', 'D', 'E'], ['B'], ['A', 'B', 'C'], ['A'], ['B', 'C'], ['A', 'B'], ['C', 'A', 'B'], ['A'], ['B', 'C']]

list_xx = [[1.0, 5.0], [3.0], [2.0, 7.0, 3.0, 1.0, 6.0], [3.0], [5.0, 2.0, 3.0], [1.0], [9.0, 3.0], [2.0, 7.0], [3.0, 6.0, 8.0], [2.0], [7.0, 9.0]]

list_zz= []
#for-loop
wd = defaultdict(float)
for i, x in zip(list_type, list_xx):
    # staff 1
    if len(i) == 1:
        #print('NaN')
        list_zz.append(np.nan)
        continue
    # Pairs and difference generator for current game (i)
    pairs = list(permutations(i, 2))
    dgen = (value[0] - value[1] for value in permutations(x, 2))
    # Sum of differences from previous games incluiding only pair of teams in the current game
    for team, result in zip(i, x):
        win_comp_past_difs = sum(wd[key] for key in pairs if key[0] == team)
        #print(win_comp_past_difs)
        list_zz.append(win_comp_past_difs)
    # Update pair differences for current game
    for pair, diff in zip(pairs, dgen):
        wd[pair] += diff
print(list_zz)

Что выглядит следующим образом:

[0.0,
 0.0,
 nan,
 -4.0,
 4.0,
 0.0,
 0.0,
 0.0,
 nan,
 -10.0,
 13.0,
 -3.0,
 nan,
 3.0,
 -3.0,
 -6.0,
 6.0,
 -10.0,
 -10.0,
 20.0,
 nan,
 14.0,
 -14.0]

Если Вы могли бы разработать код, чтобы сделать его более эффективным и выполнять быстрее, я был бы очень признателен.

1 Ответ

1 голос
/ 16 февраля 2020

Не рассматривая общий дизайн вашего кода, у меня появляется одно улучшение: переместите ваш код в функцию.

Как написано в настоящее время, все переменные, которые вы используете, являются глобальными переменными. Из-за динамической c природы глобального пространства имен, Python должен искать каждую глобальную переменную, которую вы используете каждый раз, когда вы используете доступ к ней. (1) В CPython, это соответствует поиску таблицы ha sh, что может быть дорогостоящим, особенно если присутствуют коллизии ha sh.

Напротив, локальные переменные могут быть известны во время компиляции и хранятся в массиве фиксированного размера. Следовательно, доступ к этим переменным включает только разыменование указателя, что сравнительно намного быстрее.

С учетом этого принципа вы сможете повысить производительность (где-то примерно на 40% во время выполнения), перемещая все Вы вводите свой код в «основную» функцию:

def main():
    ...
    # Your code here

if __name__ == '__main__':
    main()

(1) Источник

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...