Numpyの概要
Numpyとは
Numpyとは、数値計算を効率的に行うためのライブラリのこと。データをNumpy配列という多次元配列に格納し操作することで、大量のデータを高速に処理することができる。
Numpyのインポート
as 別名によりnpという名前で使えるようにインポートする。
import numpy as np
以下、このようにインポートされている前提で進める。
Numpy配列の特徴
Numpy配列はNumpyモジュールで独自に定義されている型で、numpy.ndarrayという型である。出力結果は[1 2 3]となり、リストに似ている形だがカンマは出力されない。
以下のような性質を持つ。
- イテラブルである(要素を繰返し取得可能)
- ミュータブルである(要素の追加・削除・更新が可能)
- 格納できるデータ型は同一のものに限る(異なる型の混在は不可)
- 各行の要素数は一致させる必要がある(行ごとに異なる要素数を持つことは不可)
Numpy配列の作成
Numpy配列の作成方法は主に2つ。
どちらもNumpyモジュールの関数を利用する。
(import numpy as npとインポートされている前提)
np.array()
引数にリストまたはタプルを指定して作成する。
np.array([1,2,3,4,5,6])
# [1 2 3 4 5 6]
np.array([[1,2,3],[4,5,6]])
# [[1 2 3]
# [4 5 6]]
np.array([[1,2,3],[4,5]])
# 行ごとの要素数が一致していないのでValueError
np.arange()
引数に 開始点・終了点・ステップを指定して作成する。
終了点は含まない。
開始点とステップは省略可能。
np.arange(0,7,2)
# [0 2 4 6]
np.arange(0,7)
# [0 1 2 3 4 5 6]
np.arange(7)
# [0 1 2 3 4 5 6]
reshape()
Numpy配列が持つメソッドで、配列の次元数を変更することができる。
reshape(a,b) = a行b列へ変更する
reshape(-1) = 1次元配列へ変更する
arr = np.arange(6).reshape(2,3)
# [[0 1 2]
# [3 4 5]]
補足
reshape()で作成されたオブジェクトは元のオブジェクトの実体を参照する。つまり、reshape()で新しく別のNumpy配列を作成していても、元となるオブジェクトは同じものである。
arr1 = np.arange(6)
arr2 = arr1.reshape(2,3)
# arr2を変更する
arr2[0][0] = 1000
print(arr1)
# arr1も変更される
# [1000 1 2 3 4 5]
arr1を元にreshape()でarr2を作成しており、この2つは異なるオブジェクトではあるが、どちらも 同じの配列オブジェクト(実体)を参照することでできている。よって、どちらか一方を変更すると、もう一方にも影響が及ぶ。

copy()
元となる配列オブジェクト自体を、全く新しい実体として作りたい場合はcopy()を使う。
arr1 = np.arange(6)
arr2 = arr1.reshape(2,3).copy()
# arr2を変更する
arr2[0][0] = 10
print(arr1)
# arr1は変更されない
# [0 1 2 3 4 5]
reshape()で作った配列のcopy()を作ると、元となる配列オブジェクトの実体も新しく作られるので、一方の変更がもう一方に影響を及ぼさない。

