Remrinのpython攻略日記

python3に入門しました。python3についてあれこれとサンプルコードとか。

NumPyの使い方(3) インデックス、スライス

NumPyのインデックス、スライスについて。
 

1次元配列のインデックス、スライス

 
値の参照:python組み込みのlistと同様
値の代入:まとめて同じ値が代入(ブロードキャスト)
 

import numpy as np

# 値の参照、代入
a1 = np.arange(1, 10)
print(a1)      # [1 2 3 4 5 6 7 8 9]
print(a1[3])   # 4
print(a1[3:6]) # [4 5 6]

a1[3:6] = 0    # すべての要素の0を代入
print(a1)      # [1 2 3 0 0 0 7 8 9]

 
[注意]部分配列はコピーではなくビューになる。つまり、
 参照して作成した部分配列の要素を変更すると、参照元のndarrayも変更される。

a1 = np.arange(1, 10)
print(a1)  # [1 2 3 4 5 6 7 8 9]

# インデックス参照で新たな変数を作り代入した場合は元は保存
x = a1[8]
x = 0
print(a1)  # [1 2 3 4 5 6 7 8 9]

# スライス参照で新たな部分配列を作り代入した場合は元も変更
a2 = a1[3:6]
a2[:] = 10
print(a2)  # [10 10 10]
print(a1)  # [ 1  2  3 10 10 10  7  8  9]

a2[0] = 20
print(a2)  # [20 10 10]
print(a1)  # [ 1  2  3 20 10 10  7  8  9]

# built-inのlist型とは挙動が異なる
list1 = list(range(1, 10))
list1[3:6] = [0]
print(list1) # [1, 2, 3, 0, 7, 8, 9]

# 元のndarrayを保存したいときはcopy()メソッドを使う。
a2 = a1[0:3].copy()

 

2次元配列のインデックス

・a2[1][0] arr2の1行目0列目の要素を指定
・a2[1, 0] 同義

a2 = np.array([[1, 2, 3], [4, 5, 6]])
print(a2)        # [[1 2 3]
                 #  [4 5 6]]
print(a2.shape)  # (2, 3)

print(a2[1][0])  # 4
print(a2[1, 0])  # 4

 

3次元配列のインデックス

 a3[0][1][2] a3の0枚目の1行目の2列目

a3 = np.array([[[1, 2, 3], [4, 5, 6]],[[7, 8, 9], [10, 11, 12]]])
print(a3)        
# [[[ 1  2  3]
#   [ 4  5  6]]
#
#  [[ 7  8  9]
#   [10 11 12]]]
print(a3.shape)  # (2, 2, 3)

print(a3[0]) 
# [[1 2 3]
#  [4 5 6]]
print(a3[0, 1])     #[4 5 6] 
print(a3[0, 1, 2])  # 6

 

多次元配列のスライス参照

・スライスすると配列の次元は変わらない。
・(数値で)インデックス参照すると次元が1つ減る。
 

3次元配列のa3について、

スライス     部分配列
a3[1:]       3次元
a3[1]        2次元
a3[1:, 1:]   3次元
a3[1, 1:]    2次元
a3[1, 1]     1次元
a3[1, 1, 1]  0次元、つまり値

 

# 3次元配列を用意
a3 = np.array([[[1, 2, 3], [4, 5, 6]],[[7, 8, 9], [10, 11, 12]]])
print(a3)        
# [[[ 1  2  3]
#   [ 4  5  6]]
#
#  [[ 7  8  9]
#   [10 11 12]]]
print(a3.shape)  # (2, 2, 3)

print(a3[1:].ndim)      # 3
print(a3[1].ndim)       # 2
print(a3[1:, 1:].ndim)  # 3
print(a3[1, 1:].ndim)   # 2
print(a3[1, 1].ndim)    # 1
print(a3[1, 1, 1].ndim) # 0

print(a3[1:])      # [[[ 7  8  9]
                   #   [10 11 12]]]
print(a3[1])       # [[ 7  8  9]
                   #  [10 11 12]]
print(a3[1:, 1:])  # [[[10 11 12]]]
print(a3[1, 1:])   # [[10 11 12]]
print(a3[1, 1])    # [10 11 12]
print(a3[1, 1, 1]) # 11

 

ブールインデックス

bool値がTrueとなるものだけを選ぶことができる。
ビュー(参照)ではなく、コピーとなる。

rgb = np.array(["r", "g", "b", "r", "g", "b"])
print(rgb == "r")
# [ True False False  True False False]

print(rgb[rgb == "r"])   #['r' 'r']
print(rgb[rgb != "r"])   #['g' 'b' 'g' 'b']

 

