[Python] NumPy Indexing

程式語言:Python
Package:numpy
官方文件

簡介:NumPy indexing 的使用

Indexing

ndarrays indexing 的方法,即是 x[obj]
obj 的型態會影響賦於的 array 是 view 還是 copy
  • view:與其他 array 共用空間,改值會互相影響
  • copy:與其他 array 不共用空間,改值不會互相影響
import numpy as np

x = np.array([[ 0, 1, 2],
              [ 3, 4, 5],
              [ 6, 7, 8],
              [ 9, 10, 11]])
view = x[1:2, 1:3]
copy = x[1:2, [1, 2]]
print(view) # [[4 5]]
view[0] = 100
print(view) # [[100 100]]
print(x)
# [[  0   1   2]
 # [  3 100 100]
 # [  6   7   8]
 # [  9  10  11]]
print(copy) # [[4 5]]
copy[0] = 200
print(copy) # [[200 200]]
print(x)
# [[  0   1   2]
 # [  3 100 100]
 # [  6   7   8]
 # [  9  10  11]]

Basic Slicing and Indexing

  • view 型態
  • obj
    • slice object (start:stop:step)
      import numpy as np
      
      x = np.array([1, 2, 3, 4])
      view = x[-1::-1]
      print(view) # [4 3 2 1]
      view[0] = 100
      print(x) # [  1   2   3 100]
      
    • an integer
      import numpy as np
      
      x = np.array([[1, 2], [3, 4]])
      view = x[:, 1]
      print(view) # [2 4]
      view[0] = 100
      print(x)
      # [[  1 100]
      #  [  3   4]]
      
    • a tuple of slice objects and integers
      import numpy as np
      
      x = np.array([[1, 2], [3, 4]])
      view = x[(slice(0,2), 1)] # 等同 x[0:2, 1]
      print(view) # [2 4]
      view[0] = 100
      print(x)
      # [[  1 100]
      #  [  3   4]]
      
    • ... (Ellipsis),表示剩餘的其他維度,等同 (:, :, :, ...),甚至可能為空
      import numpy as np
      
      x = np.array([[1, 2], [3, 4]])
      view = x[..., 1]
      print(view) # [2 4]
      view[0] = 100
      print(x)
      # [[  1 100]
      #  [  3   4]]
      
    • np.newaxis
      import numpy as np
      
      x = np.array([[1, 2], [3, 4]])
      # 等同 view = x[:, None]
      view = x[:, np.newaxis]
      print(view.shape) # (2, 1, 2)
      print(view)
      # [[[1 2]]
      #  [[3 4]]]
      view[0] = 100
      print(x)
      # [[100 100]
      #  [  3   4]]
      
  • dimension
    • 若為 integer, \(D = D - 1\),np.newaxis 則 \(D = D + 1\)
      import numpy as np
      
      x = np.ones((1, 2, 3, 4, 5, 6))
      print(x.shape)                   # (1, 2, 3, 4, 5, 6)
      print(x[:].shape)                # (1, 2, 3, 4, 5, 6)
      print(x[:, 1].shape)             # (1, 3, 4, 5, 6)
      print(x[:, 0:1].shape)           # (1, 1, 3, 4, 5, 6)
      print(x[0:1, ...].shape)         # (1, 2, 3, 4, 5, 6)
      print(x[:, :, np.newaxis].shape) # (1, 2, 1, 3, 4, 5, 6)
      
    • 若 x[obj] 的 \(D = 1\) 則回傳 scalar,此時不影響原 array
      import numpy as np
      
      x = np.array([1, 2, 3, 4])
      view = x[0]
      print(type(view)) # <class 'numpy.int32'>
      view = 100
      print(x) # [1 2 3 4]
      
  • 等效表示
    • In python
      x[(exp1, exp2, ..., expN)] == x[exp1, exp2, ..., expN]
    • 只有 interger 可拆分
      import numpy as np
      
      x = np.arange(120).reshape((2, 3, 4, 5))
      print(x[0, ..., 1:2, 0, 0]) # [20]
      print(x[0][..., 1:2, 0, 0]) # [20]
      print(x[0][...][1:2][0, 0]) # [20 21 22 23 24]
      print(x[0][...][1:2][0][0]) # [20 21 22 23 24]
      print(x)
      # [[[[  0   1   2   3   4]
      #    [  5   6   7   8   9]
      #    [ 10  11  12  13  14]
      #    [ 15  16  17  18  19]]
      # 
      #   [[ 20  21  22  23  24]
      #    [ 25  26  27  28  29]
      #    [ 30  31  32  33  34]
      #    [ 35  36  37  38  39]]
      # 
      #   [[ 40  41  42  43  44]
      #    [ 45  46  47  48  49]
      #    [ 50  51  52  53  54]
      #    [ 55  56  57  58  59]]]
      # 
      # 
      #  [[[ 60  61  62  63  64]
      #    [ 65  66  67  68  69]
      #    [ 70  71  72  73  74]
      #    [ 75  76  77  78  79]]
      # 
      #   [[ 80  81  82  83  84]
      #    [ 85  86  87  88  89]
      #    [ 90  91  92  93  94]
      #    [ 95  96  97  98  99]]
      # 
      #   [[100 101 102 103 104]
      #    [105 106 107 108 109]
      #    [110 111 112 113 114]
      #    [115 116 117 118 119]]]]
      

