Ваша проблема в том, что вы используете numpy
неправильно, потому что numpy
- это все векторизованные вычисления, такие как MATLAB
.Рассмотрим следующую модификацию вашего кода.Я заменил ваш цикл над массивом Numpy на простой код Numpy, который эффективно использует векторизацию для 2d массивов.В результате код работает в 100 раз быстрее.
import functools
import numpy as np
import time
# decorator to measure running time
def measure_running_time(echo=True):
def decorator(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
t_1 = time.time()
ans = func(*args, **kwargs)
t_2 = time.time()
if echo:
print(f'{func.__name__}() running time is {t_2 - t_1:.2f} s')
return ans
return wrapped
return decorator
def euc_distance(array1, array2):
return np.power(np.sum((array1 - array2) ** 2), 0.5)
# original function
@measure_running_time()
def calculate_TP_1(N, data2, D, Dradius, NormAttListTest, TP=0):
for i in range(N):
for j, n in enumerate(data2):
distance = euc_distance(n, D[i])
if distance < Dradius[i] and NormAttListTest[j] == "Attack":
TP += 1
return TP
# new version
@measure_running_time()
def calculate_TP_2(N, data2, D, Dradius, NormAttListTest, TP=0):
# this condition is the same for every i value
NormAttListTest = np.array([val == 'Attack' for val in NormAttListTest])
for i in range(N):
# don't use loop over numpy arrays
# compute distance for all the rows
distance = np.sum((data2 - D[i]) ** 2, axis=1) ** .5
# check conditions for all the row
TP += np.sum((distance < Dradius[i]) & (NormAttListTest))
return TP
if __name__ == '__main__':
N = 10
NN = 100_000
D = np.random.randint(0, 10, (N, 5))
Dradius = np.random.randint(0, 10, (N,))
NormAttListTest = ['Attack'] * NN
NormAttListTest[:NN // 2] = ['Defence'] * (NN // 2)
data2 = np.random.randint(0, 10, (NN, 5))
print(calculate_TP_1(N, data2, D, Dradius, NormAttListTest))
print(calculate_TP_2(N, data2, D, Dradius, NormAttListTest))
Вывод:
calculate_TP_1() running time is 7.24 s
96476
calculate_TP_2() running time is 0.06 s
96476