【Python】NumPyで効率的に計算処理をしてみよう!

Pythonロゴ

Pythonには機械学習や画像解析、音声解析を行うためにパッケージが用意されています。今回は計算処理に関してNumPyパッケージを確認します。

NumPyパッケージとは?

NumPyは配列を扱う算術演算のパッケージになります。
Pythonでは機械学習や統計分析など複雑な計算処理を求められる場合が多くあります。効率よく・短い時間で結果を出すためにNumPyを利用します。計算処理に関する命令が多く搭載されており、行列計算が得意な特徴があります。

NumPyを使うには?

NumPyは標準で搭載されていないため pip コマンドで導入します。
Anacondaを利用している場合は標準で導入が完了しています。
インストールは下記コマンドで可能です。

pip install numpy

基本メソッド

NumPyの配列を生成する: array()

NumPyを利用するには numpyモジュールをimportする必要があります。
モジュール呼び出し後は array()にて配列を作成します。
引数はリストかタプル型が利用できます。
出力結果はリストと同じ表記になるため注意が必要になります。

import numpy

numpy_int = numpy.int([0, 1, 2, 3, 4, 5])
print(type(numpy_int))
print(numpy_int)

# 結果
# <class 'numpy.ndarray'>
# [0 1 2 3 4 5]

NumPyの注意事項

NumPyの配列は数値と文字列など2種類の型を混在する事ができません。
格納は1種類にまとめる必要があります。
複数の要素を入れた場合、文字列型に変換されます。

numpy_float = numpy.array([0.2, 1.0, 1.8, 2.0, 3.3])
print(numpy_float)
# 結果 [0.2 1.  1.8 2.  3.3]

numpy_str = numpy.array(['aa', 'bb', 'cc'])
print(numpy_str)
# 結果 ['aa' 'bb' 'cc']

numpy_bool = numpy.array([True, False, False])
print(numpy_bool)
# 結果 [ True False False]

numpy_err = numpy.array([1, 'aa', False])
print(numpy_err)
# 結果 ['1' 'aa' 'False'] <= 文字列になる

NumPyのメモリ使用を制限する

NumPyは標準でint64, fload64などメモリの容量を無駄に使う可能性があります。たくさんの容量は必要無い場合は、array()にデータ型を指定することで容量を削減することができます。

numpy_int = numpy.array([0, 1, 2, 3, 4, 5], dtype=numpy.int8)
print(numpy_int)
print(numpy_int.dtype)

# 結果
# [0 1 2 3 4 5]
# int8

データ型には下記種類があるため扱う型をみて判断する必要があります。

データ型範囲
int8符号あり整数型-128 〜 127
int16符号あり整数型-32768 〜 32767
int32符号あり整数型約 -21億 〜 21億
int64符号あり整数型約 -922京 〜 922京
uint8符号なし整数型0 〜 255
uint16符号なし整数型0 〜 65535
uint32符号なし整数型0 〜 42億
uint64符号なし整数型0 〜 1844京
float16半精度浮動小数点数
float32半精度浮動小数点数
float64半精度浮動小数点数

データ型を変換する: astype()

NumPyで作成した配列内の値を別のデータ型に変換した場合があります。
astype()を利用する事で内部の値を変換することができます。

numpy_float = numpy.array([0.2, 1.0, 1.8, 2.0, 3.3])
print(numpy_float)

numpy_int = numpy_float.astype(numpy.int8)
print(numpy_int)

# 結果
# [0.2 1.  1.8 2.  3.3]  <= 少数点が
# [0 1 1 2 3]            <= 整数に変換

連続する整数を格納する: arange()

NumPyで連続した整数を配列内に格納する場合、arange()を利用します。引数の内容により結果が変わります。

arange(a): 0 から a 未満
arange(a, b): a から b 未満
arange(a, b, c): a から b 未満(cずつ加算)
numpy_int = numpy.arange(5)
print(numpy_int)
# 結果 [0 1 2 3 4]
# 引数が1つの場合 0 から N数値未満

numpy_int = numpy.arange(5, 10)
print(numpy_int)
# 結果 [5 6 7 8 9]
# 引数が2つの場合  から N数値未満

numpy_int = numpy.arange(5, 10, 2)
print(numpy_int)
# 結果 [5 7 9]

引数条件で分割して格納する: linspace()

NumPyで指定条件で分割した整数を配列内に格納する場合、linspace()を利用します。

