Этот вопрос похож на this.numpy 2d булевая индексация массива с уменьшением вдоль одной оси
У меня есть 2d булевский массив «принадлежать» и 2d поплавковый массив «углы». То, что я хочу, состоит в том, чтобы суммировать вдоль строк углы, для которых принадлежит соответствующий индекс, - True, и делать это с помощью numpy (т. Е. Избегать циклов питона). Мне не нужно сохранять результирующие строки, которые будут иметь разную длину, и, как объяснено в связанном вопросе, потребуется список.
Так что я попытался сделать np.sum (углы [принадлежат], ось = 1), но углы [принадлежат] возвращают 1d результат, и я не могу уменьшить его, как я хочу. Я также попробовал np.sum (углы * принадлежат, ось = 1), и это работает. Но мне интересно, могу ли я улучшить время, обратившись только к индексам, где принадлежит True. принадлежат Истине около 30% времени, а углы - это упрощение более длинной формулы, которая включает в себя углы.
UPDATE
Мне нравится решение с einsum, однако в моем фактическом вычислении скорости до крошечные. Я использовал углы в вопросе, чтобы упростить, на практике это формула, которая использует углы. Я подозреваю, что эта формула рассчитана для всех углов (независимо от их принадлежности), а затем передается в einsum, которая будет выполнять вычисление.
Это то, что я сделал:
THRES_THETA и max_line_length являются поплавки. принадлежат, угол и lines_lengths_vstacked имеют форму (1653, 58) и np.count_nonzero (принадлежат) /belong.size -> +0,376473287856979
l2 = (lambda angle=angle, belong=belong, THRES_THETA=THRES_THETA, lines_lengths_vstacked=lines_lengths_vstacked, max_line_length=max_line_length:
np.sum(belong*(0.3 * (1-(angle/THRES_THETA)) + 0.7 * (lines_lengths_vstacked/max_line_length)), axis=1)) #base method
t2 = timeit.Timer(l2)
print(t2.repeat(3, 100))
l1 = (lambda angle=angle, belong=belong, THRES_THETA=THRES_THETA, lines_lengths_vstacked=lines_lengths_vstacked, max_line_length=max_line_length:
np.einsum('ij,ij->i', belong, 0.3 * (1-(angle/THRES_THETA)) + 0.7 * (lines_lengths_vstacked/max_line_length)))
t1 = timeit.Timer(l1)
print(t1.repeat(3, 100))
l3 = (lambda angle=angle, belong=belong:
np.sum(angle*belong ,axis=1)) #base method
t3 = timeit.Timer(l3)
print(t3.repeat(3, 100))
l4 = (lambda angle=angle, belong=belong:
np.einsum('ij,ij->i', belong, angle))
t4 = timeit.Timer(l4)
print(t4.repeat(3, 100))
и результаты были:
[0.2505458095931187, 0.22666162878242901, 0.23591678551324263]
[0.23295411847036418, 0.21908727226505043, 0.22407296178704272]
[0.03711204915708555, 0.03149960399994978, 0.033403337575027114]
[0.025264803208228992, 0.022590580646423053, 0.024585736455331464]
Если мы посмотрим в последних двух строках, соответствующая einsum, примерно на 30% быстрее, чем при использовании базового метода. Но если мы посмотрим на первые две строки, скорость для метода einsum будет меньше, примерно на 0,1% быстрее.
Я не уверен, что это время можно улучшить.
Спасибо за ваш ответ.Подход einsum выглядит очень интересным. Однако в фактическом расчете я делаю увеличение скорости использования einsum vs на основе крошечного. Я думаю, это может быть потому, что вместо углов у меня есть большая операция, которую все равно нужно вычислить для всей матрицы, прежде чем войти в einsum. Я отредактирую свой вопрос, чтобы показать результаты своих тестов с помощью einsum и фактической формулы, содержащей углы – martinako