我正在尝试将我构建的一些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函数输出?我认为使用 array_wrap 应该可行,但我找不到确切的方法。任何帮助将不胜感激。
答案 0 :(得分:3)
从Dynamic list that automatically expands获得更新旧答案的自由。认为这应该做你需要/想要的大部分
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
答案 1 :(得分: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如何线性地存储数据(虽然它是否可以在创建数组时指定为row-major或column-major),但多维数组在这里非常棘手。
>>> 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.]])
答案 2 :(得分:0)
python dict可以很好地用作稀疏数组。主要问题是初始化稀疏数组的语法不会很漂亮:
listarray = [100,200,300]
dictarray = {0:100, 1:200, 2:300}
但之后插入或检索元素的语法是相同的
dictarray[5] = 2345