2

ビルドしたいくつかの Matlab ライブラリを Python 環境に移動しようとしています。これまでに直面した最大の問題は、インデックス指定に基づく配列の動的割り当てです。たとえば、Matlab を使用して、次のように入力します。

x = [1 2];
x(5) = 3;

次のようになります。

x = [ 1     2     0     0     3]

つまり、(x) の大きさも内容も事前に知りませんでした。配列は、私が提供しているインデックスに基づいて、その場で定義する必要があります。

Pythonで、次のことを試してください:

from numpy import *
x = array([1,2])
x[4] = 3

次のエラーが発生します: IndexError: インデックスが範囲外です。回避策として、ループ内で配列をインクリメントしてから、目的の値を次のように割り当てます。

from numpy import *
x = array([1,2])

idx = 4
for i in range(size(x),idx+1):
    x = append(x,0)

x[idx] = 3
print x

機能しますが、あまり便利ではなく、n 次元配列の場合は非常に面倒になる可能性があります。目標を達成するために ndarray をサブクラス化することについて考えましたが、うまくいくかどうかはわかりません。誰もがより良いアプローチを知っていますか?


早速のお返事ありがとうございます。setitemメソッドについて知りませんでした(私は Python にかなり慣れていません)。次のように ndarray クラスを単純に上書きしました。

import numpy as np

class marray(np.ndarray):

    def __setitem__(self, key, value):

        # Array properties
        nDim = np.ndim(self)
        dims = list(np.shape(self))

        # Requested Index
        if type(key)==int: key=key,
        nDim_rq = len(key)
        dims_rq = list(key)

        for i in range(nDim_rq): dims_rq[i]+=1        

        # Provided indices match current array number of dimensions
        if nDim_rq==nDim:

            # Define new dimensions
            newdims = []
            for iDim in range(nDim):
                v = max([dims[iDim],dims_rq[iDim]])
                newdims.append(v)

            # Resize if necessary
            if newdims != dims:
              self.resize(newdims,refcheck=False)

        return super(marray, self).__setitem__(key, value)

そして、それは魅力のように機能します!ただし、 setitemがこの要求に従ってディメンションの数を変更できるように、上記のコードを変更する必要があります。

a = marray([0,0])
a[3,1,0] = 0

残念ながら、次のようなnumpy関数を使用しようとすると

self = np.expand_dims(self,2)

返される型は、main .marray ではなくnumpy.ndarrayです。marray が入力として提供されている場合、numpy 関数が marray を出力するように強制する方法についてのアイデアはありますか? array_wrapを使用して実行できるはずだと思いますが、正確な方法を見つけることができませんでした。どんな助けでも大歓迎です。

4

3 に答える 3

3

自動的に展開される動的リストから私の古い回答を更新する自由を取りました。これはあなたが必要とする/望むことのほとんどを行うべきだと思います

class matlab_list(list):
    def __init__(self):
        def zero():
            while 1:
                yield 0
        self._num_gen = zero()

    def __setitem__(self,index,value):
        if isinstance(index, int):
            self.expandfor(index)
            return super(dynamic_list,self).__setitem__(index,value)

        elif isinstance(index, slice):
            if index.stop<index.start:
                return super(dynamic_list,self).__setitem__(index,value)
            else:
                self.expandfor(index.stop if abs(index.stop)>abs(index.start) else index.start)
            return super(dynamic_list,self).__setitem__(index,value)

    def expandfor(self,index):
            rng = []
            if abs(index)>len(self)-1:
                if index<0:
                    rng = xrange(abs(index)-len(self))
                    for i in rng:
                        self.insert(0,self_num_gen.next())
                else:
                    rng = xrange(abs(index)-len(self)+1)
                    for i in rng:
                        self.append(self._num_gen.next())

# Usage
spec_list = matlab_list()
spec_list[5] = 14
于 2012-07-13T14:24:38.510 に答える
3

これはあなたが望むものではありませんが...

x = np.array([1, 2])

try:
    x[index] = value
except IndexError:
    oldsize = len(x)   # will be trickier for multidimensional arrays; you'll need to use x.shape or something and take advantage of numpy's advanced slicing ability
    x = np.resize(x, index+1) # Python uses C-style 0-based indices
    x[oldsize:index] = 0 # You could also do x[oldsize:] = 0, but that would mean you'd be assigning to the final position twice.
    x[index] = value

>>> x = np.array([1, 2])
>>> x = np.resize(x, 5)
>>> x[2:5] = 0
>>> x[4] = 3
>>> x
array([1, 2, 0, 0, 3])

numpy がフードの下でデータを線形に格納する方法が原因で (ただし、配列を作成するときに行優先または列優先のどちらで格納するかを指定できます)、多次元配列はここではかなり注意が必要です。

>>> x = np.array([[1, 2, 3], [4, 5, 6]])
>>> np.resize(x, (6, 4))
array([[1, 2, 3, 4],
       [5, 6, 1, 2],
       [3, 4, 5, 6],
       [1, 2, 3, 4],
       [5, 6, 1, 2],
       [3, 4, 5, 6]])

これまたは同様のことを行う必要があります:

>>> y = np.zeros((6, 4))
>>> y[:x.shape[0], :x.shape[1]] = x
>>> y
array([[ 1.,  2.,  3.,  0.],
       [ 4.,  5.,  6.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])
于 2012-07-13T14:25:02.517 に答える
0

Python dict はスパース配列としてうまく機能します。主な問題は、スパース配列を初期化するための構文がそれほどきれいではないことです:

listarray = [100,200,300]
dictarray = {0:100, 1:200, 2:300}

その後、要素を挿入または取得するための構文は同じです

dictarray[5] = 2345
于 2012-07-13T15:54:56.063 に答える