Применить функцию прямоугольной волны к массиву numpy

#python #numpy #scipy

#python #numpy #scipy

Вопрос:

Я могу быстро применить функцию cos следующим образом к массиву numpy с плавающей точкой 32:

  cos_f = np.vectorize(lambda x: math.cos(2 * math.pi * x))
 signal = square_f(integral)
  

Однако, если я попробую это:

  square_f = np.vectorize(lambda x: sig.square(2 * math.pi * x))
 signal = square_f(integral)
  

для 60 000 выборок требуется 15 секунд. integral имеет длину 1024 и используется в качестве буфера.

Как я должен применять квадратную волну к своему сигналу?

Комментарии:

1. Откуда sig.square() берется? Это код, который вы написали или импортировали из другой библиотеки?

2. пожалуйста, укажите все переменные, которые вы используете в своем коде

3. signal одинаково в обеих попытках. Это опечатка?

Ответ №1:

Я не уверен, что вам np.vectorize вообще нужно здесь:

 import numpy as np
from scipy import signal as sig

integral = np.linspace(0, 10, 1024)
signal1 = np.cos(2*np.pi * integral)
signal2 = sig.square(2*np.pi * integral)
  

Вы, конечно, также можете создать функцию, а затем вызвать ее с
помощью массива в качестве входных данных:

 def cos2pi(x):
    return np.cos(2*np.pi * x)

signal1 = cos2pi(integral)
  

И можно пойти еще дальше и вызвать функцию только один раз для всех выборок одновременно.

 samples = np.random.random((60000, 1024))
signal1 = cos2pi(samples)
  

Комментарии:

1. Есть ли какие-либо случаи, когда np.vectorize стоит использовать вообще?

Ответ №2:

sig.square(2*np.pi * x) в три раза медленнее, чем np.cos(2*np.pi * x) , однако, это не является узким местом здесь. Это красивое np.vectorize оформление на самом деле стоит 120-кратного замедления! Причина, по которой это происходит, заключается в том, что square_f применяется scipy.signal.square к итеративным элементам, что представляет собой набор алгоритмов, предназначенных для работы с массивами (в отличие math.cos от). Это пример арифметики, выполняемой внутри scipy.signal.square :

 def example(x, w=0.5):
    return (1 - (w > 1) | (w < 0)) amp; (np.mod(x, 2 * pi) < w * 2 * np.pi)
  

Предполагая arr , что это большой массив, это, очевидно, более эффективно вызывать example(arr) вместо

 ex = np.vectorize(lambda x: example(x))
ex(arr)
  

Тайминги также показывают это:

 arr = np.linspace(0,1,1000000)
%timeit ex(arr)
%timeit example(arr)
8.13 s ± 208 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
18.5 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)