Есть ли более элегантный способ создания этих numpy массивов? - PullRequest
0 голосов
/ 07 марта 2020

Мне кажется, что я создаю слишком много массивов и трачу ресурсов, поэтому я ищу более чистый и эффективный подход для решения следующей проблемы:

Предположим, у нас есть колебательный график, и мы знаем, позиции минимумов (min_x˛) и максимумов (max_x). Мы выбираем контрольную точку ref_point (около 2,35 на рисунке ниже), а ближайшим экстремальным значениям (2,25 и 2,45 на рисунке) мы назначаем 1 * PI, вторым ближайшим экстремальным значениям мы присваиваем значение 2 * PI , и так далее. Таким образом, мы получаем нижний график на рисунке (обратите внимание, что значения смещены на -4 * PI, но это пока не имеет значения).

This figure helps

Вот мое решение:

import numpy as np

def min_max(ref_point, min_x, max_x):

    # finding the maximum and minimum values which are smaller than reference point
    neg_max_freq = np.array([a for a in (ref_point - max_x) if a < 0])
    neg_min_freq = np.array([b for b in (ref_point - min_x) if b < 0])

    # joining them together and flipping order
    neg_freq = sorted(np.append(neg_max_freq, neg_min_freq), reverse=True)

    # finding the maximum and minimum values which are greater than reference point
    pos_max_freq = np.array([c for c in (ref_point - max_x) if c > 0])
    pos_min_freq = np.array([d for d in (ref_point - min_x) if d > 0])

    #joining them together
    pos_freq = sorted(np.append(pos_min_freq, pos_max_freq))


    pos_values = np.array([np.pi * (i+1) for i in range(len(pos_freq))])
    neg_values = np.array([np.pi * (i+1) for i in range(len(neg_freq))])

    # joining the values for the lower graph on the picture
    x_s = np.append(pos_freq, neg_freq)
    y_s = np.append(pos_values, neg_values)

    return x_s, y_s

Пример использования:

>>> min_x = np.arange(np.pi/2, 4.5*np.pi, np.pi)
>>> max_x = np.arange(0, 4*np.pi, np.pi)
>>> x, y = min_max(0, min_x, max_x)

>>> x
[ -1.57079633  -3.14159265  -4.71238898  -6.28318531  -7.85398163
  -9.42477796 -10.99557429]

>>> y
[ 3.14159265  6.28318531  9.42477796 12.56637061 15.70796327 18.84955592
 21.99114858]

Есть ли еще более эффективный способ достижения того же результата?

1 Ответ

1 голос
/ 07 марта 2020

Вот как я бы изменил код min_max, не записывая так много временных переменных и избегая списков:

def min_max(ref_point, min_x, max_x):

    max_freq = ref_point - max_x
    min_freq = ref_point - min_x

    # Faster sort
    neg_freq = np.sort(np.append(max_freq[max_freq<0], min_freq[min_freq<0]))[::-1]
    pos_freq = np.sort(np.append(max_freq[max_freq>0], min_freq[min_freq>0]))

    pos_values = np.pi * np.arange(1, len(pos_freq)+1)
    neg_values = np.pi * np.arange(1, len(neg_freq)+1)

    x_s = np.append(pos_freq, neg_freq)
    y_s = np.append(pos_values, neg_values)

    return x_s, y_s

Что касается производительности сортировки, я тестировал случайный массив размером 1 миллион, вот результаты :

a = np.random.randint(0, 1000, 1_000_000)

%timeit sorted(a, reverse=True)
522 ms ± 29.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit np.sort(a)[::-1]
55.2 ms ± 958 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

numpy в 9,5 раз быстрее, чем ваниль python.

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