np.linspace()
要素の値が等間隔となるようなNumpy配列を作成する関数。引数に 開始点・終了点・要素数を指定して、開始点〜終了点の範囲に等間隔な要素を持つNumpy配列を作成する。この場合は終了点も最後の要素として含む。
例えば(0,1,5)と指定すると、0~ 1の間に 5個の要素を持ち、その要素全てが等間隔となるような配列を作成する。
np.linspace(0,1,5)
# [0. , 0.25, 0.5 , 0.75, 1. ]
np.diff()
要素間の差分を要素とする配列を作成する
arr = np.array([0,1,4,9])
print(np.diff(arr))
# [1 3 5]
Numpy配列の情報を調べる
shape
何行何列かを調べるプロパティ。戻り値はタプル。
arr = np.arange(6).reshape(2,3)
print(arr.shape) # (2, 3)
print(arr.shape[0]) # 2
print(arr.shape[1]) # 3
dtype
要素の型を調べるプロパティ。
print(arr.dtype) # int64
size
要素数を調べるプロパティ。
全要素数を得る。(行数ではない)
print(arr.size) # 6
len()
一次元目の要素数を調べる。(行数)
print(len(arr)) # 2
Numpy配列の操作
np.append(arr,要素)
配列に要素を追加した、新しい配列を作る。(元の配列は変えない)
複数要素を追加したい場合はリストまたはタプルで指定する。
arr = np.array([0,1,2])
arr = np.append(arr,3) # arr自体を変更したわけではないので再代入
arr = np.append(arr,[4,5,6])
print(arr)
# [0 1 2 3 4 5 6]
np.insert(arr,指定位置,要素)
配列の指定位置の前に要素を挿入した、新しい配列を作る。(元の配列は変えない)
複数要素を追加したい場合はリストまたはタプルで指定する。
arr = np.array([1,10,1000])
arr = np.insert(arr,2,100)
print(arr)
# [ 1 10 100 1000]
np.delete(arr,指定位置)
配列の指定位置の要素を削除した、新しい配列を作る。(元の配列は変えない)
arr = np.array([0,1,2,3])
arr = np.delete(arr,2)
print(arr)
# [0 1 3]
tolist()
Numpy配列を元に新たなリストを作成する。(Numpy配列自体は変わらない)
arr = np.array([0,1,2,3])
print(arr.tolist())
# [0, 1, 2, 3]
# arr自体はNumpy配列のまま
sort()
Numpy配列(自身)をソートする。
多次元配列の場合は、各行内でのみソートされる。
arr = np.array([3,2,1,0])
arr.sort()
print(arr)
# [0 1 2 3]
np.sort(arr)
配列の要素をソートした新しい配列を作成する。(元の配列は変えない)
多次元配列の場合は、各行内でのみソートされる。
arr = np.array([3,2,1,0])
arr = np.sort(arr)
print(arr) # [0 1 2 3]
np.random.shuffule(arr)
要素の並びをシャッフルする。
arr = np.array([0,1,2,3])
np.random.shuffle(arr)
print(arr) # [1 0 3 2]
要素の参照
インデクス参照
arr[row][col]またはarr[row,col]で参照できる。
arr = np.arange(6).reshape(2,3)
print(arr[1][0]) # 3
arr[1,0] = 100
print(arr)
# [[ 0 1 2]
# [100 4 5]]
スライス指定
インデックス参照arr[row,col]では、row,colの部分はスライス([開始点:終了点:ステップ])で指定できる。(終了点は含まない)
arr = np.arange(9).reshape(3,3)
print(arr[0:2:1,1:3:1])
# [[1 2]
# [4 5]]
列指定は省略することができ、その場合は全列を指定することとなる。つまり、arr[row, :]はarr[row] とも書け、これは指定行の全列分を取り出すことができる。
arr = np.arange(9).reshape(3,3)
print(arr[1,:]) # 第1行の全列分を指定
print(arr[1]) # 全列指定の : は省略できる(上と同じ)
# [3 4 5]
一方で、行指定は省略できないので、全行の特定列を抽出する場合は、全行を表す:を必ず書く必要がある。
arr = np.arange(9).reshape(3,3)
print(arr[:,1]) # 全行の第1列を指定
# [1 4 7]
リストによる複数指定
インデクス参照arr[row,col]のrowやcolに、リストで行番号、列番号を指定し、任意の複数行を抽出できる。arr[[r1,r2],[c1,c2,c3]]
arr = np.arange(9).reshape(3,3)
print(arr[[0,1],:])
# [[0 1 2]
# [3 4 5]]
arr = np.arange(9).reshape(3,3)
print(arr[0:3:2, [1,2]])
#[[1 2]
# [7 8]]

