配列の形で定義した変数に対して,インデックスを配列で与えるときどうすればいいか?
Pythonでは(不幸なことに)標準リストとnumpy配列がどちらも配列として扱える.このことが初心者にとってはなんともいやらしい.たとえば,
>>> x = [0,1,2]
>>> print(x)
[0, 1, 2]
>>> y = np.array([0,1,2])
>>> print(y)
[0 1 2]
この場合,xもyもどちらも一見すると同じ配列だ.xは標準のリスト,yはnumpy配列である.この配列の真ん中の1番目の値を取り出す場合は,
>>> x[1]
1
>>> y[1]
1
カッコの中に番号を書けばよく,これは標準リストでもnumpy配列でも全く同じ.また,範囲を指定して,
>>> x[0:3]
[0, 1, 2]
>>> y[0:3]
array([0, 1, 2])
こんな書き方もOK.こんな感じでどちらも同じことが出来てしまうので,あまり考えずに標準リストとnumpy配列を混合して使ってしまいそうになります.
それでは,リストを引数としてこれらの値を取り出してみる.たとえば,1番目,0番目,2番目の順で取り出そうとして,[1,0,2]をxのインデックスとして与えてみると,
>>> x[[1,0,2]]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: list indices must be integers or slices, not list
あらら,エラーが出てしまいました.
メッセージをみても,リストのインデックスは整数かスライスでないといけなくて,リストをインデックスにすることは出来ないと書かれてます.それでは,numpy配列をインデックスとしてはどうでしょうか?やってみます.
>>> x[np.array([1,0,2])]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: only integer scalar arrays can be converted to a scalar index
また怒られてしまいました.整数の配列のみがスカラーインデックスに変換できると書かれてます.つまり,標準リストの配列を相手にする場合はこういう書き方は出来ないということです.不便・・・
ではnumpy配列はどうでしょうか?やってみます.
>>> y[[1,0,2]]
array([1, 0, 2])
>>> y[np.array([1,0,2])]
array([1, 0, 2])
このとおり,あっさりと出来てしまいます.つまり・・・・
配列を使った数値を扱う時は,極力numpy配列を使うべきだということです!
いやいや,何を当たり前のことをと言う人がいるかもしれませんが,Python初心者の場合,このarray([…])という表示がどうも気持ちが悪く,出来るだけ避けたいと言う心理が働くと思います(私だけ?).だけど,標準のリストだとこのように制約が多く,お世辞にも便利とは言えません.
ちなみに,リストで同じようなことをするにはどうすればいいのかですが,下記のように書けばOKです.
>>> [x[n] for n in [1,0,2]]
[1, 0, 2]
出来ないことはないですが,なんとも面倒です.
ただ標準リストは数値だけでなく,文字列なども混合した配列を扱える(numpy配列では数値のみ).そういう場合を除けば,行列やベクトル演算など数値演算を伴う場合は基本numpy配列を扱うという判断でよいと思います.
問題.10次元の正規乱数の配列Xと,3次元の0以上10未満の整数の乱数配列Nを作る.NをインデックスとしてXの値を取り出し,変数Zに代入せよ.
解答
X = np.random.randn(10)
N = np.random.randint(0,10,3)
Z = X[N]
print(X)
print(N)
print(Z)
実行結果
>>> print(X)
[-0.93776079 1.32872729 0.63000034 -0.77506996 0.75173634 0.61462633
-3.46899659 0.38838182 0.51319215 0.88841092]
>>> print(N)
[9 2 5]
>>> print(Z)
[0.88841092 0.63000034 0.61462633]
配列Xの9番目,2番目,5番目の値が取り出されて,Zの値となっていることがわかる.