Кусочная функция Numpy работает медленно в scipy quad

Я пытался измерить время, затраченное на оценку математической функции, как простым, так и питоническим способом. Во-первых, я измерил, сколько времени требуется для оценки функции.

import numpy as np
import scipy as sp
import scipy.integrate as si



def func1(x):
    return np.piecewise(x, [x<=2, x>2],
                    [lambda x: 2*x + pow(2, x),
              lambda x: -(pow(x, 2) + 2)]
                       )
def func2(x):
    if (x<=2): return 2*x + pow(2,x)
    else: return -(pow(x, 2) + 2)

data = np.linspace(-10, 10, 1000)
%timeit data1 = func1(data)
data2 = []
%timeit for i in range(0, np.size(data)): data2.append(func2(data[i]))

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

35.2 µs ± 110 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
771 µs ± 10.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Однако в scipy.integrate.quad происходит странная вещь. Скорость интеграции была намного выше в базовом питоническом стиле. Почему так?

%timeit si.quad(func1, -10, 10)
%timeit si.quad(func2, -10, 10)

5.59 ms ± 25.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
187 µs ± 39.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Если производительность имеет значение, используйте низкоуровневый вызываемый объект для интеграции. Это превзойдет стандартный способ Python как минимум на порядок. например. stackoverflow.com/a/50097776/4045774

max9111 02.05.2018 12:22
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
352
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

np.piecewise работает быстро только при использовании векторизации. Когда входные данные являются скалярными, он намного медленнее, чем эквивалент Python, предположительно из-за накладных расходов:

from timeit import timeit
kwds = dict(globals=globals(), number=1000)

print(timeit("data1 = func1(data)", **kwds))
data2 = []
print(timeit("for i in range(0, np.size(data)): data2.append(func2(data[i]))", **kwds))
data3 = []
print(timeit("for i in range(0, np.size(data)): data3.append(func1(data[i]))", **kwds))

0.06953751016408205
0.957529284991324
15.591511018108577

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

Другие вопросы по теме