2016-06-15 6 views
0

をufunc適用した後、容器内numpyのサブクラスを維持し、(それをより読みやすくするために、属性の数を減らす)ように見えます: 私は<a href="http://docs.scipy.org/doc/numpy-1.10.1/user/basics.subclassing.html" rel="nofollow">numpy's documentation</a>を以下のnumpyののndarrayから派生したクラスを作成した

import numpy as np 

class Atom3D(np.ndarray): 
    __array_priority__ = 11.0 

    def __new__(cls, idnum, coordinates): 

     # Cast numpy to be our class type 
     assert len(coordinates) == 3 
     obj = np.asarray(coordinates, dtype= np.float64).view(cls) 
     # add the new attribute to the created instance 
     obj._number = int(idnum) 
     # Finally, we must return the newly created object: 
     return obj 

    def __array_finalize__(self, obj): 
     self._number = getattr(obj, '_number', None) 

    def __array_wrap__(self, out_arr, context=None): 
     return np.ndarray.__array_wrap__(self, out_arr, context) 

    def __repr__(self): 
     return "{0._number}: ({0[0]:8.3f}, {0[1]:8.3f}, {0[2]:9.3f})".format(self) 

とき私はオブジェクトにnumpyのufuncを適用するテストを実行します:

a1 = Atom3D(1, [5., 5., 5.]) 
print type(a1), repr(a1) 
m = np.identity(3) 
a2 = np.dot(a1, m) 
print type(a2), repr(a2) 

私は期待される結果を得ます。つまり、ドット関数はオブジェクトのサブクラス続けて:私は、これらのオブジェクトの配列に同じnp.dotを適用しようとすると、

<class '__main__.Atom3D'> 1: ( 5.000, 5.000,  5.000) 
<class '__main__.Atom3D'> 1: ( 5.000, 5.000,  5.000) 

をしかし、サブクラスは失われます。このように、実行:

print "regular" 
atom_list1 = [a1, a2, a3] 
atom_list2 = np.dot(atom_list1, m) 
for _ in atom_list2: 
    print type(_), repr(_) 

print "numpy array" 
atom_list1 = np.array([a1, a2, a3], dtype=np.object) 
atom_list2 = np.dot(atom_list1, m) 
for _ in atom_list2: 
    print type(_), repr(_) 

することは私にこの与える:

regular 
<type 'numpy.ndarray'> array([ 5., 5., 5.]) 
<type 'numpy.ndarray'> array([ 6., 4., 2.]) 
<type 'numpy.ndarray'> array([ 8., 6., 8.]) 
numpy array 
<type 'numpy.ndarray'> array([5.0, 5.0, 5.0], dtype=object) 
<type 'numpy.ndarray'> array([6.0, 4.0, 2.0], dtype=object) 
<type 'numpy.ndarray'> array([8.0, 6.0, 8.0], dtype=object) 

など__sub__などの他の操作のために行くだろうと同じ:

print "regular" 
a1 = Atom3D(1, [5., 5., 5.]) 
a2 = a1 - np.array([3., 2., 0.]) 
print type(a2), repr(a2) 
print "numpy array" 
a1 = Atom3D(1, [5., 5., 5.]) 
a2 = Atom3D(2, [6., 4., 2.]) 
a3 = Atom3D(3, [8., 6., 8.]) 
atom_list1 = np.array([a1, a2, a3], dtype=np.object) 
atom_list2 = atom_list1 - np.array([3., 2., 0.]) 
for _ in atom_list2: 
    print type(_), repr(_) 

が得られます:

regular 
<class '__main__.Atom3D'> 1: ( 2.000, 3.000,  5.000) 
numpy array 
<type 'numpy.ndarray'> array([2.0, 3.0, 5.0], dtype=object) 
<type 'numpy.ndarray'> array([3.0, 2.0, 2.0], dtype=object) 
<type 'numpy.ndarray'> array([5.0, 4.0, 8.0], dtype=object) 

私は見てきましたがどうやって私が間違っているのか分からない。
ありがとうございます!

J.-

答えて

1

dtype=Atom3Dのようなものはありません。 dtype=listdtype=np.ndarrayの場合も同じです。 dtype=object配列を作成します。各要素は、メモリ内の他の場所のオブジェクトへのポインタです。

np.array(...)でオブジェクト配列を作成するのは難しい場合があります。 np.arrayはエントリを評価し、独自の選択肢をいくつか行います。オブジェクト配列に入る要素を完全に制御したい場合は、空の要素を作成し、要素を自分で割り当てます。

