[Python] NumPy Indexing

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

簡介:NumPy indexing 的使用

Indexing

ndarrays indexing 的方法,即是 x[obj]
obj 的型態會影響賦於的 array 是 view 還是 copy
  • view:與其他 array 共用空間,改值會互相影響
  • copy:與其他 array 不共用空間,改值不會互相影響
  1. import numpy as np
  2.  
  3. x = np.array([[ 0, 1, 2],
  4. [ 3, 4, 5],
  5. [ 6, 7, 8],
  6. [ 9, 10, 11]])
  7. view = x[1:2, 1:3]
  8. copy = x[1:2, [1, 2]]
  9. print(view) # [[4 5]]
  10. view[0] = 100
  11. print(view) # [[100 100]]
  12. print(x)
  13. # [[ 0 1 2]
  14. # [ 3 100 100]
  15. # [ 6 7 8]
  16. # [ 9 10 11]]
  17. print(copy) # [[4 5]]
  18. copy[0] = 200
  19. print(copy) # [[200 200]]
  20. print(x)
  21. # [[ 0 1 2]
  22. # [ 3 100 100]
  23. # [ 6 7 8]
  24. # [ 9 10 11]]

Basic Slicing and Indexing

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

Advanced Indexing

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

Broadcasting

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

Field Access

  • view 型態
  • obj
    • strings
      1. import numpy as np
      2.  
      3. x = np.zeros((2,2), dtype=[('a', np.int32), ('b', np.float64, (3,3))])
      4. print(x)
      5. # [[(0, [[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]])
      6. # (0, [[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]])]
      7. # [(0, [[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]])
      8. # (0, [[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]])]]
      9.  
      10. print(x['a'].shape) # (2, 2)
      11. print(x['a'].dtype) # dtype('int32')
      12. print(x['b'].shape) # (2, 2, 3, 3)
      13. print(x['b'].dtype) # dtype('float64')
      14.  
      15. view = x['a']
      16. print(view)
      17. # [[0 0]
      18. # [0 0]]
      19.  
      20. view[0] = 100
      21. print(x)
      22. # [[(100, [[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]])
      23. # (100, [[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]])]
      24. # [( 0, [[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]])
      25. # ( 0, [[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]])]]

Flat Iterator indexing

  • view 型態
  • 範例
    1. import numpy as np
    2.  
    3. x = np.zeros((2,2))
    4. print(x)
    5. # [[ 0. 0.]
    6. # [ 0. 0.]]
    7.  
    8. view = x.flat
    9. print(view[:])
    10. # [ 0. 0. 0. 0.]
    11.  
    12. view[0] = 100
    13. print(x)
    14. # [[ 100. 0.]
    15. # [ 0. 0.]]

Note

  • 可用內建的 slice
    1. # 等同 x[1:10:5,::-1]
    2. obj = (slice(1,10,5), slice(None,None,-1))
    3. x[obj]
  • 不同情況,會得到不同的結果 view, copy , scalar
    1. import numpy as np
    2.  
    3. x = np.arange(9).reshape(3,3)
    4. print(x)
    5. # [[0 1 2]
    6. # [3 4 5]
    7. # [6 7 8]]
    8.  
    9. copy = x[(1,2),]
    10. print(copy)
    11. # [[3 4 5]
    12. # [6 7 8]]
    13. copy[0] = 100
    14. print(x)
    15. # [[0 1 2]
    16. # [3 4 5]
    17. # [6 7 8]]
    18.  
    19. # 等同 view = x[1,2]
    20. scalar = x[(1,2)]
    21. print(scalar)
    22. # 5
    23. scalar = 200
    24. print(x)
    25. # [[0 1 2]
    26. # [3 4 5]
    27. # [6 7 8]]
    28.  
    29. copy = x[[1,2]]
    30. print(copy)
    31. # [[3 4 5]
    32. # [6 7 8]]
    33. copy[0] = 300
    34. print(x)
    35. # [[0 1 2]
    36. # [3 4 5]
    37. # [6 7 8]]
    38.  
    39. view = x[[1,slice(None)]]
    40. print(view)
    41. # [3 4 5]
    42. view[0] = 400
    43. print(x)
    44. # [[ 0 1 2]
    45. # [400 4 5]
    46. # [ 6 7 8]]
  • NumPy indexing 建議 type 為 intp
    1. import numpy as np
    2.  
    3. ind = np.array([[0, 0],
    4. [3, 3]], dtype=np.intp)
  • advanced indexing 若 index 超出範圍,並不會出現 IndexError
    1. import numpy as np
    2.  
    3. x = np.zeros((8, 8))
    4. print(x[[], [100]]) # 不會出現錯誤

參考

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

留言