1. 程式人生 > >Numpy 筆記: 多維陣列的切片(slicing)和索引(indexing)【轉】

Numpy 筆記: 多維陣列的切片(slicing)和索引(indexing)【轉】

目錄

  • 切片(slicing)操作
  • 索引(indexing) 操作
    • 最簡單的情況
    • 獲取多個元素
  • 切片和索引的同異

切片(slicing)操作

Numpy 中多維陣列的切片操作與 Python 中 list 的切片操作一樣,同樣由 start, stop, step 三個部分組成

import numpy as np

arr = np.arange(12)
print 'array is:', arr

slice_one = arr[:4]
print 'slice begins at 0 and ends at 4 is:', slice_one slice_two = arr[7:10] print 'slice begins at 7 and ends at 10 is:', slice_two slice_three = arr[0:12:4] print 'slice begins at 0 and ends at 12 with step 4 is:', slice_three array is: [ 0 1 2 3 4 5 6 7 8 9 10 11] slice begins at 0 and ends at 4 is
: [0 1 2 3] slice begins at 7 and ends at 10 is: [7 8 9] slice begins at 0 and ends at 12 with step 4 is: [0 4 8]

 

上述例子是一維陣列的例子,如果是多維陣列,將不同維度上的切片操作用 逗號 分開就好了

# coding: utf-8
import numpy as np

arr = np.arange(12).reshape((3, 4))
print 'array is:'
print arr

# 取第一維的索引 1 到索引 2 之間的元素,也就是第二行 # 取第二維的索引 1 到索引 3 之間的元素,也就是第二列和第三列 slice_one = arr[1:2, 1:3] print 'first slice is:' print slice_one # 取第一維的全部 # 按步長為 2 取第二維的索引 0 到末尾 之間的元素,也就是第一列和第三列 slice_two = arr[:, ::2] print 'second slice is:' print slice_two array is: [[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]] first slice is: [[5 6]] second slice is: [[ 0 2] [ 4 6] [ 8 10]]

 

對於 slice_two,如果 arr 是用 Python 的 list 表示的,那麼要得到相同的結果得像下面這樣,相對來說就麻煩多了:

import numpy as np

arr = np.arange(12).reshape((3, 4)).tolist()

slice_two = [
    row[::2] for row in arr
]
print slice_two
[[0, 2], [4, 6], [8, 10]]

 

對於維數超過 3 的多維陣列,還可以通過 '…' 來簡化操作

# coding: utf-8
import numpy as np

arr = np.arange(24).reshape((2, 3, 4))

print arr[1, ...]               # 等價於 arr[1, :, :]
print arr[..., 1]               # 等價於 arr[:, :, 1]
[[12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]]
[[ 1  5  9]
 [13 17 21]]

 

索引(indexing) 操作

最簡單的情況

對於一個多維陣列來說,最簡單的情況就是訪問其中一個特定位置的元素了,如下所示:

# coding: utf-8
import numpy as np

arr = np.array([
    [1, 2, 3, 4],
    [2, 4, 6, 8],
    [3, 6, 9, 12],
    [4, 8, 12, 16]
])
print '第二行第二列的值:', arr[1, 1]
第二行第二列的值: 4

 

相比之下,如果用 Python 的 list 來表示上述二維陣列,獲取同一個位置的元素的方法為:

# coding: utf-8
arr = [
    [1, 2, 3, 4],
    [2, 4, 6, 8],
    [3, 6, 9, 12],
    [4, 8, 12, 16]
]
print '第二行第二列的值:', arr[1][1]
try:
    print '第二行第二列的值(嘗試用 Numpy 的方式獲取):', arr[1, 1]
except Exception as e:
    print str(e)
第二行第二列的值: 4
第二行第二列的值(嘗試用 Numpy 的方式獲取): list indices must be integers, not tuple

 

如果只是二維陣列,這種差別可能看起來並不大,但想象一下假如有一個 10 維的陣列,用 Python 的標準做法需要寫 10 對中括號,而用 Numpy 依然只需要一對。

獲取多個元素

事實上,在 Numpy 的索引操作方式 `x = arr[obj]` 中, obj 不僅僅可以是一個用逗號分隔開的數字序列,還可以是更復雜的內容。

  1. 用逗號分隔的陣列序列

    • 序列的長度和多維陣列的維數要一致
    • 序列中每個陣列的長度要一致
    import numpy as np
    
    arr = np.array([
        [1, 2, 3, 4],
        [2, 4, 6, 8],
        [3, 6, 9, 12],
        [4, 8, 12, 16]
    ])
    
    print arr[[0, 2], [3, 1]]
    [4 6]

     

    以上面這個例子來說,其含義是: 選擇第一行和第三行,然後對第一行選擇第四列,對第三行選擇第二列。

  2. boolean/mask index

    這個不太好翻譯,所以就用原來的英語表達。

    所謂 boolean index,就是用一個由 boolean 型別值組成的陣列來選擇元素的方法。比如說對下面這樣多維陣列

     array([[1, 2, 3, 4], [2, 4, 6, 8], [3, 6, 9, 12], [4, 8, 12, 16]]) 
    

    如果要取其中 值大於 5 的元素,就可以用上 boolean index 了,如下所示:

    import numpy as np
    
    arr = np.array([[1, 2, 3, 4],
                    [2, 4, 6, 8],
                    [3, 6, 9, 12],
                    [4, 8, 12, 16]])
    mask = arr > 5
    
    print 'boolean mask is:'
    print mask
    
    print arr[mask]
    boolean mask is:
    [[False False False False]
     [False False  True  True]
     [False  True  True  True]
     [False  True  True  True]]
    [ 6  8  6  9 12  8 12 16]

     

    除了比較運算能產生 boolean mask 陣列以外, Numpy 本身也提供了一些工具方法:

    • numpy.iscomplex
    • numpy.isreal
    • numpy.isfinite
    • numpy.isinf
    • numpy.isnan

切片和索引的同異

切片和索引都是訪問多維陣列中元素的方法,這是兩者的共同點,不同之處有:

  1. 切片得到的是原多維陣列的一個 檢視(view) ,修改切片中的內容會導致原多維陣列的內容也發生變化
  2. 切片得到在多維陣列中連續(或按特定步長連續)排列的值,而索引可以得到任意位置的值,自由度更大一些

不考慮第一點的話,切片的操作是可以用索引操作來實現的,不過這沒有必要就是了。

對於第一點,見下面的實驗:

import numpy as np

arr = np.arange(12).reshape(2, 6)
print 'array is:'
print arr

slc = arr[:, 2:5]
print 'slice is:'
print slc

slc[1, 2] = 10000
print 'modified slice is:'
print slc
print 'array is now:'
print arr
array
is: [[ 0 1 2 3 4 5] [ 6 7 8 9 10 11]] slice is: [[ 2 3 4] [ 8 9 10]] modified slice is: [[ 2 3 4] [ 8 9 10000]] array is now: [[ 0 1 2 3 4 5] [ 6 7 8 9 10000 11]]

 

轉自http://www.zmonster.me/2016/03/09/numpy-slicing-and-indexing.html