【问题标题】:How to access the ith column of a NumPy multidimensional array?如何访问 NumPy 多维数组的第 i 列?
【发布时间】:2011-05-26 04:48:15
【问题描述】:

假设我有:

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

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

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:
    >>> test[:,0]
    array([1, 3, 5])
    

    同样,

    >>> test[1,:]
    array([3, 4])
    

    允许您访问行。这在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。
    【解决方案2】:

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

    >>> 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]] 确实如您所说创建了一个副本。
    • 这会创建一个副本,是否可以获得引用,就像我获得了对某些列的引用一样,此引用的任何更改都会反映在原始数组中?
    • @harman786 您可以将修改后的数组重新分配给旧数组。
    • 为什么test[:,[0,2]] 只访问数据而test[:, [0, 2]][:, [0, 1]] 不访问?再次做同样的事情会产生不同的结果似乎非常不直观。
    【解决方案3】:
    >>> 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,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]] 快四倍
    【解决方案4】:
    >>> 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]])
    

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

      • 在寻找访问列的最快方法之前,我已经这样做了一段时间,我想知道这是更快、更慢还是与 test[:,[0]] 相同/跨度>
      【解决方案6】:

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

      > test[:,[0,2]]
      

      你会得到第 0 列和第 2 列

      【讨论】:

      • 这与 Akavall 的 answer 有何不同?
      【解决方案7】:

      虽然问题已经得到解答,但我还是要提一些细微差别。

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

      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 µ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
      

      【讨论】:

        【解决方案8】:

        这不是多维的。它是二维数组。您希望在哪里访问所需的列。

        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 开始的任何数字。二维并不是特例,只是它最符合我们对行和列的直觉。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多