NumPyは、ベクトルや行列の計算を高速に実行するために使われるライブラリです。ライブラリについては、関数のところで少しだけ説明しました。様々な機能を実現するコードの集まりで、基本、都度読み込んで使います。科学計算では、データ処理に配列をよく使います。配列というのは、たくさんのデータを並べて、一気に演算を行うのに使われます。
NumPyを使うには、これを事前にインポートしておきます。NumPyをインポートするには、
import numpy
と書きます。npという名前でインポートするには、
import numpy as np
です。
まず、リスト型から一次元配列を作ってみましょう。変数aでリストを作成し、それをarray()の引数に渡します。array()の引数に渡すのはリスト型ですから、変数aには各括弧をつけて数値を並べましょう。
In import numpy as np
# リスト型
a = [0, 1, 2, 3, 4]
b = np.array(a)
print(b)
# 型を表示
print("a : ", type(a))
print("b : ", type(b))
Out [0 1 2 3 4]
a : <class 'list'>
b : <class 'numpy.ndarray'>
リスト型から作った一次元配列の型はndarray型になっています。このndarrayというのはn-dimensional arrayの略で、多次元配列を意味します。NumPyのarray()はリスト型に似ていますが、扱えるデータ型が数値に制限されています。その代わり、多様な演算機能や高速処理に対応します。
リスト型で要素ごとの計算を行うには、for文を使って要素を一つずつ取り出す必要がありました。ndarray型だと、同じ位置の要素同士で演算が行われるので、for文の必要はなくなります。以下のコードには、a + 1, b += b, a + b の三つの算術演算がありますが、いずれも要素同士の演算になっています。
In import numpy as np
a = np.array([0, 1, 2, 3, 4])
b = a + 1
print(b)
b += b
print(b)
c = a + b
print(c)
Out [1 2 3 4 5]
[ 2 4 6 8 10]
[ 2 5 8 11 14]
ndarray型から値を取り出したり、複数の要素(リスト)を取り出したりできます。後者はスライスと呼びます。スライスというのは、一連の要素から部分的に要素を取り出すことです。
In import numpy as np
a = np.array([0, 1, 2, 3, 4])
print(a)
a1 = a[0:3] # 要素0, 1, 2を取り出す
print(a1)
a[0:3] = 1 # 要素0, 1, 2を1に変更する
print(a)
Out [0 1 2 3 4]
[0 1 2]
[1 1 1 3 4]
ndarray型はリスト型と同様の問題があります。ndarray型の変数aを他の変数bに代入したとき、代入先のbの値に変更を加えると、元のaの値も変更されてしまいます。これは、Pyhonの代入がコピーではなく、参照になっているということです。これをviewといいます。viewは、元の配列と同じものを指していて、元の配列を変更することになるのです。
In import numpy as np
a = np.array([0, 1, 2, 3, 4])
print(a)
b = a # ndarray型の変数aをそのまま、他の変数bに代入
b += 1 # 変数bへの変更が元の変数aにも影響を与える
print(a)
Out [0 1 2 3 4]
[1 2 3 4 5]
コピーしたい場合は、copy()メソッドを使います。viewとcopyでは動作が全く違ってきますので、注意が必要です。
In import numpy as np
a = np.array([0, 1, 2, 3, 4])
print(a)
b = a.copy()
b += 1
print(a)
Out [0 1 2 3 4]
[0 1 2 3 4]
NumPyのndarray型を生成する関数には、以下のようなものがあります。
arange([開始, ] 終了 [, ステップ]) : 連続した数値を生成する
ones(要素数) : 要素数だけ1で初期化した数値を生成する
zeros(要素数) : 要素数だけゼロで初期化した数値を生成する
linspace(開始, 終了, 要素数) : 開始値から終了値まで、要素数分の数値を並べる
random.rand(要素数0 [, 要素数1, ... ]) : 0以上から1未満の一様乱数を発生する。要素数を複数渡すと、多次元のndarray型を生成する。
In import numpy as np
a = np.arange(1, 20) # 1から19までの配列を作る
print(a)
b = a+1 # 各要素に1を足す
print(b)
Out [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
[ 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20]
In import numpy as np
a = np.ones(20)
b = np.zeros(20)
print(a + b)
Out [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
linspace()はarange()に似ていて等差数列を生成しますが、引数に要素数を指定します。
In import numpy as np
c = np.linspace(0, 20, 6)
print(c)
Out [ 0. 4. 8. 12. 16. 20.]
乱数を生成するモジュールとしてrandom()があります。代表的な関数は、random.rand()、random.randint()、random.normal()です。
random.rand(z):0以上1未満の一様乱数(実数)をz個発生する
random.randint(x, y, z):x以上y未満の整数をz個発生する
random.normal(loc, scale, size):平均loc、標準偏差scaleの正規分布に従う乱数をsize個発生する
In import numpy as np
a = np.random.rand(5)
print(a)
b = np.random.randint(10,20,5)
print(b)
c = np.random.normal(loc=0.0, scale=1.0, size=3)
print(c)
Out [0.93640108 0.25852863 0.18547717 0.23901293 0.9896948 ]
[14 17 12 11 13]
[ 0.787455 -0.38110928 1.09385348]
Boolというのは論理値のことです。ndarray型ではBoolインデックス参照という方法が可能で、論理値(True/False)の配列を用いて要素を取り出すことができます。以下のように書くと、論理値配列のTrueのところの要素を残して、ndarray型を作ります。
ndarray型変数[ndarray型の論理値の配列]
In import numpy as np
a = [1, 2, 3, 4, 5]
b = np.array(a)
c = [True, True, True, True, False]
d = np.array(c)
print(b[d])
Out [1 2 3 4]
このBoolインデックス参照を使うと、以下のように、3で割った余りが1になったとき、その要素をTrueとして返し、その要素を取り出します。
In import numpy as np
a = [1, 2, 3, 4, 5, 6]
b = np.array(a)
print(b[b % 3 == 1])
Out [1 4]
ndarray型配列の要素すべてに対して演算処理を行い、結果をndarray型で返します。代表的な関数として、以下があります。
abs():要素の絶対値を返す
exp():要素のe(自然対数の底)のべき乗を返す
sqrt():要素の平方根を返す
In import numpy as np
a = np.random.randint(-10,10,5)
print(a)
a_abs = np.abs(a)
print(a_abs)
a_exp = np.exp(a_abs)
print(a_exp)
a_sqrt = np.sqrt(a_abs)
print(a_sqrt)
Out [ 1 4 3 -2 -5]
[1 4 3 2 5]
[ 2.71828183 54.59815003 20.08553692 7.3890561 148.4131591 ]
[1. 2. 1.73205081 1.41421356 2.23606798]
集合とは何らかの対象の集まりのことで、集合演算には和、積、差があります。Numpyの集合演算ではこの和集合、積集合、差集合の関数に加えて、配列の要素から重複を取り除いてソートする関数が備えられています。
union1d(x, y):二つの配列x, yの中でどちらか一方に存在する要素を取り出してソートする(和集合)
intersect1d(x, y):二つの配列x, yの中で共通する要素を取り出してソートする(積集合)
setdiff1d(x, y):二つの配列x, yの中で共通する要素を、xから取り除いてソートする(差集合)
unique(x, y):配列の要素から重複するものを取り除いてソートする
In import numpy as np
a1 = np.random.randint(1,20,6)
a2 = np.random.randint(1,20,4)
print("a1 : ", a1)
print("a2 : ", a2)
a_unique = np.unique(a1)
print(a_unique)
a_union = np.union1d(a1, a2)
print(a_union)
a_intersect = np.intersect1d(a1, a2)
print(a_intersect)
a_setdiff = np.setdiff1d(a1, a2)
print(a_setdiff)
Out a1 : [ 7 6 8 4 8 16]
a2 : [ 1 17 7 18]
[ 4 6 7 8 16]
[ 1 4 6 7 8 16 17 18]
[7]
[ 4 6 8 16]
これまでは一次元配列を扱ってきましたが、一次元配列が幾つか集まることで二次元配列になります。二次元配列は行列に相当し、ndarray型では以下のように表記します。
array([リスト, リスト])
ndarray型にはshapeという変数があって、ndarray型の要素数を返します。つまり、何行何列の行列なのかわかります。
reshape(x, y)
とやると、x行y列の行列に変換します。
In import numpy as np
b1 = np.array([[1,2,3],[4,5,6]]) # 二次元配列
print(b1)
print(b1.shape) # 要素数
Out [[1 2 3]
[4 5 6]]
(2, 3)
In import numpy as np
c1 = np.zeros(6)
print(c1)
c2 = c1.reshape(2, 3)
print(c2)
Out [0. 0. 0. 0. 0. 0.]
[[0. 0. 0.]
[0. 0. 0.]]
二次元配列から任意の行を取り出すには、その行を括弧で指定します。行列のインデックスは、0行目0列目から始まることに注意します。スライスも使えます。変数[1, 1:] と書きますと、1行目の1列目以降を取り出します。
In import numpy as np
d1 = np.arange(6) # 0から5の数値をベクトルにする
print(d1)
d2 = d1.reshape(2, 3) # 2行3列の行列に変換する
print(d2)
print(d2[1]) # 1行目を取り出す
print(d2[1, 1:]) # 1行目の1列目以降を取り出す。
Out [0 1 2 3 4 5]
[[0 1 2]
[3 4 5]]
[3 4 5]
[4 5]
二次元配列の場合、行ごと、あるいは、列ごとに計算を行いたいことがあります。このようなとき、axisを使います。引数に axis = 0 を設定すると、列ごとの処理になり、引数に axis = 1 を設定すると、行ごとの処理になります。sum()メソッドは、ndarray型の要素を足し合わせます。
In import numpy as np
d1 = np.arange(6)
print(d1)
d2 = d1.reshape(2, 3)
print(d2)
print(d2.sum())
print(d2.sum(axis = 0))
print(d2.sum(axis = 1))
Out [0 1 2 3 4 5]
[[0 1 2]
[3 4 5]]
15
[3 5 7]
[ 3 12]