理解 numpy.r_() 连接的语法

Posted

技术标签:

【中文标题】理解 numpy.r_() 连接的语法【英文标题】:Understanding the syntax of numpy.r_() concatenation 【发布时间】:2013-01-06 06:00:14 【问题描述】:

我在函数 r_ 的 numpy 文档中阅读了以下内容:

字符串整数指定要堆叠多个逗号的轴 沿分隔数组。由两个逗号分隔的整数组成的字符串 允许指示强制每个维度的最小数量 作为第二个整数进入(要连接的轴是 仍然是第一个整数)。

他们举了这个例子:

>>> np.r_['0,2', [1,2,3], [4,5,6]] # concatenate along first axis, dim>=2
array([[1, 2, 3],
       [4, 5, 6]])

我不明白,字符串 '0,2' 到底是什么指示 numpy 做什么?

除了上面的链接,还有其他网站有更多关于这个功能的文档吗?

【问题讨论】:

【参考方案1】:

您突出显示的段落是两个逗号分隔的整数语法,它是三个逗号分隔的语法的一个特例。一旦你理解了三个逗号分隔的语法,两个逗号分隔的语法就到位了。

您的示例中等效的三个逗号分隔的整数语法为:

np.r_['0,2,-1', [1,2,3], [4,5,6]]

为了提供更好的解释,我将上面的内容更改为:

np.r_['0,2,-1', [1,2,3], [[4,5,6]]]

上面有两部分:

    逗号分隔的整数字符串

    两个逗号分隔的数组

逗号分隔的数组具有以下形状:

np.array([1,2,3]).shape
(3,)

np.array([[4,5,6]]).shape
(1, 3)

换句话说,第一个“数组”是“一维”,而第二个“数组”是“二维”。

首先0,2,-1 中的2 表示每个array 都应升级,以便强制至少为2-dimensional。由于第二个 array 已经是 2-dimensional 它不受影响。然而,第一个array1-dimensional 并且为了使其成为2-dimensional np.r_ 需要在其形状tuple 中添加一个1 以使其成为(1,3)(3,1)。这就是0,2,-1 中的-1 发挥作用的地方。它基本上决定了额外的 1 需要放置在 array 的形状 tuple 中的位置。 -1 是默认设置,并将1(或1s,如果需要更多尺寸)放在形状tuple 的前面(我将在下面解释原因)。这会将第一个array's 形状tuple 转换为(1,3),这与第二个array's 形状tuple 相同。 0,2,-1 中的 0 表示生成的数组需要沿“0”轴连接。

由于arrays 现在都具有tuple(1,3) 的形状,因此连接是可能的,因为如果您在arrays 中留出连接轴(上例中的维度0,其值为1),则剩余维度相等(在这种情况下,arrays 中剩余维度的值都是 3)。如果不是这种情况,则会产生以下错误:

ValueError: 除连接轴外的所有输入数组维度必须完全匹配

现在,如果您连接两个具有(1,3) 形状的arrays,则生成的array 将具有(1+1,3) == (2,3) 形状,因此:

np.r_['0,2,-1', [1,2,3], [[4,5,6]]].shape
(2, 3)

0 或正整数用于逗号分隔字符串中的第三个整数时,该整数确定升级后形状tuple 中每个array's 形状元组的开始(仅适用于那些@987654365 @ 需要升级其尺寸)。例如0,2,0 意味着对于需要形状升级的arraysarray's 原始形状tuple 应该从升级形状tuple 的维度0 开始。对于具有tuple (3,) 形状的array [1,2,3]1 将放在3 之后。这将导致形状tuple 等于(3,1) 并且您可以看到原始形状tuple (3,) 开始于升级形状tuple 的维度00,2,1 意味着对于 [1,2,3]array's 形状 tuple (3,) 应该从升级后的形状元组的维度 1 开始。这意味着 1 需要放置在维度 0 处。生成的形状元组将是 (1,3)

当逗号分隔字符串中的第三个整数使用负数时,负号后面的整数决定了原始形状元组的结束位置。当原始形状元组为(3,) 0,2,-1 表示原始形状元组应在升级形状元组的最后一个维度结束,因此 1 将放置在升级形状元组的维度 0 处,升级后形状元组将是(1,3)。现在(3,) 结束于升级后的形状元组的第 1 维,这也是升级后的形状元组的最后一维(原始数组是 [1,2,3],升级后的数组是 [[1,2,3]])。

np.r_['0,2', [1,2,3], [4,5,6]]

是一样的

np.r_['0,2,-1', [1,2,3], [4,5,6]]

最后是一个更多维度的例子:

