如何访问NumPy多维数组的第i列?

lpl*_*lpl 411 python arrays numpy

假设我有:

test = numpy.array([[1, 2], [3, 4], [5, 6]])
Run Code Online (Sandbox Code Playgroud)

test[i]让我第i个阵列(例如线[1, 2]).我怎样才能访问第i列?(例如[1, 3, 5]).这也是一项昂贵的操作吗?

mtr*_*trw 618

>>> test[:,0]
array([1, 3, 5])
Run Code Online (Sandbox Code Playgroud)

同样的,

>>> test[1,:]
array([3, 4])
Run Code Online (Sandbox Code Playgroud)

允许您访问行.这将在NumPy参考的第1.4节(索引)中介绍.这很快,至少在我的经验中.它肯定比访问循环中的每个元素快得多.

  • 这创建了一个副本,是否可以获得引用,就像我获得对列的引用一样,此引用中的任何更改都会反映在原始数组中. (9认同)
  • 文档中更有用的部分:[维度索引工具](https://numpy.org/doc/stable/user/basics.indexing.html#Dimensional-indexing-tools) (2认同)

Aka*_*all 63

如果您希望一次访问多个列,则可以执行以下操作:

>>> test = np.arange(9).reshape((3,3))
>>> test
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> test[:,[0,2]]
array([[0, 2],
       [3, 5],
       [6, 8]])
Run Code Online (Sandbox Code Playgroud)

  • `test [:,[0,2]]`只是访问数据,例如`test [:,[0,2]] = something`会修改test,而不是创建另一个数组.但是`copy_test = test [:,[0,2]]`确实会像你说的那样创建一个副本. (12认同)
  • 这创建了一个副本,是否有可能获得引用,就像我得到一些列的引用一样,这个引用中的任何更改都反映在原始数组中? (3认同)

Clo*_*oud 57

>>> test[:,0]
array([1, 3, 5])
Run Code Online (Sandbox Code Playgroud)

这个命令给你一个行向量,如果你只想循环它,它没关系,但是如果你想要使用尺寸为3xN的其他数组进行hstack,你将拥有

ValueError:所有输入数组必须具有相同的维数

ValueError: all the input arrays must have same number of dimensions
Run Code Online (Sandbox Code Playgroud)

为您提供列向量,以便您可以进行连接或hstack操作.

例如

>>> test[:,[0]]
array([[1],
       [3],
       [5]])
Run Code Online (Sandbox Code Playgroud)

  • +1用于指定[:,[0]] vs [:,0]以获取列向量而不是行向量.正是我正在寻找的行为.此外,还有+1到lib的附加索引注释.这个答案应该是最好的答案. (5认同)

Hot*_*hke 22

你也可以转置并返回一行:

In [4]: test.T[0]
Out[4]: array([1, 3, 5])
Run Code Online (Sandbox Code Playgroud)


And*_*dyK 16

虽然这个问题已经回答了,但让我提一些细微差别。

假设您对数组的第一列感兴趣

arr = numpy.array([[1, 2],
                   [3, 4],
                   [5, 6]])
Run Code Online (Sandbox Code Playgroud)

正如您从其他答案中已经知道的那样,要以“行向量”(形状数组(3,))的形式获取它,您可以使用切片:

arr_col1_view = arr[:, 1]         # creates a view of the 1st column of the arr
arr_col1_copy = arr[:, 1].copy()  # creates a copy of the 1st column of the arr
Run Code Online (Sandbox Code Playgroud)

要检查数组是视图还是另一个数组的副本,您可以执行以下操作:

arr_col1_view.base is arr  # True
arr_col1_copy.base is arr  # False
Run Code Online (Sandbox Code Playgroud)

ndarray.base

除了两者之间的明显区别(修改arr_col1_view会影响arr),遍历它们的字节步数是不同的:

arr_col1_view.strides[0]  # 8 bytes
arr_col1_copy.strides[0]  # 4 bytes
Run Code Online (Sandbox Code Playgroud)

看到strides和这个答案

为什么这很重要?想象一下,您有一个非常大的数组A而不是arr

A = np.random.randint(2, size=(10000, 10000), dtype='int32')
A_col1_view = A[:, 1] 
A_col1_copy = A[:, 1].copy()
Run Code Online (Sandbox Code Playgroud)

并且您想计算第一列的所有元素的总和,即A_col1_view.sum()or A_col1_copy.sum()。使用复制版本要快得多:

%timeit A_col1_view.sum()  # ~248 µs
%timeit A_col1_copy.sum()  # ~12.8 µs
Run Code Online (Sandbox Code Playgroud)

这是由于前面提到的步幅数不同造成的:

A_col1_view.strides[0]  # 40000 bytes
A_col1_copy.strides[0]  # 4 bytes
Run Code Online (Sandbox Code Playgroud)

虽然看起来使用列副本更好,但并非总是如此,因为制作副本也需要时间并使用更多内存(在这种情况下,我花了大约 200 微秒来创建A_col1_copy)。但是,如果我们首先需要复制,或者我们需要对数组的特定列执行许多不同的操作,并且我们可以牺牲内存来提高速度,那么制作复制是可行的方法。

在我们主要对列感兴趣的情况下,以列优先 ('F') 顺序而不是行优先 ('C') 顺序(这是默认值)创建数组可能是个好主意,然后像以前一样进行切片以获取一列而不复制它:

A = np.asfortranarray(A)   # or np.array(A, order='F')
A_col1_view = A[:, 1]
A_col1_view.strides[0]     # 4 bytes

%timeit A_col1_view.sum()  # ~12.6 µs vs ~248 µs
Run Code Online (Sandbox Code Playgroud)

现在,在列视图上执行 sum 操作(或任何其他操作)与在列副本上执行它一样快。

最后让我注意,转置数组并使用行切片与在原始数组上使用列切片相同,因为转置只是通过交换原始数组的形状和步幅来完成的。

A[:, 1].strides[0]    # 40000 bytes
A.T[1, :].strides[0]  # 40000 bytes
Run Code Online (Sandbox Code Playgroud)


Alb*_*rez 6

要获得几个独立的列,只需:

> test[:,[0,2]]
Run Code Online (Sandbox Code Playgroud)

你会得到第0列和第2列

  • 这与Akavall的[answer](/sf/answers/1128484731/)有何不同? (2认同)