2016-08-04 4 views
5

NumPyは、配列を作成するときに本当に役に立ちます。 numpy.arrayの最初の引数に__getitem____len__メソッドがある場合、これらは有効なシーケンスである可能性があるという基準で使用されます。numpyが多次元配列を作成しないようにする

残念ながら、NumPyが「役に立つ」ことなくdtype=objectを含む配列を作成したいと思います。

import numpy as np 

class Test(object): 
    def __init__(self, iterable): 
     self.data = iterable 

    def __getitem__(self, idx): 
     return self.data[idx] 

    def __len__(self): 
     return len(self.data) 

    def __repr__(self): 
     return '{}({})'.format(self.__class__.__name__, self.data) 

をし、「反復可能オブジェクトが」持っている場合は、異なる長さのすべてが正常であると私は私がしたい正確な結果を得る:最小限の例に分解

クラスには、このことを希望

>>> np.array([Test([1,2,3]), Test([3,2])], dtype=object) 
array([Test([1, 2, 3]), Test([3, 2])], dtype=object) 

が、これらは同じ長さを持って起こる場合numpyのは、多次元配列を作成します。

>>> np.array([Test([1,2,3]), Test([3,2,1])], dtype=object) 
array([[1, 2, 3], 
     [3, 2, 1]], dtype=object) 

不幸にもndminという引数しかないので、ndmaxを適用する方法があるのか​​、NumPyがカスタムクラスを別の次元として解釈するのを防ぐために(__len__または__getitem__を削除せずに)疑問に思っていましたか?

答えて

3

問題を回避するには、所望の形状のアレイを作成し、データをコピーすることは勿論である:numpyの挙動w.r.t.場合はいずれの場合にも、私は驚かないこと

In [19]: lst = [Test([1, 2, 3]), Test([3, 2, 1])] 

In [20]: arr = np.empty(len(lst), dtype=object) 

In [21]: arr[:] = lst[:] 

In [22]: arr 
Out[22]: array([Test([1, 2, 3]), Test([3, 2, 1])], dtype=object) 

お知らせiterableオブジェクト(あなたが使いたいものですか?)を解釈するのはnumpyバージョンに依存します。おそらくバギー。あるいは、これらのバグのいくつかは実際にはフィーチャです。とにかく、numpyのバージョンが変わると、私は壊れてしまいます。

逆に、あらかじめ作成されたアレイへのコピーは、より堅牢でなければなりません。

5

この動作は、何度も前に(例えば、Override a dict with numpy support)議論されています。 np.arrayは可能な限り高次元の配列を作成しようとします。モデルケースはネストされたリストです。反復処理が可能で、サブリストの長さが同じであれば、下にドリルダウンします。

ここでは、異なる長さのリストに遭遇する前にダウン2つのレベル行ってきました:

In [250]: np.array([[[1,2],[3]],[1,2]],dtype=object) 
Out[250]: 
array([[[1, 2], [3]], 
     [1, 2]], dtype=object) 
In [251]: _.shape 
Out[251]: (2, 2) 

形状やndmaxパラメータがなければ、私はそれが(2,)または(2,2)になりたいかどうかを知る方法がありません。どちらもdtypeで動作します。

コンパイルされたコードなので、使用するテストを正確に見るのは容易ではありません。リストやタプルを反復しようとしますが、セットや辞書は反復しません。

所定の寸法とオブジェクト配列を作成する最も確実な方法は、空のいずれかで開始し、そして

In [266]: A=np.empty((2,3),object) 
In [267]: A.fill([[1,'one']]) 
In [276]: A[:]={1,2} 
In [277]: A[:]=[1,2] # broadcast error 

に別の方法でそれを埋めるためにある少なくとも1つの異なる要素(例えばNone)で開始しますそれを置き換えてください。

In [280]: np.ndarray((2,3),dtype=object) 
Out[280]: 
array([[None, None, None], 
     [None, None, None]], dtype=object) 

しかし、(私はそれバッファー与えない限り)それは基本的にnp.emptyと同じです:形をとる

より原始的なクリエイターがあり、ndarray

これらはfudgesですが、彼らは(時間的に)高価ではありません。

================(編集)

https://github.com/numpy/numpy/issues/5933Enh: Object array creation function.がエンハンスメント要求です。また、https://github.com/numpy/numpy/issues/5303the error message for accidentally irregular arrays is confusing

開発者の感情はdtype=object配列、反復の初期寸法と深さをより細かく制御のものを作成するために、別の関数を好むようです。彼らはnp.arrayが '不規則な'配列を作成しないようにエラーチェックを強化するかもしれません。

このような関数は、指定された深さまでネストされた定期的な反復可能な形状を検出し、充填するオブジェクト型アレイを構築できます。様々な深さで

def objarray(alist, depth=1): 
    shape=[]; l=alist 
    for _ in range(depth): 
     shape.append(len(l)) 
     l = l[0] 
    arr = np.empty(shape, dtype=object) 
    arr[:]=alist 
    return arr 

In [528]: alist=[[Test([1,2,3])], [Test([3,2,1])]] 
In [529]: objarray(alist,1) 
Out[529]: array([[Test([1, 2, 3])], [Test([3, 2, 1])]], dtype=object) 
In [530]: objarray(alist,2) 
Out[530]: 
array([[Test([1, 2, 3])], 
     [Test([3, 2, 1])]], dtype=object) 
In [531]: objarray(alist,3) 
Out[531]: 
array([[[1, 2, 3]], 

     [[3, 2, 1]]], dtype=object) 
In [532]: objarray(alist,4) 
... 
TypeError: object of type 'int' has no len() 
+0

私は同様の質問を探してみましたが、私はいずれかを発見していません。たぶん私は間違ったフレーズを探しただけかもしれません。以前の質問への参照があればそれは素晴らしいでしょう。答えをありがとうが、私は実際に回避策を探していません。私はもっ​​と正確な長さを事前に知らなくても配列の最大深度(ディメンション)を定義する方法や、numpyを無効にしてカスタムクラスインスタンスをシーケンスとして解釈する、より一般的なアプローチにもっと興味を持っています。 – MSeifert

+0

クラスをサブクラス 'dict'に変更することで、インスタンスを反復することを止めることができます。これは、 'np.array'が' __getitem__'以上のテストを行っていることを示しています。しかし、私はその種のチェックを行うコードを見つけることができませんでした。 – hpaulj

+0

http://stackoverflow.com/questions/36663919/override-a-dict-with-numpy-support - 同じ問題を抱えて苦労しています。 'np.array'があなたのカスタムクラスを反復するかどうかを制御します。同じ種類の回避策。 – hpaulj

関連する問題