linspace(a, b, c): a から b の値の範囲を c 分割する
numpy_int = numpy.linspace(0, 10, 3)
print(numpy_int)

# 結果 [ 0.  5. 10.]

数値0を指定数 格納する: zeros()

NumPyの配列に数値0を指定数格納します。

zeros(a): 数値0を a 点格納する
numpy_int = numpy.zeros(5)
print(numpy_int)

# 結果 [0. 0. 0. 0. 0.]

ランダムな値を指定数 格納する: random.rand()

NumPyの配列にランダムな値を指定数格納します。格納される値は0から1までの間の小数点になります。

random.rand(a): ランダムな値を a 点格納する
numpy_float = numpy.random.rand(5)
print(numpy_float)

# 結果 [0.51240914 0.99704386 0.18455562 0.05757905 0.47002863]

仮の値を指定数 格納する: empty()

NumPyの配列に仮の値を指定数格納します。格納される値はルールが無く保証できない値になります。

empty(a): 仮の値を a 点格納する
numpy_int = numpy.empty(5)
print(numpy_int)

# 結果 [2.5e-323 3.0e-323 3.5e-323 4.0e-323 4.4e-323]

配列を結合する: concatenate()

NumPyの配列を結合する場合は、concatenate()を利用します。

concatenate([a, b]): a と b の配列を結合する
numpy_int1 = numpy.array([1, 2, 3])
numpy_int2 = numpy.array([11, 22, 33])
numpy_int3 = numpy.concatenate([numpy_int1, numpy_int2])
print(numpy_int3)

# 結果 [ 1  2  3 11 22 33]

NumPyの多次元配列を生成する: array()

NumPyでは多次元の配列を生成することもできます。array()を利用して生成します。

numpy_int = numpy.array([[0, 1, 2], [3, 4, 5]])
print(type(numpy_int))
print(numpy_int)

# 結果
# <class 'numpy.ndarray'>
# [[0 1 2]
#  [3 4 5]]

多次元配列を1次元配列に変換する: flatten()

多次元の配列を1次元の配列に変換することができます。flatten()を利用して変換処理をおこないます。

numpy_int1 = numpy.array([[0, 1, 2], [3, 4, 5]])
numpy_int2 = numpy_int1.flatten()
print(numpy_int1)
print(numpy_int2)

# 結果
# [[0 1 2]
#  [3 4 5]]
# [0 1 2 3 4 5]

変換処理には別で ravel() という処理もあります。
ravel()はデータのコピーを返さず破壊的な変更となりますが、コピー処理がないため速く動作します。

1次元配列を多次元配列に変換する: reshape()

1次元配列を多次元配列に配列に変換することができます。reshape()にて引数の条件で変換処理をおこないます。

reshape(a, b): 縦a行、横b列の連想配列に変換
numpy_int1 = numpy.array([1, 2, 3, 4, 5, 6])
numpy_int2 = numpy_int1.reshape(3, 2)
print(numpy_int1)
print(numpy_int2)

# 結果
# [1 2 3 4 5 6]
# [[1 2]
#  [3 4]
#  [5 6]]

NumPyの配列操作

要素の参照

1次元配列

NumPyで生成された配列はリストと同じ形で参照が可能です。
インデックス番号(以降:IDX)を指定して参照します。

numpy_str = numpy.array(['a', 'b', 'c', 'd', 'e', 'f'])
print(numpy_str[0])
# 結果 a

print(numpy_str[:3]) # 始めからIDX(3未満)まで指定
# 結果 ['a' 'b' 'c']

print(numpy_str[3:]) # IDX(3以上)から最終まで指定
# 結果 ['d' 'e' 'f']

print(numpy_str[0:6:2]) # IDX(0以上)からIDX(6未満)まで1飛ばしで指定
# 結果 ['a' 'c' 'e']

print(numpy_str[::3]) # 全ての要素から2飛ばしで指定
# 結果 ['a' 'd']

多次元配列

多次元配列の場合は 縦,横 の形式で指定します。

