numpy.vectorize
prend une fonction f: a-> b et la transforme en g: a [] -> b [].
Cela fonctionne bien lorsque a
et b
sont des scalaires, mais je ne vois pas pourquoi cela ne fonctionnerait pas avec b en tant que ndarray
ou liste, c'est-à-dire f: a-> b [] et g: a [] -> b [] []
Par exemple:
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))
Cela donne:
array([[ 0. 0. 0. 0. 0.],
[ 1. 1. 1. 1. 1.],
[ 2. 2. 2. 2. 2.],
[ 3. 3. 3. 3. 3.]], dtype=object)
Ok, donc ça donne les bonnes valeurs, mais le mauvais type. Et pire encore:
g(a).shape
rendements:
(4,)
Donc, ce tableau est à peu près inutile. Je sais que je peux le convertir en faisant:
np.array(map(list, a), dtype=np.float32)
pour me donner ce que je veux:
array([[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.],
[ 2., 2., 2., 2., 2.],
[ 3., 3., 3., 3., 3.]], dtype=float32)
mais ce n'est ni efficace ni Pythonic. Est-ce que l'un de vous peut trouver un moyen plus propre de faire cela?
Merci d'avance!
np.vectorize
est juste une fonction de commodité. En fait, il ne fait pas accélère le code . S'il n'est pas pratique d'utiliser np.vectorize
, écrivez simplement votre propre fonction qui fonctionne comme vous le souhaitez.
np.vectorize
sert à transformer des fonctions qui ne sont pas compatibles avec numpy (par exemple, prendre des flottants en entrée et renvoyer des flottants en sortie) en fonctions pouvant fonctionner sur (et renvoyer) des tableaux numpy.
Votre fonction f
est déjà consciente de numpy - elle utilise un tableau numpy dans sa définition et retourne un tableau numpy. Donc, np.vectorize
ne convient pas à votre cas d'utilisation.
La solution consiste donc simplement à lancer votre propre fonction f
qui fonctionne comme vous le souhaitez.
Un nouveau paramètre signature
dans 1.12.0 fait exactement ce que vous faites.
def f(x):
return x * np.array([1,1,1,1,1], dtype=np.float32)
g = np.vectorize(f, signature='()->(n)')
Alors g(np.arange(4)).shape
donnera (4L, 5L)
.
Ici, la signature de f
est spécifiée. Le (n)
est la forme de la valeur de retour et le ()
est la forme du paramètre qui est scalaire. Et les paramètres peuvent aussi être des tableaux. Pour des signatures plus complexes, voir API de fonction universelle généralisée .
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)
Cela devrait résoudre le problème et cela fonctionnera quelle que soit la taille de votre entrée. "map" ne fonctionne que pour une entrée donnée. Utiliser ".tolist ()" et créer un nouveau ndarray résout le problème plus complètement et plus agréablement (je crois). J'espère que cela t'aides.
J'ai écrit une fonction, elle semble correspondre à vos besoins.
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)
Laisser essayer
def f(x):
return x * np.array([1,1,1,1,1], dtype=np.float32)
amap(f, np.arange(4))
Les sorties
array([[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.],
[ 2., 2., 2., 2., 2.],
[ 3., 3., 3., 3., 3.]], dtype=float32)
Vous pouvez également l’envelopper de lambda ou partiel pour plus de commodité
g = lambda x:amap(f, x)
g(np.arange(4))
Notez la docstring de vectorize
dit
La fonction
vectorize
est fournie principalement pour des raisons de commodité et non pour Performances. L'implémentation est essentiellement une boucle for.
Ainsi, nous nous attendrions à ce que la amap
présente ici des performances similaires à celles de vectorize
. Je n'ai pas vérifié, tous les tests de performance sont les bienvenus.
Si la performance est vraiment importante, vous devriez envisager autre chose, par exemple calcul direct de tableau avec reshape
et broadcast
pour éviter les boucles en python pur (vectorize
et amap
sont les deux derniers cas).
La meilleure façon de résoudre ce problème consiste à utiliser un tableau 2-D NumPy (dans ce cas, un tableau de colonnes) comme entrée de la fonction original , qui générera ensuite une sortie 2-D avec les résultats, je crois. vous vous attendiez.
Voici à quoi cela pourrait ressembler dans le code:
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)
Il s'agit d'un moyen beaucoup plus simple et moins sujet aux erreurs pour terminer l'opération. Plutôt que d'essayer de transformer la fonction avec numpy.vectorize, cette méthode repose sur la capacité naturelle de NumPy à diffuser des tableaux. L'astuce consiste à s'assurer qu'au moins une dimension a une longueur égale entre les tableaux.