rgb = np.array(["r", "g", "b", "r", "g", "b"])

# 乱数の初期化
np.random.seed(1)
# 0~255までの乱数で6行4列の配列を作る
data = np.random.randint(0, 256, size=(6, 4))
print(data)
# [[ 37 235 140  72]   # r
#  [255 137 203 133]   # g
#  [ 79 192 144 129]   # b
#  [204  71 237 252]   # r
#  [134  25 178  20]   # g
#  [254 101 146 212]]  # b

print(data[rgb == "r"]) # rgbがrの行だけを抽出
# [[ 37 235 140  72]
#  [204  71 237 252]]

print(data[rgb != "r"]) # rgbがr以外の行を抽出(1)
# [[255 137 203 133]
#  [ 79 192 144 129]
#  [134  25 178  20]
#  [254 101 146 212]]

# 真偽値のbit反転でも書ける
print(~(rgb == "r"))
# [False  True  True False  True  True]

print(data[~(rgb == "r")]) # rgbがr以外の行を抽出(2)
# [[255 137 203 133]
#  [ 79 192 144 129]
#  [134  25 178  20]
#  [254 101 146 212]]

print(data[rgb == "r", 0:2]) # rbgがrの行の0~1列目の要素
# [[ 37 235]
#  [204  71]]

print(data[rgb == "r", 0]) # rbgがrの行の0列目の要素
# [ 37 204]  1次元の配列は横向き(横ベクトル)で表示

data[data < 100] = 0  # 100未満のすべての要素を0にする。
print(data)
# [[  0 235 140   0]
#  [255 137 203 133]
#  [  0 192 144 129]
#  [204   0 237 252]
#  [134   0 178   0]
#  [254 101 146 212]]

 

ファンシーインデックス

複数のインデックス参照を整数配列(list, ndarrayなど)で指定する。
スライスと違い、元データのコピーを返す。 
 

list1 = [[i+j for i in range(5)] for j in range(0, 50, 10)]
a1 = np.array(list1)
print(a1)
# [[ 0  1  2  3  4]
#  [10 11 12 13 14]
#  [20 21 22 23 24]
#  [30 31 32 33 34]
#  [40 41 42 43 44]]

print(a1[1]) # [10 11 12 13 14] 1列目
print(a1[3]) # [30 31 32 33 34] 3列目

#インデック指定であることを表す[]の中にlistの[] >>> 2重[[]]
print(a1[[1, 3, 1]]) #1列目、3列目、1列目の順に参照
# [[10 11 12 13 14]
#  [30 31 32 33 34]
#  [10 11 12 13 14]]

print(a1[[-1, -2, -3]]) #後ろから1列目、2列目、3列目
# [[40 41 42 43 44]
#  [30 31 32 33 34]
#  [20 21 22 23 24]]

# 5行10列の配列の準備
a2 = np.arange(50).reshape(5, 10)
print(a2)
# [[ 0  1  2 ...,  7  8  9]
#  [10 11 12 ..., 17 18 19]
#  [20 21 22 ..., 27 28 29]
#  [30 31 32 ..., 37 38 39]
#  [40 41 42 ..., 47 48 49]]

print(a2[[0, 1, 2, 3],[9, 8, 7, 6]])
# [ 9 18 27 36]

print(a2[range(5), range(5)])
# [ 0 11 22 33 44]

print(a2[[1, 3]][:, range(1, 10, 2)])
# 10の位も1の位も奇数の要素
# [[11 13 15 17 19]
#  [31 33 35 37 39]]

# np.ix_(list1, list2)でも同義
print(a2[np.ix_([1, 3], range(1, 10, 2))])
# [[11 13 15 17 19]
#  [31 33 35 37 39]]

 

take()とput()

take()は指定されたindexから値を取得。
put()は指定されたindexに値を代入。

a1 = np.arange(0, 100, 10)
print(a1)
# [ 0 10 20 30 40 50 60 70 80 90]

print(a1.take([1, 3, 5]))
# [10 30 50]

a1.put([1, 3, 5], [0, 0, 0])
print(a1)
# [ 0  0 20  0 40  0 60 70 80 90]

a2 = np.arange(6).reshape(2, 3)
print(a2)
# [[0 1 2]
#  [3 4 5]]

print(a2.take([1], axis=1))
# [[1]
#  [4]]

print(a2.take([1], axis=0))
# [[3 4 5]]

print(a2.take([1])) # axis指定なしだと1d化
# [1]

print(a2)
a2.put([4, 5], 10) # flatten後のindexを指定
print(a2)
# [[ 0  1  2]
#  [ 3 10 10]]