ChatGPT解决这个技术问题 Extra ChatGPT

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

鉴于:

test = numpy.array([[1, 2], [3, 4], [5, 6]])

test[i] 给出 ith 行(例如 [1, 2])。如何访问 ith 列? (例如 [1, 3, 5])。另外,这会是一项昂贵的操作吗?


M
Mateen Ulhaq

要访问第 0 列:

>>> test[:, 0]
array([1, 3, 5])

要访问第 0 行:

>>> test[0, :]
array([1, 2])

NumPy reference 的第 1.4 节(索引)对此进行了介绍。这很快,至少在我的经验中。这肯定比在循环中访问每个元素要快得多。


这创建了一个副本,是否可以获取引用,就像我获取对列的引用一样,此引用的任何更改都会反映在原始数组中。
只是为了确保,考虑 test.shape=(2,x,y)。 test[:,0 :, :, ] 是访问第一个“列”(坐标)的方式是否正确?
您将如何选择多列和多行?
@AAAlex123 - 见 Akavall 的回答[stackoverflow.com/a/16121210/120261]
@mtrw,更准确地说,我指的是选择一系列列,而不是特定列,例如第 1-5 列。阅读文档后,我发现了这种语法 A[a:b, c:d],它选择了 a 到 b 行和 c 到 d 列。
N
Neuron
>>> test[:,0]
array([1, 3, 5])

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

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

尽管

>>> test[:,[0]]
array([[1],
       [3],
       [5]])

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

例如

>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
       [3, 4, 3],
       [5, 6, 5]])

索引一次也可以处理多于一列,因此最后一个示例可以是 test[:,[0,1,0]] 或 test[:,[range(test.shape[1])+ [0]] ]
+1 用于指定 [:,[0]] 与 [:,0] 以获得列向量而不是行向量。正是我正在寻找的行为。还 +1 到 lib 以获取额外的索引说明。这个答案应该与最佳答案一起出现。
必须选择这个答案
感谢您的 [:,[0]]。根据最佳答案,我尝试做类似 test[:,0].reshape(test.shape[0], -1) 的事情,这至少可以说是不好的。
[:, i:i+1] 例如 [:, 0:1] 可能会更好。出于某种原因,它对我来说比 [:, [i]] 快四倍
A
Akavall

如果您想一次访问多个列,您可以这样做:

>>> 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]])

当然,在这种情况下,您不仅仅是访问数据;您正在返回一份副本(精美的索引)
test[:,[0,2]] 只是访问数据,例如,test[:, [0,2]] = something 会修改 test,而不是创建另一个数组。但 copy_test = test[:, [0,2]] 实际上确实如您所说创建了一个副本。
这会创建一个副本,是否可以获得引用,就像我获得对某些列的引用一样,此引用的任何更改都会反映在原始数组中?
@ harman786 您可以将修改后的数组重新分配给旧数组。
为什么 test[:,[0,2]] 只访问数据而 test[:, [0, 2]][:, [0, 1]] 不访问?再次做同样的事情会产生不同的结果,这似乎非常不直观。
H
Hotschke

您还可以转置并返回一行:

In [4]: test.T[0]
Out[4]: array([1, 3, 5])

在寻找访问列的最快方法之前,我已经这样做了一段时间,我想知道这是否更快、更慢或与 test[:,[0]] 相同
A
Andreas K.

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

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

arr = numpy.array([[1, 2],
                   [3, 4],
                   [5, 6]])

正如您从其他答案中已经知道的那样,要以“行向量”(形状 (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

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

arr_col1_view.base is arr  # True
arr_col1_copy.base is arr  # False

ndarray.base

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

arr_col1_view.strides[0]  # 8 bytes
arr_col1_copy.strides[0]  # 4 bytes

请参阅 strides 和此 answer

为什么这很重要?假设您有一个非常大的数组 A 而不是 arr

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

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

%timeit A_col1_view.sum()  # ~248 µs
%timeit A_col1_copy.sum()  # ~12.8 µs

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

A_col1_view.strides[0]  # 40000 bytes
A_col1_copy.strides[0]  # 4 bytes

尽管使用列副本似乎更好,但并非总是如此,因为制作副本也需要时间并使用更多内存(在这种情况下,我花了大约 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

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

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

A[:, 1].strides[0]    # 40000 bytes
A.T[1, :].strides[0]  # 40000 bytes

A
Alberto Perez

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

> test[:,[0,2]]

您将获得第 0 列和第 2 列


这与 Akavall 的 answer 有何不同?
m
mac
>>> test
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> ncol = test.shape[1]
>>> ncol
5L

然后您可以通过这种方式选择第 2 - 4 列:

>>> test[0:, 1:(ncol - 1)]
array([[1, 2, 3],
       [6, 7, 8]])

d
dinesh kumar

这不是多维的。它是二维数组。您要访问所需列的位置。

test = numpy.array([[1, 2], [3, 4], [5, 6]])
test[:, a:b]  # you can provide index in place of a and b

2 是一个“多”。 multidimensional 不限于 3 个或 4 个或更多。 numpy 中的基数组类是 ndarray,其中 n 代表从 0 开始的任意数字。二维并不是一个特例,除了它最符合我们对行和列的直觉。