web-dev-qa-db-ja.com

ベクトルを返す関数でのNumpy Vectorizeの使用

numpy.vectorizeは関数f:a-> bを受け取り、それをg:a []-> b []に変換します。

abがスカラーの場合、これは正常に機能しますが、bをndarrayまたはリスト、つまりfとして機能しない理由は考えられません。 :a-> b []およびg:a []-> b [] []

例えば:

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))

これにより、

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

OK、それで正しい値が得られますが、dtypeが間違っています。さらに悪いことに:

g(a).shape

利回り:

(4,)

したがって、この配列はほとんど役に立ちません。私はそれを変換することができることを知っています:

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

私が欲しいものを与えるために:

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

しかし、それは効率的でもPythonicでもありません。これを行うためのよりクリーンな方法を見つけられる人はいますか?

前もって感謝します!

34
prodigenius

np.vectorizeは便利な関数です。実際には コードをより速く実行する ではありません。 np.vectorizeを使用するのが不都合な場合は、希望どおりに機能する独自の関数を記述してください。

np.vectorizeの目的は、numpyを認識しない関数(たとえば、floatを入力として受け取り、floatを出力として返す)を、numpy配列を操作(および返す)できる関数に変換することです。

関数fはすでにnumpyに対応しています-定義でnumpy配列を使用し、numpy配列を返します。したがって、np.vectorizeは、ユースケースに適していません。

したがって、解決策は、あなたが望む方法で機能する独自の関数fをロールすることです。

43
unutbu

1.12.0の新しいパラメーターsignatureは、まさにあなたが何をしているかを実行します。

_def f(x):
    return x * np.array([1,1,1,1,1], dtype=np.float32)

g = np.vectorize(f, signature='()->(n)')
_

次に、g(np.arange(4)).shapeは_(4L, 5L)_を返します。

ここでは、fの署名が指定されています。 _(n)_は戻り値の形状であり、_()_はスカラーのパラメーターの形状です。また、パラメーターも配列にすることができます。より複雑なシグネチャについては、「 一般化ユニバーサル関数API 」を参照してください。

12
Cosyn
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)

これで問題が解決し、入力のサイズに関係なく機能します。 「マップ」は、1つの次元の入力に対してのみ機能します。 「.tolist()」を使用して新しいndarrayを作成すると、問題がより完全かつ適切に解決されます(私は信じています)。お役に立てれば。

5
Aniq Ahsan

私は関数を書きました、それはあなたのニーズに合っているようです。

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)

やってみよう

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

アウトプット

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

便宜上、ラムダまたはパーシャルでラップすることもできます

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

vectorizeのドキュメント文字列に注目してください

vectorize関数は、パフォーマンスのためではなく、主に便宜上提供されています。実装は基本的にforループです。

したがって、ここでのamapvectorizeと同様のパフォーマンスを期待します。私はそれをチェックしませんでした、どんなパフォーマンステストも歓迎です。

パフォーマンスが本当に重要な場合は、他のことを検討する必要があります。純粋なループを回避するためのreshapebroadcastを使用した直接配列計算python(vectorizeamapの両方が後である場合)。

1
Syrtis Major

関数をベクトル化したい

import numpy as np
def f(x):
    return x * np.array([1,1,1,1,1], dtype=np.float32)

結果として単一のnp.float32配列を取得したい場合、これをotypeとして指定する必要があります。あなたの質問では、otypes=[np.ndarray]を指定しましたが、これは、すべての要素をnp.ndarrayにすることを意味します。したがって、dtype=objectの結果を正しく取得できます。

正しい呼び出しは

np.vectorize(f, signature='()->(n)', otypes=[np.float32])

ただし、そのような単純な関数の場合、numpyのufunctionを利用する方が適切です。 np.vectorizeはループします。したがって、あなたの場合は関数を次のように書き直してください

def f(x):
    return np.multiply.outer(x, np.array([1,1,1,1,1], dtype=np.float32))

これはより高速で、不明瞭なエラーが少なくなります(ただし、複素数または4倍精度の数値を渡す場合、結果dtypexに依存するため、結果も同様です)。

0
DerWeh

これを解決する最良の方法は、2-D NumPy配列(この場合は列配列)をoriginal関数への入力として使用することです。結果はあなたが期待していたと思います。

コードでは次のようになります。

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)

これは、操作を完了するためのはるかに簡単でエラーが発生しにくい方法です。このメソッドは、numpy.vectorizeを使用して関数を変換しようとするのではなく、配列をブロードキャストするNumPyの自然な機能に依存します。トリックは、少なくとも1つの次元が配列間で同じ長さであることを確認することです。

0
bburks832