In [508]: A=np.array([np.matrix([1,2]),np.matrix([2,1])],dtype=object) 

In [509]: A  # a 3d array, no matrix subarrays 
Out[509]: 
array([[[1, 2]], 

     [[2, 1]]], dtype=object) 

In [510]: A=np.empty((2,),dtype=object) 

In [511]: A 
Out[511]: array([None, None], dtype=object) 

In [512]: A[:]=[np.matrix([1,2]),np.matrix([2,1])] 

In [513]: A 
Out[513]: array([matrix([[1, 2]]), matrix([[2, 1]])], dtype=object) 

通常、整形や移調などの目的でオブジェクト配列が必要な場合を除き、通常はリストを使用する方がよいでしょう。また、オブジェクト型を混在

は動作します:

In [522]: A=np.asarray([np.matrix([1,2]),np.ma.masked_array([2,1])],dtype=np.object) 

In [523]: A 
Out[523]: 
array([matrix([[1, 2]]), 
     masked_array(data = [2 1], 
      mask = False, 
     fill_value = 999999) 
], dtype=object) 

==========================

ますnp.dot([a1,a2,a3],m)を実行すると、最初にすべてのリストがnp.asarray([a1,a2,a3])の配列に変換されます。結果は2次元配列であり、Atom3dオブジェクトの配列ではありません。したがって、dotは通常の配列ドットです。

私が示唆したように、私はオブジェクト配列を作成する場合:

In [14]: A=np.empty((3,),dtype=object) 
In [16]: A[:]=[a1,a2,a1+a2] 

In [17]: A 
Out[17]: 
array([1: ( 5.000, 5.000,  5.000), 
     1: ( 5.000, 5.000,  5.000), 
     1: ( 10.000, 10.000, 10.000)], dtype=object) 

In [18]: np.dot(A,m) 
Out[18]: 
array([1: ( 5.000, 5.000,  5.000), 
     1: ( 5.000, 5.000,  5.000), 
     1: ( 10.000, 10.000, 10.000)], dtype=object) 

Atom3Dタイプが保存されます。

減算のための同じ:結果の表示に問題があるものの、そのアレイとAtom3Dの

In [23]: A- np.array([3.,2., 0]) 
Out[23]: 
array([1: ( 2.000, 2.000,  2.000), 
     1: ( 3.000, 3.000,  3.000), 
     1: ( 10.000, 10.000, 10.000)], dtype=object) 

添加すると、動作します:オブジェクトDTYPEアレイと

In [39]: x = A + a2 

In [40]: x 
Out[40]: <repr(<__main__.Atom3D at 0xb5062294>) failed: TypeError: non-empty format string passed to object.__format__> 

計算があやふやです。配列の要素を反復処理し、関数を適用し、結果をオブジェクト配列に戻すことによって、明らかにいくつかの作業が行われます。実際には配列形式の

[func(a, x) for a in A] 

でも、高速コンパイルされた操作は実行されません。それは反復的です(タイミングは同等のリストに似ています)。私たちは、DTYPE配列は見せかけのリストよりも少ししているオブジェクトを何度も指摘してきた

In [41]: a1>0 
Out[41]: 1: ( 1.000, 1.000,  1.000) 

In [42]: A>0 
... 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

他のものは動作しません。要素はリストと同様にポインタであるため、操作ではこれらのポインタを反復する必要があります.CではなくPythonではnumpyコードの高度なコーディングではありません。

+0

私は混乱を避けるために私の例でこれを変更しました。しかし、これは私の質問に答えるものではありません。これは、numpyのufuncを適用すると、list/np.array内のオブジェクトのサブクラス化が失われることです。十分にはっきりしていないかもしれませんか?ちょっとでも私の質問を少し言い直しました。この 'Atom3D'オブジェクトの全部に翻訳(' __sub__'と '__add__')と回転(' np.dot')を適用できるようにするために、 'np.array'が必要です私が毎回それらのすべてをループすることを避けたいのであれば... – jaumebonet

+0

私はあなたのクラスでいくつかのことを試しました。 – hpaulj

+0

ああ! OK!今私はそれを得る!私はこれが私のために働くと思う! 2つのアトムを追加しても機能しないようですが、それでも問題はありません。配列や行列のみを適用してください。ありがとう!! – jaumebonet

関連する問題

 関連する問題