如何将多维数组从 matlab 交换到 python/numpy 并返回



我认为这段代码正确处理了 n-d(请验证(,我已经将其破解为多态性,但它很丑陋。 有没有更好/更有效的方法?我不确定它是否尽可能多地共享内存。 我想避免F order,我猜 Numpy/Python 对C更满意。 如果我错了,请启发我在这种情况下使用F的任何优势。

具体问题(如果这种整体方法最好(:

  • array.array(.,numpy.ndarray.ravel)复制数据吗? 我怀疑是的。 有没有办法分享它? 例如,改用numpy.nditer()numpy.ndarray.flatnumpy.ndarray.flatten的性能/内存共享影响是什么? 见 http://numpy-discussion.10968.n7.nabble.com/Why-ndarray-provides-four-ways-to-flatten-td38989.html
  • 我需要一个array.peek的方法,为什么没有?
  • 如果我不能array.peekarray.append是否像我怀疑的那样低效(再次复制整个数组(? 我本可以使用numpy.insertnumpy.append代替(这会清理代码,因为我不必对空数组进行特殊处理(,但我相信这些确实会复制。
  • F order有什么负面影响吗?
  • 我相信numpy.reshapenumpy.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.arraynumpy数组的正常构造函数,尤其是在从列表开始时。 事实上,我从时间上得到的印象是,它将其所有输入转换为列表(如果是数组(,然后返回,使其对输入的解释和 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"下的数字是指向其数据缓冲区的指针。 yx的副本,而不是视图。

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连续内存布局的全部意义吗?

reshapetranspose更改shapestrides等值,但不会对数据缓冲区执行任何操作。 访问缓冲区中的一个连续数据块会快一些,对于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 的 intfloat类型(py.type(p(1))(会导致对缓冲区的错误解释。 这并不是因为内存一直共享到 Matlab——而是因为p(1)在隔离(intfloat(时被转换为不同的 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和 MATLAB permute步骤并制作更少的副本吗?
  • 除了更改元素重塑/扁平化的顺序之外,它的使用是否有任何影响?
有很多

方法可以展平 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

最新更新