Advanced Indexing

  • copy 型態
  • obj
    • integers (broadcasting 經常使用,後述會再說明)
      import numpy as np
      
      x = np.arange(9).reshape(3, 3)
      copy = x[[1, 2], [0, 1]]
      print(copy) # [3 7]
      copy[0] = 100
      print(x) 
      # [[0 1 2]
      #  [3 4 5]
      #  [6 7 8]]
      
    • boolean ndarrays (前幾個 \(D\) 需一致),等同 x[obj.nonzero()]
      import numpy as np
      
      x = np.arange(9).reshape(3, 3)
      copy = x[np.array([[True, False, True],
                         [False, True, False],
                         [False, False, False]])]
      print(copy) # [0 2 4]
      copy[0] = 100
      print(x) 
      # [[0 1 2]
      #  [3 4 5]
      #  [6 7 8]]
      
  • dimension
    • integers 依組合不同,會得到不同的結果
      import numpy as np
      
      x = np.arange(90).reshape((10, 9))
      print(x.shape) # (10, 9)
      
      # 等同 x.take([[1, 2]], axis=1)
      result = x[:, [[1, 2]], ...]
      print(result.shape) # (10, 1, 2)
      
      # 等同 x.take([[1, 2]], axis=0)
      result = x[..., [[1, 2]], :]
      print(result.shape) # (1, 2, 9)
      
      result = x[[1, 2], ..., [0]]
      print(result.shape) # (2, )
      
      result = x[[1, 2]]
      print(result.shape) # (2, 9)
      
      import numpy as np
      
      x = np.arange(10*9*8*7).reshape((10, 9, 8, 7))
      print(x.shape) # (10, 9, 8, 7)
      
      # 等同 x.take([[1, 2]], axis=1)
      result = x[:, [[1, 2]], ...]
      print(result.shape) # (10, 1, 2, 8, 7)
      
      # 等同 x.take([[1, 2]], axis=2)
      result = x[..., [[1, 2]], :]
      print(result.shape) # (10, 9, 1, 2, 7)
      
      result = x[:, [1, 2], [0], :]
      print(result.shape) # (10, 2, 7)
      
      result = x[:, [1, 2], :, [0]]
      print(result.shape) # (2, 10, 8)
      
      result = x[[1, 2], [0]]
      print(result.shape) # (2, 8, 7)
      
    • boolean array 依 obj 的 dimension 決定,\(D = D_x - D_{obj} +1\)
      import numpy as np
      
      x = np.arange(60).reshape(3, 4, 5)
      print(x.shape) # (3, 4, 5)
      print(x[x>15].shape) # (44,)
      print(x[[True, True, False]].shape) # (2, 4, 5)
      ind = np.array([[True, True, False, True],
                      [True, True, False, True],
                      [True, True, False, False]])
      print(x[ind].shape) # (8, 5)
      

Broadcasting

  • 規則
    • dimension 相同
    • dimension=1 自動延展
  • 平常範例
    import numpy as np
    
    x = np.arange(6).reshape(2,3)
    y = np.arange(3).reshape(3,1)
    
    z = x*y # operands could not be broadcast together with shapes (2,3) (3,1)
    
    import numpy as np
    
    x = np.arange(3).reshape(3,1)
    y = np.arange(3).reshape(3,1)
    
    z = x*y
    print(x.shape) # (3, 1)
    print(y.shape) # (3, 1)
    print(z.shape) # (3, 3)
    
    import numpy as np
    
    x = np.arange(3).reshape(1,3)
    y = np.arange(3).reshape(3,1)
    
    z = x*y
    print(x.shape) # (1, 3)
    print(y.shape) # (3, 1)
    print(z.shape) # (3, 3)
    
    import numpy as np
    
    x = np.arange(3)
    y = np.arange(3).reshape(3,1)
    
    z = x*y
    print(x.shape) # (3, )
    print(y.shape) # (3, 1)
    print(z.shape) # (3, 3)
    
  • index 範例
    import numpy as np
    
    x = np.array([[ 0,  1,  2],
                  [ 3,  4,  5],
                  [ 6,  7,  8],
                  [ 9, 10, 11]])
    
    rows = np.array([0, 3], dtype=np.intp)
    columns = np.array([0, 2], dtype=np.intp)
    
    rowsT = rows[:, np.newaxis]
    print("rows.shape {}, columns.shape {}".format(rowsT.shape, columns.shape))
    # rows.shape (2, 1), columns.shape (2,)
    
    print(x.shape) # (4, 3)
    
    # 以下兩者等價
    print(x[rowsT, columns].shape) # (2, 2)
    print(x[np.ix_(rows, columns)].shape) # (2, 2)
    

