#python #arrays #numpy
#python #массивы #numpy
Вопрос:
Мне приходится иметь дело с анализом чувствительности, который необходимо ускорить. Данные задаются в массиве numpy, назовем его A
. A
получил форму (M, N)
, где M
— количество точек данных и N
— количество атрибутов, из которых состоит каждая точка данных и на основе которых должен быть вычислен анализ. Для простоты давайте предположим M=2, N=4
. Имейте M=1 e9
в виду что-то подобное. В любом случае. Пусть a_{mn}
будет элементом A
. Анализ должен выполняться для f(a_{m1},a_{m2}, a_{m3}, a_{m4}) = a_{m1} - a_{m2} - ( a_{m3} * a_{m4} )
вычисления функций для каждой строки, чтобы это f(A)
приводило к B
форме массива (M,1)
. So b_m
является элементом B
.
Хотите создать E
форму массива (M, N)
, содержащую чувствительность для каждого элемента B
в целом. например, элемент e: m=1 an n=2, e_{mn}= e_{12} = f(a_{11},a_{12}*(1-i), a_{13}, a_{14}) - b_1
Теперь поиск чувствительности каждого элемента включен B
. Пусть чувствительность i
будет i=0.05
. Прежде всего, я вычислил массив формы (M, N)
, который содержит все элементы и его изменение. Давайте назовем это C = B * i
, где *
это поэлементное умножение. После этого, создавая D
, я перебирал каждый отдельный элемент в массиве. Наконец-то вычтено B
, чтобы получить E
. Я думаю, это слишком дорого и очень дешево. Вот почему он не работает с огромным объемом данных. Вот что я получил:
import numpy as np
A = np.array([
[2., 2., 100., 0.02],
[4., 2., 100., 0.02]
])
def f_from_array(data):
att_1 = data[:, 0]
att_2 = data[:, 1]
att_3 = data[:, 2]
att_4 = data[:, 3]
return ((att_1 - att_2) - (att_3 * att_4)).reshape(-1, 1)
def f_from_list(data):
att_1 = data[0]
att_2 = data[1]
att_3 = data[2]
att_4 = data[3]
return ((att_1 - att_2) - (att_3 * att_4)).reshape(-1, 1)
B = f_from_array(A)
# B = np.array([
# [-2.],
# [0.]
# ])
i = 0.05
C = A * i
A_copy = A * 1
D = np.zeros(A.shape)
for m in range(A.shape[0]):
for n in range(A.shape[1]):
A_copy[m][n] -= C[m][n]
D[m][n] = f_from_list(A_copy[m])
A_copy = A * 1
E = D - B
E = np.sqrt(E**2)
Вывод:
E = np.array([
[0.1, 0.1, 0.1, 0.1],
[0.2, 0.1, 0.1, 0.1]
])
Комментарии:
1.
$A$
Почему вы используете эту нотацию?2. Нотация LaTeX — интересно, stackoverlow не справляется с этим. Удалит эти $ link
3. Обозначения и, следовательно, описание того, что вы намереваетесь вычислить, довольно сложно прочитать тому, кто знает только Python, но не LaTeX. Возможно, было бы полезно отформатировать его с помощью синтаксиса Python / Numpy.
4. Справедливое замечание. Там я добавил код запуска, который ваш ответ ниже немного ускорил. Спасибо за это, но, как вы упомянули, циклы могут быть полностью устранены. Как это сделать?
5. Конечно, можно отказаться от кода, но также было бы неплохо иметь возможность проверить, действительно ли код делает то, что вы хотите. Например, я не уверен в последней строке (строках):
np.sqrt(E ** 2)
в основном такой же, какnp.abs(E)
для действительных чисел. Скорее всего, вы имели в виду что-то вродеnp.sqrt((E ** 2).mean(axis=0))
, что является среднеквадратичным значением по столбцам.
Ответ №1:
Очевидно, что проблемной частью вашего кода является вложенный цикл for . Здесь можно многое сделать, и, вероятно, возможно полностью исключить цикл.
Но, не задумываясь слишком много о том, что делает код, наиболее очевидным убийцей времени, вероятно, является то, что вы создаете копию всего массива во время каждой итерации цикла. Устраните это, просто восстановив один элемент вместо всего массива.
Вместо
A_copy = A * 1
внутри цикла сделайте это:
A_copy[m, n] = A[m, n]
(В качестве отступа: индексирование с помощью запятой выполняется немного быстрее, чем многоступенчатое индексирование с использованием более чем одной пары скобок, но это, вероятно, будет незначительным для вашего случая.)