【发布时间】:2011-05-26 04:48:15
【问题描述】:
假设我有:
test = numpy.array([[1, 2], [3, 4], [5, 6]])
test[i] 获取数组的ith 行(例如[1, 2])。如何访问 ith 列? (例如[1, 3, 5])。另外,这会是一项昂贵的操作吗?
【问题讨论】:
假设我有:
test = numpy.array([[1, 2], [3, 4], [5, 6]])
test[i] 获取数组的ith 行(例如[1, 2])。如何访问 ith 列? (例如[1, 3, 5])。另外,这会是一项昂贵的操作吗?
【问题讨论】:
>>> test[:,0]
array([1, 3, 5])
同样,
>>> test[1,:]
array([3, 4])
允许您访问行。这在NumPy reference 的第 1.4 节(索引)中有介绍。这很快,至少在我的经验中。这肯定比在循环中访问每个元素要快得多。
【讨论】:
A[a:b, c:d],它选择行 a 到 b,列 c 到 d。
如果您想一次访问多个列,您可以这样做:
>>> 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 将修改测试,而不是创建另一个数组。但copy_test = test[:, [0,2]] 确实如您所说创建了一个副本。
test[:,[0,2]] 只访问数据而test[:, [0, 2]][:, [0, 1]] 不访问?再次做同样的事情会产生不同的结果似乎非常不直观。
>>> test[:,0]
array([1, 3, 5])
这个命令给你一个行向量,如果你只是想循环它,没问题,但如果你想与其他维度为 3xN 的数组进行 hstack,你将拥有
ValueError: all the input arrays must have same number of dimensions
同时
>>> test[:,[0]]
array([[1],
[3],
[5]])
为您提供一个列向量,以便您可以进行连接或 hstack 操作。
例如
>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
[3, 4, 3],
[5, 6, 5]])
【讨论】:
test[:,0].reshape(test.shape[0], -1) 之类的事情,至少可以这么说。
>>> 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]])
【讨论】:
你也可以转置并返回一行:
In [4]: test.T[0]
Out[4]: array([1, 3, 5])
【讨论】:
要获得多个独立的列,只需:
> test[:,[0,2]]
你会得到第 0 列和第 2 列
【讨论】:
虽然问题已经得到解答,但我还是要提一些细微差别。
假设您对数组的第一列感兴趣
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
两者除了明显的区别(修改arr_col1_view会影响arr)外,每个遍历的字节步数都不一样:
arr_col1_view.strides[0] # 8 bytes
arr_col1_copy.strides[0] # 4 bytes
为什么这很重要?想象一下,您有一个非常大的数组 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 µs 来创建 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
【讨论】:
这不是多维的。它是二维数组。您希望在哪里访问所需的列。
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 开始的任何数字。二维并不是特例,只是它最符合我们对行和列的直觉。