Как мне сделать эту функцию более эффективной? (крикет статистика) - PullRequest
0 голосов
/ 17 октября 2019

Я пишу функцию batting_stats , чтобы показать статистику ватина для каждой возможности на протяжении всей карьеры игрока с битой. Входными данными для функции является список списков целых чисел. Список верхнего уровня содержит список подач, в то время как внутренние списки содержат забитые запуски, шары, с которыми сталкиваются, и логическое значение (1 = нет или 0 = нет), указывающее, был ли игрок с битой уволен во время подачи. Функция состоит в том, чтобы возвращать список целых чисел, представляющих среднее число игроков с битой, коэффициент удара и коэффициент конверсии для каждого из этих источников.

Среднее = выполняется // увольнения (Если игрокне отбрасывается, среднее значение - это общее количество набранных пробежек)

Скорость удара = 100 * пробежек // столкновение с шарами

Коэффициент конверсии = 100 *количество забитых веков / количество 50+ очков. (Если у игрока нет очков больше пятидесяти, коэффициент конверсии равен нулю)

Input Format:
[[r1,b1,d1],[r2,b2,d2],...]
where r=runs, b=balls, d=dissmissal

Output Format:
[[avg1,sr1,cr1],[avg2,sr2,cr2],...]
where avg=average, sr=strike rate, cr=conversion rate

Например:

>>> batting_stats([[12,24,0],[18,36,1]])
[[12,50,0],[30,50,0]]

Мой код дает мне ожидаемые результаты, но, по-видимому, реализациюне оптимально. Я получаю ошибки тайм-аута для очень больших входов. Как я могу оптимизировать это?

def batting_stats(lst):
    """Compute the average, strike rate, and conversion rate of a batsman after each innings."""
    innings = len(lst)  # number of innings
    last = 1 + innings
    r_lst = [r[0] for r in lst]  # list of runs per innings
    b_lst = [b[1] for b in lst]  # list of balls faced per innings
    d_lst = [d[2] for d in lst]  # list of dismissals per innings
    c_lst = [1 if r >= 100 else 0 for r in r_lst]  # list of 100+ scores
    f_lst = [1 if r >= 50 else 0 for r in r_lst]  # list of 50+ scores

    # Keep track of sums after each innings
    rt = [sum(r_lst[:n]) for n in range(1, last)]  # runs scored
    bt = [sum(b_lst[:n]) for n in range(1, last)]  # balls faced
    dt = [sum(d_lst[:n]) for n in range(1, last)]  # dismissals
    ct = [sum(c_lst[:n]) for n in range(1, last)]  # 100+ scores
    ft = [sum(f_lst[:n]) for n in range(1, last)]  # 50+ scores

    avg_ = [rt[i] if dt[i] == 0 else rt[i] // dt[i] for i in range(innings)]  # averages after each innings
    sr_ = [100 * rt[i] // bt[i] for i in range(innings)]  # strike rates after each innings
    cr_ = [0 if ft[i] == 0 else 100 * ct[i] // ft[i] for i in range(innings)]  # conversion rates after each innings

    return [[avg_[i], sr_[i], cr_[i]] for i in range(innings)]

1 Ответ

1 голос
/ 18 октября 2019

Я использовал комбинацию предложения Даниэля Месехо (используя itertools.accumulate) и unzip из модуля more_itertools, чтобы изменить вашу функцию (простите за переформатирование / переименование -это было для моей собственной читабельности). Я также довольно либерально использовал zip.

def batting_stats2(lst):
    """Compute the average, strike rate, and conversion rate of a batsman after each innings."""
    innings = len(lst)  # number of innings
    # Not needed
    #last = 1 + innings

    # Unzip reshapes the various stats into their own lists
    r_lst, b_lst, d_lst = map(list, unzip(lst))

    # Similarly, for the 100+ and 50+ scores
    # Note: int(True) = 1, int(False) = 0
    c_lst, f_lst = map(list, unzip((int(r >= 100), int(r >= 50)) for r in r_lst))

    # Accumulate the sums
    rt = list(accumulate(r_lst)) # list of runs per innings
    bt = list(accumulate(b_lst)) # list of balls faced per innings
    dt = list(accumulate(d_lst)) # list of dismissals per innings
    ct = list(accumulate(c_lst)) # list of 100+ scores
    ft = list(accumulate(f_lst)) # list of 50+ scores

    # averages after each innings
    avg_ = [run if dismiss == 0 else run // dismiss for run, dismiss in zip(rt, dt)]

    # strike rates after each innings
    sr_ = [100 * run // ball for run, ball in zip(rt, bt)]

    # conversion rates after each innings
    cr_ = [fifty if fifty == 0 else 100 * hundo // fifty for fifty, hundo in zip(ft, ct)]

    # The "list(x)" is because your output is nested lists. Without, it would be
    # list of tuples.
    return list(list(x) for x in zip(avg_, sr_, cr_))

Затем я проверил ваш опубликованный пример и получил тот же результат, так что кажется, что он вычисляется правильно.

Впоследствии я рассчитал его с помощью ввода 1000000 списков из трех участников (называемых stats):

>>> %%timeit
>>> batting_stats2(stats)

2.43 s ± 35.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Я также пытался рассчитать время оригинала, но сдался после ожидания в течение 10 минут:)

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