我该如何使用np.newaxis?

373

什么是numpy.newaxis,我何时应该使用它?

在1维数组x上使用它会产生:

>>> x
array([0, 1, 2, 3])

>>> x[np.newaxis, :]
array([[0, 1, 2, 3]])

>>> x[:, np.newaxis]
array([[0],
       [1],
       [2],
       [3]])

4
除了将行向量转换为列向量外,它还有什么不同之处?第一个示例不是行向量。那是Matlab的概念,在Python中它只是一个没有行或列概念的一维向量。行向量或列向量是二维的,就像第二个示例。 - endolith
5
那个术语并不来自matlab,它是一个数学概念,并且是描述他的示例中的数组的一种完全有效的方式。https://math.stackexchange.com/questions/1198729/row-vector-vs-column-vector - rocksNwaves
5个回答

674
简而言之,当使用一次numpy.newaxis时,它被用于将现有数组的维度增加一个维度。因此,

  • 1D 数组将变为 2D 数组

  • 2D 数组将变为 3D 数组

  • 3D 数组将变为 4D 数组

  • 4D 数组将变为 5D 数组

以此类推。

下面是一个可视化示例,展示了将 1D 数组提升为 2D 数组的过程。

newaxis canva visualization


场景-1:当你想要将 1D 数组显式转换为行向量或列向量时,np.newaxis可能会派上用场,就像上面的图片所示。

例如:

# 1D array
In [7]: arr = np.arange(4)
In [8]: arr.shape
Out[8]: (4,)

# make it as row vector by inserting an axis along first dimension
In [9]: row_vec = arr[np.newaxis, :]     # arr[None, :]
In [10]: row_vec.shape
Out[10]: (1, 4)

# make it as column vector by inserting an axis along second dimension
In [11]: col_vec = arr[:, np.newaxis]     # arr[:, None]
In [12]: col_vec.shape
Out[12]: (4, 1)

场景-2: 当我们想在某些操作中利用numpy广播,例如在数组加法时。

例子:

假设你想要将以下两个数组相加:

 x1 = np.array([1, 2, 3, 4, 5])
 x2 = np.array([5, 4, 3])

如果您直接尝试添加这些元素,NumPy会引发以下“ValueError”异常:
ValueError: operands could not be broadcast together with shapes (5,) (3,)

在这种情况下,您可以使用 np.newaxis 来增加其中一个数组的维数,以便NumPy可以进行 广播
In [2]: x1_new = x1[:, np.newaxis]    # x1[:, None]
# now, the shape of x1_new is (5, 1)
# array([[1],
#        [2],
#        [3],
#        [4],
#        [5]])

现在,添加:
In [3]: x1_new + x2
Out[3]:
array([[ 6,  5,  4],
       [ 7,  6,  5],
       [ 8,  7,  6],
       [ 9,  8,  7],
       [10,  9,  8]])

或者,您还可以向数组x2添加新轴:

In [6]: x2_new = x2[:, np.newaxis]    # x2[:, None]
In [7]: x2_new     # shape is (3, 1)
Out[7]: 
array([[5],
       [4],
       [3]])

现在,添加:
In [8]: x1 + x2_new
Out[8]: 
array([[ 6,  7,  8,  9, 10],
       [ 5,  6,  7,  8,  9],
       [ 4,  5,  6,  7,  8]])

注意:请注意,在这两种情况下我们得到了相同的结果(但其中一种是另一种的转置)。


场景-3:这类似于场景-1。但是,您可以使用np.newaxis多次来将数组提升到更高的维度。对于高阶数组(即张量),有时需要进行这样的操作。

示例:

In [124]: arr = np.arange(5*5).reshape(5,5)

In [125]: arr.shape
Out[125]: (5, 5)

# promoting 2D array to a 5D array
In [126]: arr_5D = arr[np.newaxis, ..., np.newaxis, np.newaxis]    # arr[None, ..., None, None]

In [127]: arr_5D.shape
Out[127]: (1, 5, 5, 1, 1)

作为替代方案,您可以使用numpy.expand_dims,它具有直观的axis关键字。