np.r_['2,4,1',[[1,2],[4,5],[10,11]],[7,8,9]].shape
(1, 3, 3, 1)

逗号分隔的数组是:

[[1,2],[4,5],[10,11]] 具有形状元组(3,2)

[7,8,9] 具有形状元组(3,)

arrays 都需要升级到4-dimensional arrays。原始的array's 形状元组需要从维度 1 开始。

因此,对于第一个数组,形状变为 (1,3,2,1),因为 3,2 从维度 1 开始,因为需要添加两个 1 才能使其成为 4-dimensional 一个 1 放在原始形状元组之前,一个 1 放在后面。

使用相同的逻辑,第二个数组的形状元组变为(1,3,1,1)

现在需要使用维度 2 作为连接轴连接两个 arrays。从每个数组的升级后的形状元组中消除维度 2 会导致两个 arrays 的元组 (1,3,1)。由于生成的元组是相同的,因此可以连接数组并将连接的轴相加以产生(1, 3, 2+1, 1) == (1, 3, 3, 1)

【讨论】:

感谢您的深入了解!我从来没有完全理解这一点。【参考方案2】:

'n,m' 告诉r_ 沿着axis=n 连接,并生成至少具有m 尺寸的形状:

In [28]: np.r_['0,2', [1,2,3], [4,5,6]]
Out[28]: 
array([[1, 2, 3],
       [4, 5, 6]])

所以我们沿轴=0 连接,因此我们通常期望结果具有形状(6,),但由于m=2,我们告诉r_,形状必须至少是二维的。所以我们得到了形状(2,3)

In [32]: np.r_['0,2', [1,2,3,], [4,5,6]].shape
Out[32]: (2, 3)

看看当我们增加m时会发生什么:

In [36]: np.r_['0,3', [1,2,3,], [4,5,6]].shape
Out[36]: (2, 1, 3)    # <- 3 dimensions

In [37]: np.r_['0,4', [1,2,3,], [4,5,6]].shape
Out[37]: (2, 1, 1, 3) # <- 4 dimensions

您可以使用r_ 执行的任何操作也可以使用更具可读性的数组构建函数之一完成,例如np.concatenatenp.row_stacknp.column_stacknp.hstacknp.vstacknp.dstack ,但可能还需要致电 reshape

即使调用了 reshape,其他函数甚至可能更快:

In [38]: %timeit np.r_['0,4', [1,2,3,], [4,5,6]]
10000 loops, best of 3: 38 us per loop
In [43]: %timeit np.concatenate(([1,2,3,], [4,5,6])).reshape(2,1,1,3)
100000 loops, best of 3: 10.2 us per loop

【讨论】:

unutbu 写道“我不喜欢这种符号。”,我想知道为什么它首先是在 numeric/numarray 中引入的。通常怀疑是 matlab 兼容性,但我转换了 fortran->python 并且我不知道足够的 matlab 来确定...【参考方案3】:

字符串 '0,2' 告诉 numpy 沿轴 0(第一个轴)连接并将元素包装在足够多的括号中以确保二维数组。考虑以下结果:

for axis in (0,1):
    for minDim in (1,2,3):
        print np.r_[','.format(axis, minDim), [1,2,30, 31], [4,5,6, 61], [7,8,90, 91], [10,11, 12, 13]], 'axis=, minDim=\n'.format(axis, minDim)

[ 1  2 30 31  4  5  6 61  7  8 90 91 10 11 12 13] axis=0, minDim=1

[[ 1  2 30 31]
 [ 4  5  6 61]
 [ 7  8 90 91]
 [10 11 12 13]] axis=0, minDim=2

[[[ 1  2 30 31]]

 [[ 4  5  6 61]]

 [[ 7  8 90 91]]

 [[10 11 12 13]]] axis=0, minDim=3

[ 1  2 30 31  4  5  6 61  7  8 90 91 10 11 12 13] axis=1, minDim=1

[[ 1  2 30 31  4  5  6 61  7  8 90 91 10 11 12 13]] axis=1, minDim=2

[[[ 1  2 30 31]
  [ 4  5  6 61]
  [ 7  8 90 91]
  [10 11 12 13]]] axis=1, minDim=3

【讨论】:

以上是关于理解 numpy.r_() 连接的语法的主要内容,如果未能解决你的问题,请参考以下文章

MySQL表连接语法[重复]

Coq初学者在这里,如何理解语法?

JAVA语法技术课第1课day01_Java基础语法&HelloWorld

(转)十步完全理解 SQL

试图理解延迟函数的语法

Elasticsearch教程 Elasticsearch查询语法 Elasticsearch权威指南 深入理解Elasticsearch