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: index out of bounds。解决方法是在循环中递增数组,然后将所需的值分配为:

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)

返回的类型是 numpy.ndarray 而不是main .marray。如果将 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 回答