ただし、行と列の両方にリスト指定した場合、対角データが抽出される。
arr = np.arange(9).reshape(3,3)
print(arr[[1,2],[1,2]])
print(arr[[0,2],[0,2]])
# [4 8]
# [0 8]
arrの四隅 [0 2 6 8]を抽出するために行、列ともに指定したい場合は、①任意の行を指定した後、②全行について任意の列を指定する。
arr[[0,2]][:,[0,2]]
# [[0 2]
# [6 8]]
np.ndenumerate(arr)
2次元配列から要素を順に取り出すことができる。
for文のイテラブルとしてnp.ndenumerate(arr)を指定すると第一変数に(行番号,列番号)のタプル・第二変数に要素の値を分割代入することができる。
arr = np.arange(6).reshape(2,3)
for i,item in np.ndenumerate(arr):
print(i,item)
出力結果
(0, 0) 0
(0, 1) 1
(0, 2) 2
(1, 0) 3
(1, 1) 4
(1, 2) 5
ブールインデクス参照
条件式にNumpy配列を使う
Numpy配列を条件式のオペランドとして使うと、Numpy配列の全ての要素を個々に条件判定を行い、その結果(bool値)を要素とするNumpy配列を作成する。
さらに、ブール値を格納したNumpy配列の持つメソッドsum()は、True=1,False=0として計算するので、条件式がTrueとなる要素の合計数を求めることができる。
arr1 = np.arange(9).reshape(3,3)
arr2 = arr1 > 4
print(arr1)
print(arr2)
print(arr2.sum())
出力結果
[[0 1 2]
[3 4 5]
[6 7 8]]
[[False False False]
[False False True]
[ True True True]]
4
条件式をインデクスに使う
Numpy配列をオペランドとして使う条件式によってブール値を格納したNumpy配列を得ることができ、そのブール値のNumpy配列をインデックスとして指定することで、Trueとなる要素を格納した1次元Numpy配列を抽出できる。
arr1 = np.arange(9).reshape(3,3)
print(arr1[arr1 > 4])
# [5 6 7 8]
arr1 > 4によって、ブール値のNumpy配列ができる。
さらにarr1のインデックスとして使うことによって、Trueとなる要素のみを選んだNumpy配列ができる

