Я пытаюсь улучшить производительность функции ниже
import numpy as np
import time
r_0 = 0.1
drt_measurement = 9.999999999999991269e+04 3.305791191233514031e-02
9.083278409243831993e+04 6.686534998595229651e-02
1.569368719222600794e-01 7.259131510582693403e-02
1.425501300345730638e-01 1.423914344911824392e-01
1.294822518377939102e-01 2.296111516784170581e-01
1.176123342498509028e-01 3.236305655613548882e-01
1.068305576352440167e-01 4.110383626909880905e-01
9.703716976156935570e-02 4.774860553090806148e-01
8.814156289893920748e-02 5.096622216542943118e-01
8.006143552369422711e-02 4.972726694760475352e-01
7.272203087054407433e-02 4.349122174992410828e-01
6.605544528827768380e-02 3.237240623831713071e-01
5.999999999999999778e-02 1.727623254500962879e-01
def backcalculate_impedance_from_drt_freq(drt_measurement, r_0):
# Extract frequency and DRT from drt_measurement matrix
drt_frequency = drt_measurement[:,0]
drt = drt_measurement[:,1]
# Frequency to angular frequency, ω, and scaling factor
ω_drt = -np.log(2*np.pi*drt_frequency)
ds = ω_drt[2] - ω_drt[1] # ds is a constant
# Unscaling the DRT
unscaled_drt = drt*ds
# Initializing Zreal and ZImag vectors
ZReal = np.empty((len(drt_frequency),1))
ZImag = np.empty((len(drt_frequency),1))
print("\nBackImpedance For loop")
tic = time.time()
# Solve for ZReal and ZImag
for i in range(len(drt_frequency)):
K1 = 1 / (1 + np.exp(2 * (-ω_drt[i] + ω_drt))) * unscaled_drt
K2 = -np.exp(-ω_drt[i] + ω_drt) * K1
ZReal[i,0] = sum(K1) + r_0
ZImag[i,0] = sum(K2)
toc = time.time()
diff = toc - tic
print(f'Executed in {diff} seconds or {diff*1000} milliseconds')
# Save Backcalculated Impedance into a (x,3) matrix
drt_frequency = drt_frequency[:,None]
backcalculated_impedance = np.hstack((drt_frequency,ZReal,ZImag))
return backcalculated_impedance
В настоящее время я получаю около 10 мс каждый раз, когда эта функция вызывается, причем большую часть времени приходится на цикл for, что действительно замедляет общее выполнение. Есть ли лучшая альтернатива циклу for или способ векторизации его операций?
используйте np.sum вместо sum. Я думаю, это ваше узкое место. Кроме того, вы можете использовать line_profiler, чтобы найти узкие места.
Я использовал np.sum, и он стал в 2 раза быстрее. Переход от ~ 10 мс до ~ 5 мс. В конце концов я воспользовался решением Кристофа и реализовал ваше предложение использовать в нем np.sum. Спасибо @dankal444






Функцию можно переписать без цикла for, используя векторизацию:
def backcalculate_impedance_from_vectorized(drt_measurement, r_0):
drt_frequency, drt = drt_measurement[:, 0], drt_measurement[:, 1]
ω_drt = -np.log(2 * np.pi * drt_frequency)
ds = ω_drt[2] - ω_drt[1]
unscaled_drt = drt * ds
ω_drt_expanded = ω_drt[:, np.newaxis]
K1 = 1 / (1 + np.exp(2 * (-ω_drt_expanded + ω_drt))) * unscaled_drt
ZReal = K1.sum(axis=1) + r_0
ZImag = (-np.exp(-ω_drt_expanded + ω_drt) * K1).sum(axis=1)
return np.hstack((drt_frequency[:, np.newaxis], ZReal[:, np.newaxis], ZImag[:, np.newaxis]))
Насколько это быстрее?
Я попробовал ваше решение и изменил сумму на np.sum. Теперь он работает примерно в 10 раз быстрее, чем моя первоначальная версия. Огромное спасибо @Christoph!
@impedance_gatto, пример Кристофа намного быстрее, чем метод цикла for, но результаты неверны. Сравните полученный результат с результатом исходной функции.
@ Скотт Вайс. Спасибо, что упомянули об этом. Чтобы получить правильные результаты, код должен иметь «-ω_drt_expanded + ω_drt» вместо «ω_drt_expanded — ω_drt».
@impedance_gatto, хороший улов. Теперь я вижу, что решение Кристофа правильное после этой замены. Я внес это изменение в его решение.
Вы должны описать, что вы пробовали до сих пор (особенно в отношении векторизации, которая является подходящим способом и должна работать хорошо).