numpy.ndarray.flags.contiguous 是关于什么的?

What is numpy.ndarray.flags.contiguous about?

在尝试使用 Numpy 时,我发现 numpy.info 提供的连续值可能与 numpy.ndarray.data.contiguous 不同(请参见下面的代码和屏幕截图)。

import numpy as np

x = np.arange(9).reshape(3,3)[:,(0,1)]

np.info(x)

print(f'''
{x.data.contiguous = }
{x.flags.contiguous = }

{x.data.c_contiguous = }
{x.flags.c_contiguous = }

{x.data.f_contiguous = }
{x.flags.f_contiguous = }
''')

根据documentation about a memoryview class, data.contiguous == True exactly if an array is either C-contiguous or Fortran contiguous. As for numpy.info, I believe it displays the value of flags.contiguous. Alas, there is no information about it in the manual。它到底是什么意思?它是 flags.c_contiguous 的同义词吗?

x = np.arange(9).reshape(3,3)[:,(0,1)]

np.arange(9) 生成一维数组; reshape(3,3) 将其重塑为 2d。它是原始 arangeview。没有订单参数,reshape 坚持使用默认值 c-order

[0,[0,1]]是高级索引,正在制作副本。使用 [0,:2] 进行索引会 select 相同的值,但会生成 view.

info 步幅为 (8,24)。整形后 xstrides 应该是 (24,8),最后一个维度步进 8 个字节,第一个维度步进 3*8。但是高级索引会颠倒过来——这是我们通常忽略(或不知道)的索引细节。

第一个步长较小的二维数组是 F-order

我不会尝试破译所有 data/flats 连续的印刷品,但从形状和步幅来看,基本布局对我来说是显而易见的。我认为步幅优先,所有 'contiguous' 显示都是派生的,可以说是对步幅的解释。

对于 3d(或更高)数组,contiguous 替代方案可能会崩溃。可以制作一个步幅为 (48,8,24) 的数组,其中中间维度步幅最快。这既不是 c 也不是 f 连续。

我可能会补充一点,除非你正在做类似

的事情
np.arange(9).reshape(3,3, order='F')

邻接类型通常不是我们担心的事情。一些函数(尤其是编译函数)需要一定的连续性。并且某些操作更快(或更慢)取决于哪个维度 'inner-most'。但是对于普通的numpy使用我不太关注flags。在意识到您的示例索引翻转了 order.

之前,我使用了 numpy 多年

您可以直接显示 x.flags。我不确定显示 x.data 对你有什么用。

编辑

x,在我的会话中创建为 int32:

x
Out[28]: 
array([[0, 1],
       [3, 4],
       [6, 7]])

x.strides
Out[29]: (4, 12)

我通常使用__array_interface__而不是np.info,但信息是相似的:

x.__array_interface__
Out[30]: 
{'data': (1175190303648, False),
 'strides': (4, 12),
 'descr': [('', '<i4')],
 'typestr': '<i4',
 'shape': (3, 2),
 'version': 3}

我通常更关注 strides 而不是标志,但这里是完整显示:

x.flags
Out[31]: 
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False

为什么 owndata 是错误的?显然索引实际上创建了:

x.base
Out[32]: 
array([[0, 3, 6],
       [1, 4, 7]])

然后 returns 转置。 c_contiguous 数组的转置是 f_contiguous.

如果我创建相同的数组(按值)但使用切片,我得到一个 view 在任何意义上都不连续:

y = np.arange(9).reshape(3,3)[:,:2]

y
Out[34]: 
array([[0, 1],
       [3, 4],
       [6, 7]])

y.strides
Out[35]: (12, 4)

y.base
Out[36]: array([0, 1, 2, 3, 4, 5, 6, 7, 8])

y.flags
Out[37]: 
  C_CONTIGUOUS : False
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False

它是 base 值的不连续子集。 base 是原始 np.arange(...),而不是 reshaped 结果。

numpy.infosource code中可以看到处理ndarray的子程序:

def info(object=None, maxwidth=76, output=None, toplevel='numpy'):
    ...
    elif isinstance(object, ndarray):
        _info(object, output=output)
    ...

def _info(obj, output=None):
    """Provide information about ndarray obj"""
    bp = lambda x: x
    ...
    print("contiguous: ", bp(obj.flags.contiguous), file=output)
    print("fortran: ", obj.flags.fortran, file=output)
    ...

它returns flags.contiguous作为数组的连续性参数。这个没有在 flags description. But we can find it in flagsobject.c:

中指定
// ...
static PyGetSetDef arrayflags_getsets[] = {
    {"contiguous",
        (getter)arrayflags_contiguous_get,
        NULL,
        NULL, NULL},
    {"c_contiguous",
        (getter)arrayflags_contiguous_get,
        NULL,
        NULL, NULL},
// ...

现在很清楚 numpy.infocontiguous 参数实际上是 flags.c_contiguous 并且与 ndarray.data.contiguous 没有任何共同之处。我想在用 C 编程时,很自然地只说 contiguous 而不是 c_contiguous,这导致了术语上的轻微不一致。