NumPyは「多次元配列を効率的に扱い、行列演算を行いやすくするためのライブラリ」です。
Pythonは科学技術計算や機械学習で使われることが多いですが、NumPyがあるのもその理由の一つです。
ここでは「NumPyって何?」「NumPyはどうやって使うの?」といった方へ、NumPyの使い方を解説します。なお、numpyをインストールしていない場合は、まずはpip等でnumpyをインストールしましょう。
YouTubeも公開していますので、動画や音声で聞きたい方はぜひご覧ください。
numpyの基本
まずはnumpyの基本的な使い方をみていきましょう。
最も基本的な配列を作成してみます。
import numpy as np
list = np.array([1, 2, 3])
print(list)
[出力結果]
[1 2 3]
numpyを使うためには、まずnumpyをインポートする必要があります。慣例として、numpyはnpという別名をつけることが多いです。
次に配列を作成しています。配列を作成するときはarray()を使い、リストやタプルを引数にします。これで変数listに配列が作成されます。print()で出力すると、通常のリストなどとは違い、半角の空白で表示されます。
結果だけを見るとリストと似ていますが、numpyで初期化した配列はndarrayという独自のデータ構造を持っています。
ndarrayは通常のリストに比べ、大量のデータを効率的に扱うのに長けており、科学計算に適しています。ちなみに、numpyの配列は通常のリストと違い、要素の型は混同できません。複数の型が入っている場合、要素の型が自動的に変換され統一されます。
多次元配列を作る
では次に多次元配列を作ってみましょう。
numpyは多次元配列の扱いに長けているので、ここからが本番です。ここでは3行3列の二次元配列を作成します。
import numpy as np
row1 = [1, 2, 3]
row2 = [4, 5, 6]
row3 = [7, 8, 9]
d_list = np.array([row1, row2, row3])
print(d_list)
[出力結果]
[[1 2 3]
[4 5 6]
[7 8 9]]
3行3列の二次元配列を作成しました。
一次元配列から二次元配列を作る - reshape()
次に、一次元配列から二次元配列を作る方法を見ていきましょう。
一次元配列を多次元配列にする場合、reshape()を使うと簡単です。
import numpy as np
list = np.array([1, 2, 3, 4, 5, 6])
d_list1 = list.reshape(2, 3)
d_list2 = list.reshape(3, 2)
print(d_list1)
print()
print(d_list2)
[出力結果]
[[1 2 3]
[4 5 6]]
[[1 2]
[3 4]
[5 6]]
reshape()の第一引数は行数、第二引数は列数です。
d_list1は行数2、列数3で作成し、d_list2は行数3、列数2で作成しています。
要素の追加・挿入・削除
では次に、初期化済みの配列に要素の追加・変更・削除をしてみましょう。
追加にはappend()、挿入はinsert()、削除はdelete()を使います。
追加 - append()
まずは追加から見ていきましょう。
import numpy as np
row1 = [1, 2, 3]
row2 = [4, 5, 6]
row3 = [7, 8, 9]
d_list = np.array([row1, row2, row3])
row4 = [10, 11, 12]
d_list = np.append(d_list, [row4], 0)
print(d_list)
[出力結果]
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
append()を使って4行目の行を追加しています。
第一引数に追加先の配列、第二引数に追加する配列を指定します。追加する配列は追加先の配列と同じ次元の配列である必要があります。今回は二次元配列なので、同じく二次元配列で追加していまる。
第三引数は「行として追加するか、または列として追加するか」を指定します。
今回は0を指定したので行として追加しましたが、1を指定すると列として配列を追加します。
挿入 - insert()
では次に要素の挿入を見ていきましょう。
追加と違い、挿入は指定箇所に要素を追加できます。挿入にはinsert()を使います。
import numpy as np
row1 = [1, 2, 3]
row2 = [4, 5, 6]
row3 = [7, 8, 9]
d_list = np.array([row1, row2, row3])
row4 = [10, 11, 12]
d_list = np.insert(d_list, 2, [row4], 1)
print(d_list)
[出力結果]
[[ 1 2 10 3]
[ 4 5 11 6]
[ 7 8 12 9]]
append()と異なるのは引数が4つあることです。
第二引数は挿入する位置を決める数値です。また、第四引数は行列の指定です。
今回は第二引数は「2」、第四引数は「1」を指定したので、左から2列目の次の箇所に、縦方向に配列を挿入しています。
削除 - delete ()
最後に削除方法です。
要素の削除にはdelete()を使います。
import numpy as np
row1 = [1, 2, 3]
row2 = [4, 5, 6]
row3 = [7, 8, 9]
d_list = np.array([row1, row2, row3])
d_list = np.delete(d_list, 2, 0)
print(d_list)
[出力結果]
[[1 2 3]
[4 5 6]]
第二引数は削除する要素の位置、第三引数は行列の指定です。引数に指定した通りの要素が削除されているのがわかります。
要素へのアクセス
次は多次元配列の要素へのアクセス方法を見ていきましょう。
基本的にはリストと同じようにインデックス番号を使って参照しますが、numpyの場合は次のように多次元配列の要素へアクセスできます。
import numpy as np
row1 = [1, 2, 3]
row2 = [4, 5, 6]
d_list = np.array([row1, row2])
num = d_list[1, 2]
print(num)
[出力結果]
6
このプログラムでは、次のようにアクセスしています。
[構文]
多次元配列[行, 列]
インデックス番号なので0番から数えた行と列になります。
リストと同じようにアクセスできるので、d_list[1][2]でも同じ要素を参照できます。また、この方法で配列を更新することもできます。
import numpy as np
row1 = [1, 2, 3]
row2 = [4, 5, 6]
d_list = np.array([row1, row2])
d_list[1, 2] = 10
print(d_list)
[出力結果]
[[ 1 2 3]
[ 4 5 10]]
多次元配列から要素を順番に取り出す - ndenumerate()
numpyで作った多次元配列から要素を順に取り出してみましょう。
基本的にはリストと同じくforを使ってループさせますが、numpyではndenumerate()を使うことで、多次元配列から順に要素を取り出せます。
では例を見てみましょう。
import numpy as np
row1 = [1, 2, 3]
row2 = [4, 5, 6]
d_list = np.array([row1, row2])
for i, num in np.ndenumerate(d_list):
print(i, num) #iは要素の位置を示す変数
[出力結果]
(0, 0) 1
(0, 1) 2
(0, 2) 3
(1, 0) 4
(1, 1) 5
(1, 2) 6
ndenumerate()に多次元配列を引数として渡すと、iには取り出した要素の位置が、numには要素が入ります。
スライス
numpyで作成したndarrayでも通常のリストのようにスライスが可能です。
import numpy as np
row = np.array([1, 2, 3, 4, 5])
print(row[:3])
print(row[2:])
print(row[1:3])
[出力結果]
[1 2 3]
[3 4 5]
[2 3]
また、ndarrayは多次元配列でのスライスも可能です。多次元配列のスライスをする場合は各次元毎のスライスをカンマで区切って指定します。
import numpy as np
d_ary = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]).reshape(3, 3)
print(d_ary[0:2, 1:3]) #1〜2行目の2〜3列目
print(d_ary[:, 0:1]) #全行の1列目
print(d_ary[1:3, 1:]) #2〜3行目の2列目以降
[出力結果]
[[2 3]
[5 6]]
[[1]
[4]
[7]]
[[5 6]
[8 9]]
配列の演算
numpyを使うことで、配列の全ての要素に対する演算を簡単に行うことができます。
今回は最も基本的な足し算をしてみましょう。
次の例を見てください。
import numpy as np
list = np.array([1, 2, 3, 4])
A = list.reshape(2, 2)
B = A + 10
print(B)
[出力結果]
[[11 12]
[13 14]]
重要なのは5行目です。二次元配列Aに10を足し算した結果をBに代入しています。
このように、numpyでは配列に直接足し算すると、その配列の全ての要素に加算処理を行います。
引き算や掛け算、割り算でも同じです。一度試してみてください。
合計・最大値・最小値の計算
合計はsum()、最大値はmax()、最小値はmin()で求めることができます。
import numpy as np
d_ary = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]).reshape(3, 3)
print(d_ary.sum())
print(d_ary.max())
print(d_ary.min())
[出力結果]
45
9
1
また、各メソッドの引数に「0」を指定すると各列の合計の配列、「1」を指定すると各行の合計の配列が返却されます。
ここではsum()の各列・行の合計値を出力します。
import numpy as np
d_ary = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]).reshape(3, 3)
print(d_ary.sum(0)) #各列の合計
print(d_ary.sum(1)) #各行の合計
[出力結果]
[12 15 18]
[ 6 15 24]
配列同士の四則演算
先ほどの演算では A + 10で、Aの要素全てに10を加算していました。
さて、この10の箇所も配列の場合はどうなるのでしょうか?
実際にやってみましょう。
import numpy as np
A = np.array([1, 2, 3, 4]).reshape(2, 2)
B = np.array([10, 20, 30, 40]).reshape(2, 2)
C = A + B
print(C)
[出力結果]
[[11 22]
[33 44]]
配列Aと配列Bの同じ位置にある要素同士が加算されているのがわかります。
ブロードキャスト
行と列が合っていない配列同士で演算すると、行や列が補完されます。これをブロードキャストと呼びます。
import numpy as np
A = np.array([10, 20, 30, 40]).reshape(2, 2)
B = np.array([1, 2])
C = A + B
print(C)
[出力結果]
[[11 22]
[31 42]]
Bの配列は一次元配列なので、Aとは列数が合っていません。この場合、Bは2列目の配列をコピーし、2行目の配列を補完しています。
上記の例は行数が足りないパターンですが、列数が足りない場合もブロードキャストされます。次の例は2行3列の行列に2行1列の行列を足し算しています。
import numpy as np
A = np.array([10, 20, 30, 40, 50, 60]).reshape(2, 3)
B = np.array([1, 2]).reshape(2, 1)
C = A + B
print(C)
[出力結果]
[[11 21 31]
[42 52 62]]
Aが2行3列の行列で、Bが2行1列の行列です。
Aの列毎の要素にBの値が加算されているのがわかります。
ちなみに、ブロードキャストはBが1行1列の行列、またはBの行数または列数がAと同じ場合のみで、それ以外の場合はエラーになります。
import numpy as np
A = np.array([10, 20, 30, 40, 50, 60]).reshape(2, 3) #2行3列
B = np.array([1, 2]).reshape(1, 2) #1行2列 ※Aと行数も列数も合っていない!
C = A + B
print(C)
[出力結果]
ValueError: operands could not be broadcast together with shapes (2,3) (1,2)
効率よく配列を作成する方法
ここまでNumpyの配列の初期化にはarray()やreshape()を使ってきましたが、Numpyには他にも様々な配列の初期化方法があります。
ここでは等差数列(「◯の倍数」のような、値と値の間の差が一定の数列)で初期化するarange()、0で初期化するzeros()、1で初期化するones()を解説します。
等差数列で初期化する - arange()
配列を等差数列で初期化したい場合はarange()が便利です。arange()は1つ目の引数に開始値、2つ目の引数に終了値、3つ目に値と値の差(公差)を指定します。
[構文]
arange([開始値], 終了値, [公差])
引数を一つだけ指定した場合は終了値のみとなり、2つ指定した場合は開始値と終了値が指定されます。
各引数を指定した場合のパターンを見てみましょう。
import numpy as np
A = np.arange(5) #終了値のみ
B = np.arange(2, 5) #開始, 終了値
C = np.arange(3, 20, 3) #開始, 終了, 公差
print(A)
print(B)
print(C)
[出力結果]
[0 1 2 3 4]
[2 3 4]
[ 3 6 9 12 15 18]
Aは終了値のみを指定しています。終了値のみ指定する場合は0〜終了値 - 1までの数列が作成されます。またBは開始と終了値を指定しています。開始値を指定しているので2〜終了値 - 1までの数列が作成されます。
Cは公差を指定しているので、3の倍数の数列が作成されました。
また、作成された配列はndarrayなので、reshape()を使うことで多次元配列にすることもできます。
import numpy as np
C = np.arange(3, 20, 3)
D = C.reshape(2, 3)
print(D)
[出力結果]
[[ 3 6 9]
[12 15 18]]
全ての要素を0で初期化する - zeros()
要素を0で初期化したい場合はzeros()が便利です。
1つ目の引数に行数・列数を指定し、dtypeにデータ型を指定します。
[構文]
zeros(行数・列数, [dtype=データ型])
import numpy as np
A = np.zeros(3) #行数のみ
B = np.zeros((2, 3)) #行数・列数をタプルで指定
C = np.zeros((2, 3), dtype="int") #int型にする
print(A)
print(B)
print(C)
[出力結果]
[ 0. 0. 0.]
[[ 0. 0. 0.]
[ 0. 0. 0.]]
[[0 0 0]
[0 0 0]]
zeros()はデータ型を指定しない場合はnumpy.float64という型になるので、intにしたい場合はdtypeに”int”を指定する必要があります。
全ての要素を1で初期化する - ones()
要素を1で初期化したい場合はones()が便利です。
使い方はzeros()と同じです。
[構文]
ones(行数・列数, [dtype=データ型])
import numpy as np
A = np.ones((2, 3), dtype="int")
print(A)
[出力結果]
[[1 1 1]
[1 1 1]]