definir una firma numposa para la matriz de salida de longitud desconocida (para uso en numba.guvectorize)
Es posible crear una firma para un numpy
ufunc
que devuelve una matriz de 1d de longitud desconocida?
Tengo una función que toma en un array x
de longitud (n)
y una matriz de etiquetas y
de longitud (m)
, realiza una reducción y devuelve el array out
de tamaño desconocido.
La función misma se envuelve con numba.guvectorize
:
@guvectorize([(int16[:], float64[:], int32[:], int16[:])], "(n),(m) -> (l)", nopython=True)
def fun(x, y, out):
#perform stuff
# ...
# no return in guvectorize
Esto devuelve el siguiente error:
NameError: símbolos de salida no definidos: l
Mi solución sería pasar en un conjunto de plantillas de longitud l
Pero no se usaría para ningún cálculo, así que me gustaría evitarlo.
¿Alguna manera alrededor de esto, o está pasando en una plantilla la mejor (y tal vez no tan mala) solución?
Editar:
Algunos puntos válidos hechos en los comentarios que quiero abordar:
Se supone que la función se aplique en un array con dimensiones (x, y, z)
a lo largo z
dimensión, que tiene longitud n
.
El propósito previsto de la función es tomar cada matriz 1d a lo largo de z
[z,z,z,z,z,z,z,z,...,z]
y ampliarlo a la longitud m
[z1,z1,z1,z2,z2,z2,z2,z3,...,zz]
y finalmente los valores correspondientes se promedian
[z1,z2,z3,z4,z5,z6,z7,z8,...,zz]
resultante en un array con longitud l
.
Sé de antemano exactamente qué tamaños m
, n
y l
será - solo necesito "tell" a la función. Es por eso que tampoco espero salidas.
La manera más rápida de aplicar esto a un gran array 3d usando xarray
está con guvectorize
. Pero esto resulta en la cuestión anterior.
Una solución de trabajo es pasar en una plantilla de longitud l
.
Para comparación, he creado un @njit
función envuelta, que manualmente bucles sobre la primera dos dimensiones, aplicando la misma funcionalidad.
Desafortunadamente esto sigue siendo aproximadamente 4 veces más lento que el uso guvectorize
Así que me gustaría usar guvectorize
para esta aplicación.
Pregunta hecha hace 3 años, 5 meses, 6 días - Por rubyrogue
2 Respuestas:
-
Para definir una firma numposa para la matriz de salida de longitud desconocida en
numba.guvectorize
, puedes utilizar una firma numposal->()
en lugar de"(n),(m) -> (l)"
. Esto indica que la longitud de la matriz de salida es desconocida y será determinada durante la ejecución de la función.Aquí tienes un ejemplo de cómo podrías ajustar tu decorador
guvectorize
:python from numba import guvectorize, float64, int32, int16 @guvectorize([(int16[:], float64[:], int32[:])], "(),() -> ()", nopython=True) def fun(x, y, out):
Realiza la reducción y asigna el resultado a 'out'
out[0] = 0Aquí se asignaría el resultado de la reducción
Ejemplo de uso
x = np.array([1, 2, 3], dtype=np.int16) y = np.array([0.1, 0.2, 0.3], dtype=np.float64) out = np.empty(1, dtype=np.int32) fun(x, y, out) print(out)Al especificar la firma numposa
(l->())
, le estás diciendo a la funciónguvectorize
que la longitud de la matriz de salida se determinará dinámicamente en tiempo de ejecución.Espero que esta solución te ayude a resolver el problema que estás experimentando. ¡Déjame saber si tienes alguna otra pregunta!
Respondida el Dec 18, 2020 a las 10:06 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
Sí, es posible crear una firma para un
numpy
ufunc
que devuelve una matriz 1D de longitud desconocida. Aquí hay un ejemplo usandonumba.guvectorize
:python import numpy as np from numba import guvectorize @guvectorize([(np.int16[:], np.float64[:], np.int32[:], np.int16[:])], "(n),(m) -> ()", nopython=True) def fun(x, y, out):
Realizar cálculos
...
Asignar el resultado a la matriz de salida
out[()] = resultadoEn esta firma, el tipo de retorno se especifica como
()
para indicar que no se devuelve ningún valor explícito. En su lugar, el resultado se asigna directamente a la matriz de salida proporcionada pornumba.guvectorize
.Tenga en cuenta que la función
fun
debe ser pura, es decir, no debe modificar ningún dato de entrada o variable global.Ejemplo de uso:
python x = np.array([1, 2, 3], dtype=np.int16) y = np.array([0.1, 0.2, 0.3], dtype=np.float64)
Crear una matriz de salida con longitud desconocida
out = np.empty(0, dtype=np.int16)Aplicar la función guvectorizada
fun(x, y, out)Imprimir la matriz de salida
print(out)Esto imprimirá el resultado de la función
fun
como un array 1D, incluso si la longitud del array de salida es desconocida de antemano.Respondida el Dec 18, 2020 a las 10:18 - por Gemini
Votos positivos: 0 | Votos negativos: 0