vectorize array python arrays numpy vectorization

python - array - Usando Numex Vectorize en funciones que devuelven vectores



numpy vectorize (5)

La mejor manera de resolver esto sería usar una matriz NumPy 2-D (en este caso una matriz de columnas) como una entrada a la función original , que luego generará una salida 2-D con los resultados que creo que esperaba.

Esto es lo que podría verse en el código:

import numpy as np def f(x): return x*np.array([1, 1, 1, 1, 1], dtype=np.float32) a = np.arange(4).reshape((4, 1)) b = f(a) # b is a 2-D array with shape (4, 5) print(b)

Esta es una forma mucho más simple y menos propensa a errores para completar la operación. En lugar de tratar de transformar la función con numpy.vectorize, este método se basa en la capacidad natural de NumPy para transmitir matrices. El truco es asegurarse de que al menos una dimensión tenga la misma longitud entre las matrices.

numpy.vectorize toma una función f: a-> b y la convierte en g: a [] -> b [].

Esto funciona bien cuando a y b son escalares, pero no puedo pensar en una razón por la cual no funcione con b como una ndarray o lista, es decir, f: a-> b [] yg: a [] -> segundo[][]

Por ejemplo:

import numpy as np def f(x): return x * np.array([1,1,1,1,1], dtype=np.float32) g = np.vectorize(f, otypes=[np.ndarray]) a = np.arange(4) print(g(a))

Esto produce:

array([[ 0. 0. 0. 0. 0.], [ 1. 1. 1. 1. 1.], [ 2. 2. 2. 2. 2.], [ 3. 3. 3. 3. 3.]], dtype=object)

Ok, eso da los valores correctos, pero el tipo incorrecto. Y aún peor:

g(a).shape

rendimientos:

(4,)

Entonces esta matriz es bastante inútil. Sé que puedo convertirlo haciendo:

np.array(map(list, a), dtype=np.float32)

para darme lo que quiero:

array([[ 0., 0., 0., 0., 0.], [ 1., 1., 1., 1., 1.], [ 2., 2., 2., 2., 2.], [ 3., 3., 3., 3., 3.]], dtype=float32)

pero eso no es ni eficiente ni pitónico. ¿Alguno de ustedes puede encontrar una manera más limpia de hacer esto?

¡Gracias por adelantado!


np.vectorize es solo una función de conveniencia. En realidad, no hace que el código se ejecute más rápido . Si no es conveniente usar np.vectorize , simplemente escriba su propia función que funcione como desee.

El objetivo de np.vectorize es transformar las funciones que no son numpy-aware (por ejemplo, tomar flotantes como entrada y devolver flotantes como salida) en funciones que pueden operar en matrices numpy (y regresar).

Su función f ya es numpy-aware - usa una matriz numpy en su definición y devuelve una matriz numpy. Entonces np.vectorize no es una buena np.vectorize para su caso de uso.

La solución, por lo tanto, es simplemente desplegar su propia función f que funcione de la manera que desee.


import numpy as np def f(x): return x * np.array([1,1,1,1,1], dtype=np.float32) g = np.vectorize(f, otypes=[np.ndarray]) a = np.arange(4) b = g(a) b = np.array(b.tolist()) print(b)#b.shape = (4,5) c = np.ones((2,3,4)) d = g(c) d = np.array(d.tolist()) print(d)#d.shape = (2,3,4,5)

Esto debería solucionar el problema y funcionará independientemente del tamaño de su entrada. "mapa" solo funciona para una entrada dimensional. Usar ".tolist ()" y crear un nuevo ndarray resuelve el problema de forma más completa y agradable (creo). Espero que esto ayude.


He escrito una función, parece ajustarse a tu necesidad.

def amap(func, *args): ''''''array version of build-in map amap(function, sequence[, sequence, ...]) -> array Examples -------- >>> amap(lambda x: x**2, 1) array(1) >>> amap(lambda x: x**2, [1, 2]) array([1, 4]) >>> amap(lambda x,y: y**2 + x**2, 1, [1, 2]) array([2, 5]) >>> amap(lambda x: (x, x), 1) array([1, 1]) >>> amap(lambda x,y: [x**2, y**2], [1,2], [3,4]) array([[1, 9], [4, 16]]) '''''' args = np.broadcast(None, *args) res = np.array([func(*arg[1:]) for arg in args]) shape = args.shape + res.shape[1:] return res.reshape(shape)

Dejar que intente

def f(x): return x * np.array([1,1,1,1,1], dtype=np.float32) amap(f, np.arange(4))

Salidas

array([[ 0., 0., 0., 0., 0.], [ 1., 1., 1., 1., 1.], [ 2., 2., 2., 2., 2.], [ 3., 3., 3., 3., 3.]], dtype=float32)

También puede envolverlo con lambda o parcial para mayor comodidad

g = lambda x:amap(f, x) g(np.arange(4))

Tenga en cuenta que el docstring de vectorize dice

La función vectorize se proporciona principalmente por conveniencia, no por rendimiento. La implementación es esencialmente un ciclo for.

Por lo tanto, esperaríamos que el amap aquí tenga un rendimiento similar al de vectorize . No lo revisé, cualquier prueba de rendimiento es bienvenida.

Si el rendimiento es realmente importante, debe considerar otra cosa, por ejemplo, el cálculo de matriz directa con reshape y broadcast para evitar el bucle en python puro (tanto vectorize como amap son el caso posterior).


Una nueva signature parámetro en 1.12.0 hace exactamente lo que tú.

def f(x): return x * np.array([1,1,1,1,1], dtype=np.float32) g = np.vectorize(f, signature=''()->(n)'')

Entonces la forma g(np.arange(4)).shape Dará (4L, 5L) .

Aquí se especifica la firma de f . El (n) es la forma del valor de retorno, y el () es la forma del parámetro que es escalar. Y los parámetros también pueden ser matrices. Para firmas más complejas, vea la API de función universal generalizada .