PytonのNumPyの使い方その1では、初期化と要素の追加・削除について解説しました。
ここからはndarrayの要素へのアクセスと演算について解説します。
目次
リストの要素にアクセスする
まずはndarrayの要素へアクセスする方法を見ていきましょう。
ここでは多次元リストの場合を中心に解説しています。
要素の参照
要素の参照は通常のリストと同じようにインデックス番号を使います。今回は2次元リストなので、1つの要素にアクセスしたい場合は2つのインデックス番号を指定します。
import numpy as npnp_list = np.array(list(range(1, 10))).reshape(3, 3)print(np_list)print(np_list[1]) #行を出力print(np_list[2][2]) #要素を出力print(np_list[2, 2]) #こういうアクセス方法もある
[[1 2 3][4 5 6][7 8 9]][4 5 6]99
要素の更新
要素の更新も参照と同じくインデックス番号を使います。
import numpy as npnp_list = np.array(list(range(1, 10))).reshape(3, 3)print(np_list)np_list[1, 1] = 10print(np_list)np_list[2] = [11, 12, 13] #行を更新するprint(np_list)
[[1 2 3][4 5 6][7 8 9]][[ 1 2 3][ 4 10 6][ 7 8 9]][[ 1 2 3][ 4 10 6][11 12 13]]
多次元リストをスライスする
スライスとはリストの一部分だけを切り出すことです。
スライスの詳細はこちら↓
ndarrayの多次元リストの場合は[行の開始位置:行の終了位置, 列のスライス開始位置:列のスライス終了位置]と指定することで、行と列に対してスライスが可能です。
import numpy as npnp_list = np.array(list(range(1, 10))).reshape(3, 3)print(np_list[:, :]) #全てprint(np_list[1:, :]) #2行目以降print(np_list[:, 1:]) #2列目以降print(np_list[:2, :2]) #2行目までかつ2列目までprint(np_list[1:2, 1:2]) #真ん中の要素
[[1 2 3][4 5 6][7 8 9]][[4 5 6][7 8 9]][[2 3][5 6][8 9]][[1 2][4 5]][[5]]
全ての要素を順番に取り出す
多次元リストの全ての要素を取得する場合はfor..inをネストするのが直感的です。
import numpy as npnp_list = np.array(list(range(1, 5))).reshape(2, 2)for items in np_list: for item in items: print(item)
1234
しかし、forのネストはソースコードが読みにくくなりがちです。
NumPyではndenumerate()という関数が用意されています。ndenumerate()を使って要素を取り出すと、要素の他に行と列の情報がタプルで付与されます。
import numpy as npnp_list = np.array(list(range(1, 5))).reshape(2, 2)for i, item in np.ndenumerate(np_list): print(i, item)
(0, 0) 1(0, 1) 2(1, 0) 3(1, 1) 4
条件に合った要素のみ取得する
リスト内で条件に合った要素のみを抽出して取得することもできます。条件式には比較演算子や論理演算子が使えます。多次元リストの場合は条件で抽出すると1次元リストになります。
import numpy as npnp_list = np.array(list(range(1, 10))).reshape(3, 3)print(np_list[np_list < 5])print(np_list[np_list >= 5])
[1 2 3 4][5 6 7 8 9]
また、論理演算は「and」「or」「not」の代わりに「&」「|」「~」を使います。
import numpy as npnp_list = np.array(list(range(1, 10))).reshape(3, 3)print(np_list[(np_list >= 3) & (5 >= np_list)]) #3以上5以下print(np_list[(np_list == 1) | (np_list > 6)]) #1または6より上print(np_list[~(np_list%3 == 0)]) #3の倍数以外
[3 4 5][1 7 8 9][1 2 4 5 7 8]
条件に合う要素を一括更新する
条件を指定して一括で要素を更新することもできます。下の例では偶数を0、奇数を1に置き換えています。
import numpy as npnp_list = np.array(list(range(1, 17))).reshape(4, 4)np_list[np_list%2 == 0] = 0np_list[np_list%2 == 1] = 1print(np_list)
[[1 0 1 0][1 0 1 0][1 0 1 0][1 0 1 0]]
NumPyの演算
ndarrayは通常のリストにはない優れた機能がいくつもあり、化学計算や機械学習に使われています。一つずつ見ていきましょう。
四則演算
要素が数値のリストのときは、リスト同士で四則演算することができます。
import numpy as npA = [[3, 6], [2, 5]]B = [[9, 1], [4, 7]]C = A + Bprint(C) #通常のリストの場合は結合になるA_n = np.array(A)B_n = np.array(B)C_n = A_n + B_nprint(C_n) #ndarrayの場合は加算される
[[3, 6], [2, 5], [9, 1], [4, 7]][[12 7][ 6 12]]
引き算、掛け算、割り算も同様に計算できます。
import numpy as npA = np.array([[3, 6], [2, 5]])B = np.array([[9, 1], [4, 7]])C = A - BD = A * BE = A / Bprint(C)print(D)print(E)
行列数が異なるリスト同士の計算
行列数が異なる場合は足りない行や列を補って計算します(ブロードキャストと言います)
import numpy as npA = np.array([[1, 2], [3, 4]])B = np.array([10, 20])C = A + Bprint(C)
[[11 22][13 24]]
上の例ではAが2行2列に対してBが1行2列なので、Bの行列が1行足りていません。
この場合はBの行を複製して補った後に計算しています。
また、列が足りない場合も同様にブロードキャストされて計算されます。
import numpy as npA = np.array([1, 2, 3, 4, 5, 6]).reshape(2, 3)B = np.array([10, 20]).reshape(2, 1)C = A + Bprint(C)
[[11 12 13][24 25 26]]
合計・最小値・最大値
合計はsum()、最小値はmin()、最大値はmax()で求めることができます。
列単位での計算は引数に0を、行単位での計算は引数に1を指定します。
import numpy as npA = np.array(list(range(1, 10))).reshape(3, 3)print(A)sum = A.sum() #全要素の合計print(sum)sum_row = A.sum(0) #列の合計print(sum_row)sum_col = A.sum(1) #行の合計print(sum_col)min = A.min() #最小値print(min)max = A.max() #最大値print(max)
[[1 2 3][4 5 6][7 8 9]]45[12 15 18][ 6 15 24]19
算術平均・分散・標準偏差を計算する
算術平均はmean()、標準偏差はstd()、分散はvar()で計算できます。
import numpy as npA = np.random.randint(0, 100, 30)print(A)print(np.mean(A)) #算術平均print(np.std(A)) #標準偏差print(np.var(A)) #分散
[12 19 10 84 68 25 99 61 41]48.233333333329.1521106535849.845555556
内積の計算
行列の内積計算はdot()を使います。内積を計算するには、左右の行列の行数が等しくないとできません。
import numpy as npA = np.array([3, 2, 4, 5]).reshape(2, 2)B = np.array([2, 6, 1, 4]).reshape(2, 2)C = np.dot(A, B)print(C)
[[ 8 26][13 44]]