我认为这段代码正确处理了 n-d(请验证(,我已经将其破解为多态性,但它很丑陋。 有没有更好/更有效的方法?我不确定它是否尽可能多地共享内存。 我想避免F order
,我猜 Numpy/Python 对C
更满意。 如果我错了,请启发我在这种情况下使用F
的任何优势。
具体问题(如果这种整体方法最好(:
array.array(.,numpy.ndarray.ravel)
复制数据吗? 我怀疑是的。 有没有办法分享它? 例如,改用numpy.nditer()
、numpy.ndarray.flat
或numpy.ndarray.flatten
的性能/内存共享影响是什么? 见 http://numpy-discussion.10968.n7.nabble.com/Why-ndarray-provides-four-ways-to-flatten-td38989.html- 我需要一个
array.peek
的方法,为什么没有? - 如果我不能
array.peek
,array.append
是否像我怀疑的那样低效(再次复制整个数组(? 我本可以使用numpy.insert
或numpy.append
代替(这会清理代码,因为我不必对空数组进行特殊处理(,但我相信这些确实会复制。 F order
有什么负面影响吗?- 我相信
numpy.reshape
和numpy.transpose
在不复制数据的情况下有效地创建view
- 但是,当数据被访问时,访问模式将通过一堆分层view
通过间接寻址全部破坏。 这岂不是否定了numpy
的连续内存布局的全部意义吗? - 一般来说,这种类型的信息似乎没有在我能找到的任何文档中系统地列出。 我必须求助于阅读
array
/ndarray
SRC吗?
法典
function f
sz = [2 4 3 2];
d = reshape(1:prod(sz),sz)
d = to_np(d)
d = from_np(d)
end
function p = to_np(p)
sz = size(p);
p = reshape(p,[1 numel(p)]); % Conversion to Python is only supported for 1-N vectors.
p = py.numpy.array(p); % if empty, type is always set to double cuz of https://github.com/numpy/numpy/issues/6028
p = p.reshape(num2cell(fliplr(sz)));
t = 0:length(sz)-1;
t(end-[1 0]) = t(end-[0 1]);
p = p.transpose(num2cell(t));
end
function p = from_np(p)
sz = cellfun(@double,cell(p.shape));
method = 1;
switch method
case 1
empty = any(sz == 0);
if empty
p = py.numpy.insert(p,0,0); % casts 0 to p's type so we can later pop it for use with matlab's cast
end
p = py.array.array(p.dtype.char,p.ravel); % does this copy data -- how share memory? any better to use py.numpy.nditer(p), p.flat, or p.flatten?
% http://numpy-discussion.10968.n7.nabble.com/Why-ndarray-provides-four-ways-to-flatten-td38989.html
c = p.pop(); % i can has peek?
if ~empty
p.append(c); % i suspect this could be very inefficient, does it copy the whole thing again?
end
case 2
p = py.numpy.insert(p,p.size,0); % numpy.insert / numpy.append copy the whole array, so maybe worse than array.append?
p = py.array.array(p.dtype.char,p); % numpy.insert already flattened p
c = p.pop();
end
p = cast(p,'like',c);
p = reshape(p,fliplr(sz));
t = 1:length(sz);
t([1 2]) = t([2 1]);
p = permute(p,t);
end
输出
d(:,:,1,1) =
1 3 5 7
2 4 6 8
d(:,:,2,1) =
9 11 13 15
10 12 14 16
d(:,:,3,1) =
17 19 21 23
18 20 22 24
d(:,:,1,2) =
25 27 29 31
26 28 30 32
d(:,:,2,2) =
33 35 37 39
34 36 38 40
d(:,:,3,2) =
41 43 45 47
42 44 46 48
d =
Python ndarray with properties:
T: [1x1 py.numpy.ndarray]
base: [1x1 py.numpy.ndarray]
ctypes: [1x1 py.numpy.core._internal._ctypes]
dtype: [1x1 py.numpy.dtype]
flags: [1x1 py.numpy.flagsobj]
flat: [1x1 py.numpy.flatiter]
imag: [1x1 py.numpy.ndarray]
itemsize: 8
nbytes: 384
ndim: 4
real: [1x1 py.numpy.ndarray]
shape: [1x4 py.tuple]
size: 48
strides: [1x4 py.tuple]
[[[[ 1. 3. 5. 7.]
[ 2. 4. 6. 8.]]
[[ 9. 11. 13. 15.]
[ 10. 12. 14. 16.]]
[[ 17. 19. 21. 23.]
[ 18. 20. 22. 24.]]]
[[[ 25. 27. 29. 31.]
[ 26. 28. 30. 32.]]
[[ 33. 35. 37. 39.]
[ 34. 36. 38. 40.]]
[[ 41. 43. 45. 47.]
[ 42. 44. 46. 48.]]]]
d(:,:,1,1) =
1 3 5 7
2 4 6 8
d(:,:,2,1) =
9 11 13 15
10 12 14 16
d(:,:,3,1) =
17 19 21 23
18 20 22 24
d(:,:,1,2) =
25 27 29 31
26 28 30 32
d(:,:,2,2) =
33 35 37 39
34 36 38 40
d(:,:,3,2) =
41 43 45 47
42 44 46 48
我将一点一点地解决这些问题,逐个编辑
- array.array(.,numpy.ndarray.ravel( 会复制数据吗? 我怀疑是的。 有没有办法分享它? 例如,使用 numpy.nditer((、numpy.ndarray.flat 或 numpy.ndarray.flatten 对性能/内存共享有什么影响? 请参阅 http://numpy-discussion.10968.n7.nabble.com/Why-ndarray-provides-four-ways-to-flatten-td38989.html
np.array
是numpy
数组的正常构造函数,尤其是在从列表开始时。 事实上,我从时间上得到的印象是,它将其所有输入转换为列表(如果是数组(,然后返回,使其对输入的解释和 dtype 具有最大的控制权。
我没有使用太多np.ndarray
,但它似乎是一个更基本的构造函数,如果你想使用预先存在的数据缓冲区制作数组,它很合适。
In [333]: x=np.arange(10)
In [334]: y=np.array(x)
In [335]: x.__array_interface__
Out[335]:
{'shape': (10,),
'version': 3,
'strides': None,
'typestr': '<i4',
'descr': [('', '<i4')],
'data': (158045400, False)}
In [336]: y.__array_interface__
Out[336]:
{'shape': (10,),
'version': 3,
'strides': None,
'typestr': '<i4',
'descr': [('', '<i4')],
'data': (158072688, False)}
"data"下的数字是指向其数据缓冲区的指针。 y
是x
的副本,而不是视图。
对x.flatten().__array_interface__
做同样的事情表明它也是一个副本。 x.ravel().__array_interface__
是一个视图(相同的数据指针(。
x.reshape((-1,1)).__array_interface__
是视图
x.shape = (-1,1)
就地操作中 - 它不仅不会复制数据,也不会复制元数据。
- 我需要一个 array.peek 方法,为什么没有?
peek
应该怎么做? 听起来像是迭代器或其他串行访问对象的前瞻函数。
- 如果我不能拥有 array.peek,array.append 是否像我怀疑的那样低效(再次复制整个数组(? 我本可以使用 numpy.insert 或 numpy.append 代替(这会清理代码,因为我不必对空数组进行特殊处理(,但我相信这些确实会复制。
np.append
使用np.concatenate
,这反过来又会创建一个新数组。 在数组中添加新值一次或两次是可以的,但新用户错误地尝试迭代使用它。 np.insert
也一样。 Python 列表追加更适合迭代工作。
没有办法在不复制的情况下将元素添加到 numpy 数组中。
- F阶有什么负面影响吗?
索引 2D 数组时的访问时间因轴和 C v F 顺序而异。 否则我不会太担心。
- 我相信 Numpy.Reshape 和 Numpy.Transpose 无需复制数据即可有效地创建视图 - 但是,当访问数据时,访问模式将通过一堆分层视图的间接寻址全部破坏。 这难道不是首先否定了Numpy连续内存布局的全部意义吗?
reshape
和transpose
更改shape
和strides
等值,但不会对数据缓冲区执行任何操作。 访问缓冲区中的一个连续数据块会快一些,对于C
顺序数组来说,这意味着类似于 x[3]
或 x[3,:]
. 但是步幅机制应该为任何常规的访问模式提供合理的速度。
- 一般来说,这种类型的信息似乎没有在我能找到的任何文档中系统地列出。 我必须求助于读取数组/ND阵列SRC吗?
我错过了这样一个事实,即一半的问题集中在 Python array
模块上,而不是 numpy
。 我没有使用它,但文档看起来很简单。 和测试:
In [420]: import array
In [421]: xa=array.array('i') # create the array
In [422]: xa.fromlist(np.arange(10).tolist())
# can add elements in various ways, including all the list ones
# so to/from list is always an option
In [423]: xa
Out[423]: array('i', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [424]: xa[3] # can be indexed like a list, not need for a peek
Out[424]: 3
In [425]: xa[8:]
Out[425]: array('i', [8, 9])
ndarray
不像np.array
那样经常使用,但如果已经有数据缓冲区,则很有用。 显然,array.array
符合条件:
In [426]: xn=np.ndarray((10,),int,buffer=xa)
In [427]: xn
Out[427]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
修改xa
中的元素也会在xn
中修改它们,因为共享缓冲区
In [428]: xa[3]=30
In [429]: xn[3]
Out[429]: 30
从xa
中添加或删除元素势必会弄乱xn
。 但是xn
可以重塑、转置等。 对xn
的就地更改(例如 +=(反映在 xa
中。 任何复制xn
的东西都会与xa
失去联系.
每当您将 matlab 数组p
(必须1xN
(传递给 Python 函数时,Matlab 都会自动将其转换为array.array
。 这不适用于 Python 8 中的 2.7 字节整数,那里没有这样的array.array
。 开放性问题:
- 这些对象是否可以共享内存?
- 实际执行此操作的 MATLAB SRC 在哪里? 它似乎是故意隐藏/不透明的,甚至不是
<matlabroot>/toolbox/matlab/external/interfaces/python/+python/+internal/
.
以下是创建与该array.array
共享内存的numpy.ndarray
的方法: py.numpy.ndarray(length(p),py.numpy.dtype(py.numpy(class(p))),pyargs('buffer',p))
. 突变项表明此内存并未一直共享回 MATLAB 的数组。 开放性问题:
- 有没有办法将内存一直共享回 MATLAB?
- 为什么
numpy.array(array.array)
不使用与ndarray
构造函数方法相同的缓冲区共享? - 为什么这里没有提到
ndarray
构造函数? ndarray
构造函数需要知道实际的 MATLAB 类,仅使用 Python 的int
或float
类型(py.type(p(1))
(会导致对缓冲区的错误解释。 这并不是因为内存一直共享到 Matlab——而是因为p(1)
在隔离(int
或float
(时被转换为不同的 Python 类型,而不是当数组的一部分(它将是b, B, h, H, i, I, f or d
array.array
类型之一(时。 对于 4 字节整数,为什么 MATLAB 使用i
/I
而不是l
/L
?- 有没有办法以另一种方式共享内存?
array.array(.,numpy.ndarray)
从 matlab 索引到array.array
的方法(例如最后一个元素(是 py.operator.getitem(p,py.len(p)-1)
。 对于numpy.ndarray
来说,这是p.item(p.size - 1)
。
- 为什么它们不从
collections.Sequence
继承——如果继承了,MATLAB 可以使用p{1}
、p(1)
或cell(p)
索引到它们中。
MATLAB 将数据保存在F order
中。 开放性问题:
- 这可以用来避免
numpy.transpose
和 MATLABpermute
步骤并制作更少的副本吗? - 除了更改元素重塑/扁平化的顺序之外,它的使用是否有任何影响?
方法可以展平 NDaArray。 在这个用例中,哪一个最快,制作的副本最少?
-
.flatten
复制 - 为什么有人想要它? .reshape((-1,))
气馁(我想?.ravel
提出一个观点 - 这是否使它成为最佳选择?numpy.nditer
(或其他像.flatiter
这样的迭代器(是否具有与.ravel
完全相同的空间/时间效率?.flat
呢?p.shape = (-1,)
可能是最好的,因为它甚至不复制元数据(引用?(,但需要一个contiguous
数组,所以通常需要制作副本。 在这个用例中(可能涉及F order
(有没有一种方法可以保证我们是连续的? 是否出于与.reshape((-1,))
相同的原因而气馁? 它有什么不同?
是真的 大量的分层view
不会显着降低ndarray
的性能吗? 参考?
为什么numpy.array
不保留空array.array
的类型? https://github.com/numpy/numpy/issues/6028