行列の演算
和 (+)
行列の和は、サイズが同じ行列でのみ求めることができる。
arr1 = np.array([[1,2],[3,4]])
arr2 = np.array([[0,1],[2,3]])
print(arr1 + arr2)
# [[1 3]
# [5 7]]
差 (-)
行列の差は、サイズが同じ行列でのみ求めることができる。
arr1 = np.array([[1,2],[3,4]])
arr2 = np.array([[0,1],[2,3]])
print(arr1 - arr2)
# [[1 1]
# [1 1]]
積
np.dot()
\begin{bmatrix} a & b \\ c & d \end{bmatrix}
\begin{bmatrix} e & f \\ g & h \end{bmatrix}
=
\begin{bmatrix} ae+bg & af+bh \\ ce+dg & cf+dh \end{bmatrix}
n行m列とm行p列の積は、n行p列の行列になる。
arr1 = np.array([[1,2],[3,4]])
arr2 = np.array([[0,1],[2,3]])
print(np.dot(arr1,arr2))
# [[ 4 7]
# [ 8 15]]
np.dot()は@演算子でも代用でき、以下のコードも同じ結果となる。
print(arr1 @ arr2)
\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}
\begin{bmatrix} 0 & 1 \\ 2 & 3 \end{bmatrix}
=
\begin{bmatrix} 1*0+2*2 & 1*1+2*3 \\ 3*0+4*2 & 3*1+4*3 \end{bmatrix}
スカラー倍
全ての成分に同じ値を掛ける
arr1 = np.array([[1,2],[3,4]])
print(arr1 * 2)
# [[2 4]
# [6 8]]
アマダール積 (*)
サイズが同じ行列同士で、成分ごとを掛ける
arr1 = np.array([[1,2],[3,4]])
arr2 = np.array([[0,1],[2,3]])
print(arr1 * arr2)
# [[ 0 2]
# [ 6 12]]
\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}
\begin{bmatrix} 0 & 1 \\ 2 & 3 \end{bmatrix}
=
\begin{bmatrix} 1*0 & 2*1 \\ 3*2 & 4*3 \end{bmatrix}
ブロードキャスト
2次元配列の演算の際、行または列のどちらかが足りない場合に行や列を補う仕組みのこと。
arr1 = np.array([[1,2],[3,4]])
arr2 = np.array([[10,20]])
print(arr1 + arr2)
# [[11 22]
# [13 24]]
\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}
\begin{bmatrix} 10 & 20 \end{bmatrix}
=
\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}
\begin{bmatrix} 10 & 20 \\ 10 & 20 \end{bmatrix}
=
\begin{bmatrix} 11 & 22 \\ 13 & 24 \end{bmatrix}
逆行列
逆行列とは、積が単位行列になるような行列のことで、逆行列を持つような行列のことを正則行列という。
結果の行列の要素の型は浮動小数点型(float64)になる。
np.linalg.inv()
正則行列の逆行列を求めることができる。
arr1 = np.array([[1,2],[1,3]])
print(np.linalg.inv(arr1))
# [[ 3. -2.]
# [-1. 1.]]
# float64型になる
np.linalg.pinv()
正則行列ではない行列でも、エラーならずに疑似逆行列として求めることができる。
arr1 = np.array([[1,2,3],[1,1,2]])
print(np.linalg.pinv(arr1))
# [[-1.00000000e+00 1.66666667e+00]
# [ 1.00000000e+00 -1.33333333e+00]
# [-6.92807316e-16 3.33333333e-01]]
print(np.linalg.inv(arr1)) # これだとlinalgErrorになる
転置行列
転置行列とは元の行列の行成分と列成分を入れ替えた行列のこと。
Tプロパティ
arr1 = np.array([[1,2,3],[4,5,6]])
print(arr1.T)
# [[1 4]
# [2 5]
# [3 6]]
transpose()メソッド
arr1 = np.array([[1,2,3],[4,5,6]])
print(arr1.transpose())
# [[1 4]
# [2 5]
# [3 6]]
np.transepose(arr)
arr1 = np.array([[1,2,3],[4,5,6]])
print(np.transpose(arr1))
# [[1 4]
# [2 5]
# [3 6]]
以上3つの方法で作成した転置行列は、元の行列と同一ビューとなるので、一方の変更がもう一方に影響を与える。
これを回避するには、.copy()を適用して別ビューを作成する。
Numpy配列の比較
np.array_equal(arr1,arr2,equal_nan=False)
2つのNumpy配列が同じ形状かつ全ての要素が等しい場合にTrueを返す。形状が異なる場合はFalseを返す。
arr1 = np.array([[1,2],[1,2]])
arr2 = np.array([[1,2],[1,2]])
arr3 = np.array([[1,2]])
print(np.array_equal(arr1,arr2)) # True
print(np.array_equal(arr1,arr3)) # False
通常はnp.nan == np.nanはFalseであるが、キーワード引数equal_nanにTrueを渡すと、np.nan同士の比較はTrueと設定することができる。(デフォルト値はFalse)
arr1 = np.array([np.nan])
arr2 = np.array([np.nan])
print(np.array_equal(arr1,arr2)) # False
print(np.array_equal(arr1,arr2,equal_nan=True)) # True
np.array_equiv(arr1,arr2)
2つのNumpy配列が同じ形状かつ全ての要素が等しい場合にTrueを返す。形状が異なる場合はブロードキャストを行った上で全ての要素が等しい場合はTrueを返すで比較する。equivalentは「相当する」という意味。
np.array_equal()と違ってequal_nan引数はない。
arr1 = np.array([[1,2],[1,2]])
arr2 = np.array([[1,2],[1,2]])
arr3 = np.array([[1,2]])
print(np.array_equiv(arr1,arr2)) # True
print(np.array_equiv(arr1,arr3)) # True
np.shares_memory()
2つの配列が同じメモリのデータを共有しているかどうか判定する。
arr1 = np.arange(6)
arr2 = arr1.reshape(2,3)
print(np.shares_memory(arr1,arr2)) #True
reshape()は元の配列の実体をもとにして次元数を変更したビューを返す。reshape()によって作成されたオブジェクト自体(arr2)は元の配列(arr1)とは別物だが、そのビューオブジェクトが参照しているオブジェクト(0~5の配列)は同一のものである。
ユニバーサルファンクション
ユニバーサルファンクションとは、配列の要素を一括で変換する仕組みのことで、これが高速な処理を可能にしている。
演算(sprt,power,sin,mod)
arr = np.array([[1,2],[3,4]])
print(np.power(arr,2)) # べき乗
print(np.sqrt(arr)) # 平方根
print(np.sin(arr)) # sin,cos,tan
print(np.mod(arr,2)) # 割った余り
[[ 1 4]
[ 9 16]]
[[1. 1.41421356]
[1.73205081 2. ]]
[[ 0.84147098 0.90929743]
[ 0.14112001 -0.7568025 ]]
[[1 0]
[1 0]]
小数点(ceil,floor,rint)
arr = np.array([[0.4,0.5,0.6],[0.9,1.0,1.1]])
print(np.ceil(arr)) # 切り上げ
print(np.floor(arr)) # 切り捨て
print(np.rint(arr)) # 整数へ丸め
[[1. 1. 1.]
[1. 1. 2.]]
[[0. 0. 0.]
[0. 1. 1.]]
[[0. 0. 1.]
[1. 1. 1.]]
符号(abs,positive,negative)
arr = np.array([-1,0,1])
print(np.abs(arr)) # 絶対値
print(np.positive(arr)) # +を付加
print(np.negative(arr)) # -を付加
[1 0 1]
[-1 0 1]
[ 1 0 -1]
その他(isin,isnan)
arr = np.array([[1,2],[3,np.NaN]])
print(np.isin(arr,3)) # 含まれているか
print(np.isnan(arr)) # 欠損値かどうか
[[False False]
[ True False]]
[[False False]
[False True]]
Numpy配列の集計
集計するためのメソッドは渡す引数によって集計の対象が変わる。
| 引数 | 集計の対象 |
|---|---|
| なし | 全体 |
| 0 | 各列の合計 |
| 1 | 各行の合計 |
sum()
arr = np.array([[1,2,3],[4,5,6]])
print(arr.sum()) # 21
print(arr.sum(0)) # [5 7 9]
print(arr.sum(1)) # [ 6 15]
min()
arr = np.array([[1,2,3],[4,5,6]])
print(arr.min()) # 1
print(arr.min(0)) # [1 2 3]
print(arr.min(1)) # [1 4]
max()
arr = np.array([[1,2,3],[4,5,6]])
print(arr.max()) # 6
print(arr.max(0)) # [4 5 6]
print(arr.max(1)) # [3 6]
mean()
arr = np.array([[1,2,3],[4,5,6]])
print(arr.mean()) # 3.5
print(arr.mean(0)) # [2.5 3.5 4.5]
print(arr.mean(1)) # [2. 5.]
乱数発生(random)
numpyモジュールの中に独自のrandomモジュールがあるので、numpyモジュールをインポートすればrandomモジュールをインポートする必要がない。
np.random.rand(n)
0.0~1.0の範囲内で n個の浮動小数点の乱数を発生させる。
print(np.random.rand(5))
# [0.29704614 0.55228022 0.80563698 0.99353206 0.8414947 ]
np.random.randint(a,b,n)
a~bの範囲内で n個の整数の乱数を発生させる。(bは含まない)
aの省略時、0~bの範囲内となる。
nの省略時、1個の乱数が発生する。
print(np.random.randint(1,100,5))
# [56 81 78 27 54]
np.random.normal(m,s,n)
平均=m,標準偏差=sの正規分布に従った乱数をn個発生させ、それを要素とするNumpy配列を作成する。
np.random.randn(n)
平均=0,標準偏差=1の正規分布に従った乱数をn個発生させ、それを要素とするNumpy配列を作成する。
np.random.seed(a)
テストなどで同じ乱数を発生させたい場合に疑似乱数を発生させる。
乱数を発生させる前に実行したseed()の引数が同じなら、同じ乱数が発生する。
np.random.seed(1)
print(np.random.randint(100))
np.random.seed(2)
print(np.random.randint(100))
np.random.seed(1)
print(np.random.randint(100))
np.random.seed(2)
print(np.random.randint(100))
37
40
37
40
np.random.
ヒストグラム
ヒストグラムとは
横軸に階級、縦軸に度数をとり、階級ごとの度数を帯状に表したもので、データの分布状況が視覚的にわかる。
matplotlib
matplotlibとはデータを可視化するためのライブラリで、そのmatplotlibパッケージの中にあるpyplotモジュールは、Numpy配列に格納されたデータから様々なグラフを描画することができる。
また、Jupiter Notebookにおいてグラフを表示するためにマジックハンドでおまじないをかておく。
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
show()
hist()関数で作成したヒストグラムを、Jupter Notebook上で表示するための関数。
plt.hist(arr)
pyplotモジュールのhist関数は、第一引数にNumpy配列・リスト・Series型・1次元DataFrame型などを受け取り、ヒストグラムを作成する。第二引数以降には様々なキーワード引数でグラフの設定をすることができる。
| 引数名 | 引数の型 | 内容 | 初期値 |
|---|---|---|---|
| bins | 整数 | 横軸の階級をいくつにするか | 10 |
| range | (min,max) [min,max] |
使用するデータ範囲を指定する | データのminとmax |
| color | "blue" "red" "yellow" など |
グラフの色指定 | "blue" |
| align | "left" "mid" "right" |
棒の位置がメモリの左か中央か右 | "left" |
| density (以前は normed) |
True False |
縦軸を確率密度に変更 | False |
| orientation | "vertical" "horizontal" |
縦軸と横軸を入れ替える("horizontal") | "vertical" (入れ替えなし) |
sigma = 2.5
mu = 50
data = sigma * np.random.randn(10_000) + mu
# 平均=0 標準偏差=1の正規分布に従った乱数を1000個格納するNumpy配列
plt.hist(data,bins=100)
plt.show()