Field Access

  • view 型態
  • obj
    • strings
      import numpy as np
      
      x = np.zeros((2,2), dtype=[('a', np.int32), ('b', np.float64, (3,3))])
      print(x)
      # [[(0, [[ 0.,  0.,  0.], [ 0.,  0.,  0.], [ 0.,  0.,  0.]])
      #   (0, [[ 0.,  0.,  0.], [ 0.,  0.,  0.], [ 0.,  0.,  0.]])]
      #  [(0, [[ 0.,  0.,  0.], [ 0.,  0.,  0.], [ 0.,  0.,  0.]])
      #   (0, [[ 0.,  0.,  0.], [ 0.,  0.,  0.], [ 0.,  0.,  0.]])]]
      
      print(x['a'].shape) # (2, 2)
      print(x['a'].dtype) # dtype('int32')
      print(x['b'].shape) # (2, 2, 3, 3)
      print(x['b'].dtype) # dtype('float64')
      
      view = x['a']
      print(view)
      # [[0 0]
      #  [0 0]]
      
      view[0] = 100
      print(x)
      # [[(100, [[ 0.,  0.,  0.], [ 0.,  0.,  0.], [ 0.,  0.,  0.]])
      #   (100, [[ 0.,  0.,  0.], [ 0.,  0.,  0.], [ 0.,  0.,  0.]])]
      #  [(  0, [[ 0.,  0.,  0.], [ 0.,  0.,  0.], [ 0.,  0.,  0.]])
      #   (  0, [[ 0.,  0.,  0.], [ 0.,  0.,  0.], [ 0.,  0.,  0.]])]]
      

Flat Iterator indexing

  • view 型態
  • 範例
    import numpy as np
    
    x = np.zeros((2,2))
    print(x)
    # [[ 0.  0.]
    #  [ 0.  0.]]
    
    view = x.flat
    print(view[:])
    # [ 0.  0.  0.  0.]
    
    view[0] = 100
    print(x)
    # [[ 100.    0.]
    #  [   0.    0.]]
    

Note

  • 可用內建的 slice
    # 等同 x[1:10:5,::-1] 
    obj = (slice(1,10,5), slice(None,None,-1))
    x[obj]
    
  • 不同情況,會得到不同的結果 view, copy , scalar
    import numpy as np
    
    x = np.arange(9).reshape(3,3)
    print(x)
    # [[0 1 2]
     # [3 4 5]
     # [6 7 8]]
    
    copy = x[(1,2),]
    print(copy)
    # [[3 4 5]
     # [6 7 8]]
    copy[0] = 100
    print(x)
    # [[0 1 2]
     # [3 4 5]
     # [6 7 8]]
    
    # 等同 view = x[1,2]
    scalar = x[(1,2)] 
    print(scalar)
    # 5
    scalar = 200
    print(x)
    # [[0 1 2]
     # [3 4 5]
     # [6 7 8]]
    
    copy = x[[1,2]] 
    print(copy)
    # [[3 4 5]
     # [6 7 8]]
    copy[0] = 300
    print(x)
    # [[0 1 2]
     # [3 4 5]
     # [6 7 8]]
    
    view = x[[1,slice(None)]] 
    print(view)
    # [3 4 5]
    view[0] = 400
    print(x)
    # [[  0   1   2]
     # [400   4   5]
     # [  6   7   8]]
    
  • NumPy indexing 建議 type 為 intp
    import numpy as np
    
    ind = np.array([[0, 0],
                    [3, 3]], dtype=np.intp)
    
  • advanced indexing 若 index 超出範圍,並不會出現 IndexError
    import numpy as np
    
    x = np.zeros((8, 8))
    print(x[[], [100]]) # 不會出現錯誤
    

參考

Numpy 笔记(二): 多维数组的切片(slicing)和索引(indexing)
numpy 中的 broadcasting(广播)机制

留言