numpy_str = numpy.array([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']])
# 内容
# [['a', 'b', 'c']
#  ['d', 'e', 'f']
#  ['g', 'h', 'i']]

print(numpy_str[0, 0])
# 結果 a

print(numpy_str[:2, :1]) # 縦IDX(2未満) 横IDX(1未満)指定
# 結果 
# [['a']
#  ['d']]

print(numpy_str[:2, :2]) # 縦IDX(2未満) 横IDX(2未満)指定
# 結果 
# [['a' 'b']
#  ['d' 'e']]

print(numpy_str[1:3, 1:3]) # 縦IDX(1以上 3未満) 横IDX(1以上 3未満)指定
# 結果 
# [['e' 'f']
#  ['h' 'i']]

print(numpy_str[0:3, 0:3:2]) # 縦IDX(0以上 3未満) 横IDX(0以上 3未満 1飛ばし)指定
# 結果 
# [['a' 'c']
#  ['d' 'f']
#  ['g' 'i']]

要素の追加: append()

1次元配列

NumPyで生成された配列に要素を追加します。追加は append() を使います。
要素の追加は1点または複数可能です。

numpy_str = numpy.array(['a', 'b', 'c'])
numpy_str = numpy.append(numpy_str, 'z')
print(numpy_str)
# 結果 ['a' 'b' 'c' 'z']

numpy_str = numpy.array(['a', 'b', 'c'])
numpy_str = numpy.append(numpy_str, ['x', 'y', 'z'])
print(numpy_str)
# 結果 ['a' 'b' 'c' 'x' 'y' 'z']

多次元配列

多次元配列にappend()を利用して要素を追加すると1次元配列に変換されるようです。多次元配列に要素を追加する場合は下の「指定位置に要素を追加」を利用ください。

numpy_str = numpy.array([['a', 'b'], ['c', 'd']])
print(numpy_str)
numpy_str = numpy.append(numpy_str, 'z')
print(numpy_str)

# 結果
# [['a' 'b']
#  ['c' 'd']]
# ['a' 'b' 'c' 'd' 'z'] <= 1次元配列に変換

要素の追加: insert()

1次元配列

NumPyで生成された配列に要素を追加します。insertはIDX番号で指定した位置に要素を追加します。

# IDX1番目に追加
numpy_str = numpy.array(['a', 'b', 'c'])
numpy_str = numpy.insert(numpy_str, 1, 'z')
print(numpy_str)
# 結果 ['a' 'z' 'b' 'c']

# IDX2番目に複数追加
numpy_str = numpy.array(['a', 'b', 'c'])
numpy_str = numpy.insert(numpy_str, 2, ['x', 'y', 'z'])
print(numpy_str)
# 結果 ['a' 'b' 'x' 'y' 'z' 'c']

多次元配列

多次元配列にinsert()を利用して要素を追加します。
4番目の引数に0を指定する事で横列追加、1を指定する事で縦列追加になります。
最終行または最終列に追加する場合は事前にshapeを使い最終のIDX番号を取得して利用します。

numpy_str1 = numpy.array([['a', 'b'], ['c', 'd']])
numpy_str2 = numpy.array(['x', 'y'])

# 最初の行に追加
numpy_str = numpy.insert(numpy_str1, 0, numpy_str2, 0)
print(numpy_str)
# 結果
# [['x' 'y']
#  ['a' 'b']
#  ['c' 'd']]

# IDX1行目に追加
numpy_str = numpy.insert(numpy_str1, 1, numpy_str2, 0)
print(numpy_str)
# 結果
# [['a' 'b']
#  ['x' 'y']
#  ['c' 'd']]

# IDX1列目に追加
numpy_str = numpy.insert(numpy_str1, 1, numpy_str2, 1)
print(numpy_str)
# 結果
# [['a' 'x' 'b']
#  ['c' 'y' 'd']]

# 最終行に追加
(mh, mw) = numpy_str.shape
numpy_str = numpy.insert(numpy_str1, mh, numpy_str2, 0)
print(numpy_str)
# 結果
# [['a' 'b']
#  ['c' 'd']
#  ['x' 'y']]

# 最終列に追加
(mh, mw) = numpy_str.shape
numpy_str = numpy.insert(numpy_str1, mw, numpy_str2, 1)
print(numpy_str)
# 結果
# [['a' 'b' 'x']
#  ['c' 'd' 'y']]

要素の削除: delete()

1次元配列

NumPyで生成された配列の要素を削除します。削除はdelete()を利用します。

# IDX1番目を削除
numpy_str = numpy.array(['a', 'b', 'c', 'd'])
numpy_str = numpy.delete(numpy_str, 1)
print(numpy_str)
# 結果 ['a' 'c' 'd']

# IDX1と3番目を削除
numpy_str = numpy.array(['a', 'b', 'c', 'd'])
numpy_str = numpy.delete(numpy_str, [1, 3])
print(numpy_str)
# 結果 ['a' 'c']

多次元配列

NumPyで生成された配列の要素を削除します。
3番目の引数に0を指定する事で横列削除、1を指定する事で縦列削除になります。

# IDX1行目を削除
numpy_str = numpy.array([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']])
numpy_str = numpy.delete(numpy_str, 1, 0)
print(numpy_str)
# 結果
# [['a' 'b' 'c']
#  ['g' 'h' 'i']]

# IDX1列目を削除
numpy_str = numpy.array([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']])
numpy_str = numpy.delete(numpy_str, 1, 1)
print(numpy_str)
# 結果
# [['a' 'c']
#  ['d' 'f']
#  ['g' 'i']]

要素に四則演算

1次元配列

配列に入っている要素に四則演算を行うことができます。

# 配列に1加算
numpy_int1 = numpy.array([1, 2, 3, 4, 5, 6])
numpy_int2 = numpy_int1 + 1
print(numpy_int1)
print(numpy_int2)
# 結果 
# [1 2 3 4 5 6]
# [2 3 4 5 6 7]

# 配列に2乗算
numpy_int1 = numpy.array([1, 2, 3, 4, 5, 6])
numpy_int2 = numpy_int1 * 2
print(numpy_int1)
print(numpy_int2)
# 結果 
# [1 2 3 4  5  6]
# [2 4 6 8 10 12]

多次元配列

# 配列に1加算
numpy_int1 = numpy.array([[1, 2], [3, 4]])
numpy_int2 = numpy_int1 + 1
print(numpy_int2)
# 結果 
# [[2 3]
#  [4 5]]

# 配列に2乗算
numpy_int1 = numpy.array([[1, 2], [3, 4]])
numpy_int2 = numpy_int1 * 2
print(numpy_int2)
# 結果 
# [[2 4]
#  [6 8]]

ユニバーサル関数

NumPyには配列の全要素に対して、要素毎に演算を行い結果を返す関数が用意されています。それらをユニバーサル関数と言います。
一部ユニバーサル関数を確認します。

要素の加算: add()

上記、四則演算と違い2つの配列に格納されている要素を使って加算します。

numpy_int1 = numpy.array([1, 2, 3])
numpy_int2 = numpy.array([1, 1, 1])
numpy_int = numpy.add(numpy_int1, numpy_int2)
print(numpy_int)

# 結果 [2 3 4]

要素の減算: subtract()

2つの配列に格納されている要素を使って減算します。

numpy_int1 = numpy.array([1, 2, 3])
numpy_int2 = numpy.array([1, 1, 1])
numpy_int = numpy.subtract(numpy_int1, numpy_int2)
print(numpy_int)

# 結果 [0 1 2]

多次元配列の要素格納を左右反転: subtract()

numpy_int = numpy.array([[1, 2, 3], [4, 5, 6]])
numpy_int = numpy.subtract(numpy_int)
print(numpy_int)

# 結果
# [[3 2 1]
#  [6 5 4]]

多次元配列の要素格納を上下反転: fliplr()

numpy_int = numpy.array([[1, 2, 3], [4, 5, 6]])
numpy_int = numpy.fliplr(numpy_int)
print(numpy_int)

# 結果
# [[4 5 6]
#  [1 2 3]]

多次元配列の要素格納を回転: rot90()

2番目の引数に0を指定する事で要素格納の位置が回転します。
0: 0度 1: 反時計周り90度 2: 時計周り90度 3: 180度

# 0度
numpy_int = numpy.array([[1, 2], [3, 4]])
numpy_int = numpy.rot90(numpy_int, 0)
print(numpy_int)
# 結果
# [[1 2]
#  [3 4]]

# 1: 反時計周り90度
numpy_int = numpy.rot90(numpy_int, 1)
print(numpy_int)
# 結果
# [[2 4]
#  [1 3]]

# 2: 時計周り90度
numpy_int = numpy.rot90(numpy_int, 2)
print(numpy_int)
# 結果
# [[3 1]
#  [4 2]]

# 3: 180度
numpy_int = numpy.rot90(numpy_int, 3)
print(numpy_int)
# 結果
# [[4 3]
#  [2 1]]

その他ユニバーサル関数に関して

ユニバーサル関数は二項演算や三角関数など色々な処理が用意されています。
用意されている処理は下記公式サイトをご確認ください。

参考 Mathematical functionsNumPy

サンプルプログラム

こちらの記事で作成したプログラムはGitHub環境にアップしております。
下記からダウンロードいただけます。

参考 nump.py スクリプトGitHub python-beginner