# adding new axes at 1st, 4th, and last dimension of the resulting array
In [131]: newaxes = (0, 3, -1)
In [132]: arr_5D = np.expand_dims(arr, axis=newaxes)
In [133]: arr_5D.shape
Out[133]: (1, 5, 5, 1, 1)

关于 np.newaxisnp.reshape 的更多背景信息

newaxis 也被称为伪索引,它允许将一个轴临时添加到多维数组中。

np.newaxis 使用切片操作符来重新创建数组,而numpy.reshape 重塑数组以获得所需的布局(假定尺寸匹配,这是进行 reshape 必须的)。

示例

In [13]: A = np.ones((3,4,5,6))
In [14]: B = np.ones((4,6))
In [15]: (A + B[:, np.newaxis, :]).shape     # B[:, None, :]
Out[15]: (3, 4, 5, 6)

在上面的例子中,我们在B的第一个和第二个轴之间插入了一个临时轴(使用广播)。这里使用np.newaxis来填充缺失的轴,以使广播操作起作用。
常规提示: 您还可以使用None代替np.newaxis;实际上它们是同一对象
In [13]: np.newaxis is None
Out[13]: True

P.S. 还可以参考这个很好的答案:newaxis与reshape添加维度的区别


4
x1_new + x2 是什么类型的运算?对我来说有些奇怪,因为我认为只有当两个矩阵具有相同的维度(或者其中一个实际上只是一个标量)时才能进行加法运算。 - Stephen
3
@Stephen 我在答案中也指出了,这是由于NumPy广播机制导致的。 - kmario23
2
要么@kmario23等于Ian Dzindo,要么Ian Dzindo01在2018年Medium帖子中抄袭了这个答案:https://medium.com/@ian.dzindo01/what-is-numpy-newaxis-and-when-to-use-it-8cb61c7ed6ae。 - Chiraz BenAbdelkader
@ChirazBenAbdelkader 我并不是那篇 Medium 文章的作者。是的,这是完全复制,但文章末尾有来源说明,尽管我更希望它在文章开头。 - kmario23
3
@kmario23 实际上,归属权在文章的最后一句话中隐藏,难怪我没有看到它。即使有这个归属权声明,我仍认为这是边缘抄袭。在我的书中,逐字逐句地复制只有在同一作者在不同平台上发布时才是可以接受的。我对Medium的期望更高。 - Chiraz BenAbdelkader
8
等等,全都是None?- 一直都是这样。 - Darkonaut

53

什么是 np.newaxis

np.newaxis只是Python常量None的别名,这意味着无论何时使用np.newaxis,您也可以使用None

>>> np.newaxis is None
True

如果你读的代码使用np.newaxis而不是None,那么它会更描述性。

如何使用np.newaxis

np.newaxis通常与切片一起使用。它表示您想要将一个附加维度添加到数组中。 np.newaxis的位置表示我想要添加维度的位置。

>>> import numpy as np
>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a.shape
(10,)

在第一个示例中,我使用了第一维度的所有元素,并添加了第二个维度:

>>> a[:, np.newaxis]
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [7],
       [8],
       [9]])
>>> a[:, np.newaxis].shape
(10, 1)

第二个示例将一个维度作为第一维添加,然后使用原始数组的第一维中的所有元素作为结果数组的第二维中的元素:

>>> a[np.newaxis, :]  # The output has 2 [] pairs!
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
>>> a[np.newaxis, :].shape
(1, 10)

同样地,您可以使用多个np.newaxis来添加多个维度:

>>> a[np.newaxis, :, np.newaxis]  # note the 3 [] pairs in the output
array([[[0],
        [1],
        [2],
        [3],
        [4],
        [5],
        [6],
        [7],
        [8],
        [9]]])
>>> a[np.newaxis, :, np.newaxis].shape
(1, 10, 1)

有没有np.newaxis的替代方案?

NumPy中还有一个非常类似的功能:np.expand_dims,它也可以用于插入一个维度:

>>> np.expand_dims(a, 1)  # like a[:, np.newaxis]
>>> np.expand_dims(a, 0)  # like a[np.newaxis, :]

但是,考虑到它只在shape中插入1,您也可以使用reshape函数来添加这些维度:

>>> a.reshape(a.shape + (1,))  # like a[:, np.newaxis]
>>> a.reshape((1,) + a.shape)  # like a[np.newaxis, :]

大多数情况下,np.newaxis是添加维度的最简单方法,但了解替代方案也很好。

何时使用np.newaxis

在几个情境下,添加维度很有用:

  • 如果数据应该有指定数量的维度。例如,如果要使用matplotlib.pyplot.imshow显示1D数组。

  • 如果你想让NumPy广播数组。通过添加一个维度,你可以得到例如一个数组中所有元素之间的差异:a - a[:, np.newaxis]。这是因为NumPy操作从最后一个维度开始广播 1

  • 添加必要的维度以使NumPy能够广播数组。这是因为每个长度为1的维度只需广播到其他数组的相应1维度的长度即可。


1 如果想要阅读更多关于广播规则的内容,NumPy文档非常好。它还包括一个关于np.newaxis的例子:

>>> a = np.array([0.0, 10.0, 20.0, 30.0])
>>> b = np.array([1.0, 2.0, 3.0])
>>> a[:, np.newaxis] + b
array([[  1.,   2.,   3.],
       [ 11.,  12.,  13.],
       [ 21.,  22.,  23.],
       [ 31.,  32.,  33.]])

我并没有看到第二种和第三种用例之间的区别;它们都是关于允许 NumPy 将数组广播为某些操作的一部分。如果不是这样的话,那么在第三种用例中添加一个示例以澄清该点会有所帮助。 - Chiraz BenAbdelkader
@ChirazBenAbdelkader 是的,区别并不是很明显。我不确定是否应该删除第三点或将其合并到第二点中。 - MSeifert

12
你从一个一维数字列表开始。一旦使用 numpy.newaxis,就将其转换为由四行每列一个元素组成的二维矩阵。
然后你可以将该矩阵用于矩阵乘法,或者将其包含在构建的更大的 4 x n 矩阵中。

6

newaxis 在选择元组中的对象用于扩展结果选择的维度,增加一个单位长度的维度。

它不仅仅是将行矩阵转换成列矩阵。

考虑下面的例子:

In [1]:x1 = np.arange(1,10).reshape(3,3)
       print(x1)
Out[1]: array([[1, 2, 3],
               [4, 5, 6],
               [7, 8, 9]])

现在让我们为我们的数据添加新的维度,
In [2]:x1_new = x1[:,np.newaxis]
       print(x1_new)
Out[2]:array([[[1, 2, 3]],

              [[4, 5, 6]],

              [[7, 8, 9]]])

你可以看到,newaxis 在这里添加了额外的维度,x1 的维度为 (3,3),而 X1_new 的维度为 (3,1,3)。
我们新维度如何使我们能够执行不同的操作:
In [3]:x2 = np.arange(11,20).reshape(3,3)
       print(x2)
Out[3]:array([[11, 12, 13],
              [14, 15, 16],
              [17, 18, 19]]) 

将x1_new和x2相加,我们得到:

In [4]:x1_new+x2
Out[4]:array([[[12, 14, 16],
               [15, 17, 19],
               [18, 20, 22]],

              [[15, 17, 19],
               [18, 20, 22],
               [21, 23, 25]],

              [[18, 20, 22],
               [21, 23, 25],
               [24, 26, 28]]])

因此,newaxis 不仅仅是将行转换为列矩阵。它增加了矩阵的维度,从而使我们能够在其上执行更多操作。

2
它不仅适用于矩阵,还适用于NumPy术语中的任何“ndarray”。 - kmario23
...并且甚至包括PyTorch张量 - Wizard Z.

0
它在哪里扩展模糊。
例如:arr[newaxis] 等于 expand_dims(arr, 0)arr[:, newaxis] 等于 expand_dims(arr, 1)arr[:, :, newaxis] 等于 expand_dims(arr, 2)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接