numpy.vectorize
neemt een functie f:a->b en verandert deze in g:a[]->b[].
Dit werkt prima als a
en b
scalaire waarden zijn, maar ik kan geen reden bedenken waarom het niet zou werken met b als een ndarray
of lijst, bijv. f:a->b[] en g:a[]->b[][]
Bijvoorbeeld:
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))
Dit levert:
array([[ 0. 0. 0. 0. 0.],
[ 1. 1. 1. 1. 1.],
[ 2. 2. 2. 2. 2.],
[ 3. 3. 3. 3. 3.]], dtype=object)
Ok, dus dat geeft de juiste waarden, maar het verkeerde dtype. En nog erger:
g(a).shape
opbrengst:
(4,)
Dus deze array is vrijwel nutteloos. Ik weet dat ik het kan converteren door:
np.array(map(list, a), dtype=np.float32)
om me te geven wat ik wil:
array([[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.],
[ 2., 2., 2., 2., 2.],
[ 3., 3., 3., 3., 3.]], dtype=float32)
maar dat is noch efficiënt, noch pythonisch. Kan iemand van jullie een schonere manier vinden om dit te doen?
Bij voorbaat dank!
Antwoord 1, autoriteit 100%
np.vectorize
is slechts een gemaksfunctie. Het maakt de code niet echt sneller. Als het niet handig is om np.vectorize
te gebruiken, schrijf dan gewoon je eigen functie die werkt zoals je wilt.
Het doel van np.vectorize
is om functies die niet numpy-aware zijn (bijv. floats als invoer te nemen en floats als uitvoer terug te geven) om te zetten in functies die kunnen werken op (en retourneren) numpy arrays .
Uw functie f
is al numpy-aware — het gebruikt een numpy-array in zijn definitie en retourneert een numpy-array. Dus np.vectorize
is niet geschikt voor uw gebruik.
De oplossing is daarom gewoon je eigen functie f
te gebruiken die werkt zoals jij dat wilt.
Antwoord 2, autoriteit 38%
Een nieuwe parameter signature
in 1.12.0 doet precies wat je doet.
def f(x):
return x * np.array([1,1,1,1,1], dtype=np.float32)
g = np.vectorize(f, signature='()->(n)')
Vervolgens geeft g(np.arange(4)).shape
(4L, 5L)
.
Hier wordt de handtekening van f
gespecificeerd. De (n)
is de vorm van de geretourneerde waarde en de ()
is de vorm van de parameter die scalair is. En de parameters kunnen ook arrays zijn. Voor meer complexe handtekeningen, zie Generalized Universal Function API.
Antwoord 3, autoriteit 11%
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)
Dit zou het probleem moeten oplossen en het werkt ongeacht de grootte van uw invoer. “map” werkt alleen voor ééndimensionale ingangen. Het gebruik van “.tolist()” en het maken van een nieuwe ndarray lost het probleem vollediger en mooier op (denk ik). Ik hoop dat dit helpt.
Antwoord 4, autoriteit 2%
Ik heb een functie geschreven, het lijkt aan uw behoefte te voldoen.
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)
Probeer het
def f(x):
return x * np.array([1,1,1,1,1], dtype=np.float32)
amap(f, np.arange(4))
Uitgangen
array([[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.],
[ 2., 2., 2., 2., 2.],
[ 3., 3., 3., 3., 3.]], dtype=float32)
Je kunt het voor het gemak ook met lambda of gedeeltelijk inpakken
g = lambda x:amap(f, x)
g(np.arange(4))
Let op de DOCSTRING VAN vectorize
zegt
De
vectorize
Functie wordt voornamelijk verstrekt voor het gemak, niet voor
uitvoering. De implementatie is in wezen een voor lus.
We zouden dus verwachten dat de amap
hier een vergelijkbare uitvoering hebben als vectorize
. Ik heb het niet gecontroleerd, elke prestatietest is welkom.
Als de uitvoering echt belangrijk is, moet u iets anders overwegen, b.v. Directe array-berekening met reshape
en broadcast
om lus in pure python te voorkomen (beide vectorize
en amap
zijn het latere geval ).
5, Autoriteit 2%
U wilt de functie
omgeven
import numpy as np
def f(x):
return x * np.array([1,1,1,1,1], dtype=np.float32)
Aangenomen dat u een enkele np.float32
arrays als resultaat wilt krijgen, moet u dit opgeven als otype
. In uw vraag die u echter hebt gespecificeerd otypes=[np.ndarray]
, wat betekent dat u wilt dat elk element een np.ndarray
is. U krijgt dus correct een resultaat van dtype=object
.
De juiste oproep zou
zijn
np.vectorize(f, signature='()->(n)', otypes=[np.float32])
Voor een dergelijke eenvoudige functie is het echter beter om numpy
sfuncties te gebruiken; np.vectorize
Loopt er gewoon over. Dus in uw geval Herschrijf uw functie gewoon als
def f(x):
return np.multiply.outer(x, np.array([1,1,1,1,1], dtype=np.float32))
Dit is sneller en produceert minder obscure fouten (meld echter dat de resultaten dtype
afhankelijk zijn van x
als u een complex of quad-precisienummer passeert, dus het resultaat).