Eficiente numpy atribuição de valor através de máscara booleana

0

Pergunta

Eu tenho um boolean valor de máscara de atribuir o problema requer eficiente boolean máscara de operação.

É um multi-dimensão máscara e eu estou usando einsum para atingir o resultado, mas a operação não é muito eficiente, e eu estou querendo saber, se eu posso obter alguma ajuda com isso Aqui está a minha solução atual: (tanto mask, truth_value, false_value são dados fictícios com dtype e de forma de jogos para o meu problema.

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)

Existe alguma maneira mais rápida para obter objective dado mask, truth_value, false_value ?

Enquanto eu estava esperando, descobriu uma maneira mais rápida

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

Mas existe alguma alternativa mais rápida ?

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

Melhor resposta

0

Você pode usar o Numba JIT para fazer isso de forma mais eficiente.

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)

O cálculo de objective é 4,8 vezes mais rápido na minha máquina.

Se isso não for rápido o suficiente, você pode tentar para paralelizar o código usando o parâmetro parallel=True e usando nb.prange em vez de range no i ciclo. Este pode não ser o mais rápido, devido à sobrecarga de criação de novas threads. Na minha máquina (com 6 núcleos), a versão paralela de 7,4 vezes mais rápido (a criação de threads é muito caro em comparação com o tempo de execução).

Outra possível otimização é escrever diretamente o resultado em um buffer alocado antes do tempo (este é somente o melhor, se você chamar essa função várias vezes com o mesmo tamanho do array).

Aqui estão o total de intervalos na minha máquina:

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

obrigado! este é de fato mais rápido do que o meu einsum solução! um pouco mais rápido do que o meu np.where +np.broadcast_to solução.
yupbank

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................