Эффективное присвоение значения numpy с помощью логической маски

0

Вопрос

У меня есть проблема с присвоением значения логической маски, требующая эффективной операции с логической маской.

Это многомерная маска, и я использую einsum для достижения результата, но операция не очень эффективна, и мне интересно, смогу ли я получить некоторую помощь в этом Вот мое текущее решение: (оба mask, truth_value, false_value являются фиктивными данными с типом dtype и формой, соответствующими моей проблеме.

mask = np.random.randn(1000, 50)> 0.5
truth_value = np.random.randn(50, 10)
false_value = np.random.randn(10)
objective = np.einsum('ij,jk->ijk', mask, truth_value) + np.einsum('ij,k->ijk', ~mask, false_value)

Есть ли какой-нибудь более быстрый способ добраться objective подаренный mask, truth_value, false_value ?

Пока я ждал, придумал более быстрый способ

objective = np.where(mask[...,np.newaxis], np.broadcast_to(truth_value, (1000, 50, 10)), np.broadcast_to(false_value,  (1000, 50, 10)))

Но есть ли более быстрая альтернатива ?

mask numpy python
2021-11-21 23:00:26
1

Лучший ответ

0

Вы можете использовать JIT Numba, чтобы сделать это более эффективно.

import numpy as np
import numba as nb

@nb.njit('float64[:,:,::1](bool_[:,::1], float64[:,::1], float64[::1])')
def blend(mask, truth_value, false_value):
    n, m = mask.shape
    l = false_value.shape[0]
    assert truth_value.shape == (m, l)
    result = np.empty((n, m, l), dtype=np.float64)
    for i in range(n):
        for j in range(m):
            if mask[i, j]:
                result[i, j, :] = truth_value[j, :]
            else:
                result[i, j, :] = false_value[:]
    return result

mask = np.random.randn(1000, 50) > 0.5
truth_value = np.random.randn(50, 10)
false_value = np.random.randn(10)
objective = blend(mask, truth_value, false_value)

Вычисление objective на моей машине это в 4,8 раза быстрее.

Если это недостаточно быстро, вы можете попробовать распараллелить код с помощью параметра parallel=True и используя nb.prange вместо range в цикле на основе i. Это может быть не быстрее из-за накладных расходов на создание новых потоков. На моей машине (с 6 ядрами) параллельная версия в 7,4 раза быстрее (создание потоков довольно дорого по сравнению со временем выполнения).

Другая возможная оптимизация заключается в прямой записи результата в буфер, выделенный заранее (это лучше, только если вы вызываете эту функцию несколько раз с одинаковым размером массива).

Вот общие тайминги на моей машине:

np.einsum:         4.32 ms
np.where:          1.72 ms
numba sequential:  0.89 ms
numba parallel:    0.58 ms
2021-11-21 23:52:43

Спасибо! это действительно быстрее, чем мой einsum решение! немного быстрее, чем мой np.where +np.broadcast_to решение на основе.
yupbank

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................