【入門】numpyの使い方|15分で徹底攻略!
- numpyの機能が多すぎて混乱、重要なものを体系的に学びたい…
- 重要なnumpyの文法を押さえたい
この悩みを解決します。
いまや『numpy』はPythonで数値計算・機械学習を行う際には必要不可欠なツールです。
確かに始めの頃は私も機能が多くて混乱していました。
本記事では、numpyの重要な文法・使えると便利な文法を整理し解説していきます。
記事を読み終えると、numpyをある程度自由自在に使えるようになります。
Numpyの基本知識
Numpyは、科学や数学のための数値計算ライブラリです。
Numpyを利用することで、データ解析で必要不可欠な行列の計算を高速で行うことができます。
下記をターミナルに入力することで『Numpy』をインストールすることができます。
$ pip3 install numpy
*Google Colabを使用している方は、デフォルでインストールされているので特にインストールする必要はありません。
Google Colabの導入方法に関しては下記を参考にしてください。
Numpyのインポート
以下のコードをNotebook上で実行すると、Numpyをインポートできます。
import numpy as np
このようにインポートすることで、『np』でNumpyを呼び出すことができます。
この『np』という名付け方は慣習です。
Numpyの配列の生成方法
まずは、さまざまなNumpy配列を生成する方法を紹介していきます。
また、Numpyの配列のことは、一般的に『ndarray』と呼ばれます!
- array : ndarray配列を生成
- arange : 値が等間隔に変化する配列を生成
- linspace : 与えた範囲を等間隔に分割した配列を生成
- ones : 要素が1の配列を生成
- zeros : 要素が0の配列を生成
- eye : 単位行列を生成
詳しく説明していきます。
array : ndarray配列を生成
リストをarray関数に渡すことで、numpyが提供する『ndarray』配列を生成することができます。
まずは、一次元の配列を作ってみましょう。
np.array([1, 2, 3])
<output>
array([1, 2, 3])
次に二次元配列を作成してみましょう。
np.array([[1, 2, 3], [4, 5, 6]])
<output>
array([[1, 2, 3],
[4, 5, 6]])
補足ですが、numpyでは、配列の次元をrank
と言います。
つまり、ここまでrank=1
, rank=2
の配列を作ったことになります。
また、dtype
を指定することで、指定した型の配列を作ることができます。
# 型をfloatに設定
np.array([[1, 2, 3], [4, 5, 6]], dtype=float)
<output>
array([[1., 2., 3.],
[4., 5., 6.]])
また、asarryを使ってもndarray配列を作ることができます。
np.asarray([1, 2, 3])
<output>
array([1, 2, 3])
arrayとasarrayの違いは値が同期されるかされないかの違いです。
少し応用なので、初心者の方は、np.array
のみ利用できればOKです!!
一応、同期を理解するための具体例を紹介しておきます。
# コピーになる
lis1 = [1, 2, 3]
array1 = np.array(lis1)
array2 = np.array(array1)
array2[0] = 100
print(f'Case Array {array1} : {array2}')
# 同期される
lis3 = [1, 2, 3]
array3 = np.asarray(lis3)
array4 = np.asarray(array3)
array4[0] = 100
print(f'Case Asarray {array3}:{array4}')
<output>
Case Array [1 2 3] : [100 2 3]
Case Asarray [100 2 3]:[100 2 3]
arange : 値が等間隔に変化する配列を生成
arange関数は、引数として(start, stop, step)という形式で引数を与えることで配列を生成します。
*startの値は含みますが、stopの値は含まないことに注意しましょう。
np.arange(4, 20, 2)
<output>
array([ 4, 6, 8, 10, 12, 14, 16, 18])
Stepの部分に『-1』を指定することで、降順で配列を生成できます。
# 降順の配列を作成
np.arange(20, 10, -1)
<output>
array([20, 19, 18, 17, 16, 15, 14, 13, 12, 11])
linspace : 与えた範囲を等間隔に分割した配列を生成
linspace関数を用いることで、等間隔な配列を作ることができます。
引数としては、(start, stop, 要素数)を指定することができます。
*arangeのときと異なり、デフォルでstopの値を含みます!
np.linspace(0, 1, 5)
<output>
array([0. , 0.25, 0.5 , 0.75, 1. ])
引数にendpoint = False
とすることでstopの値を含まなくすることができます。
np.linspace(0, 1, 5, endpoint = False)
<output>
array([0. , 0.2, 0.4, 0.6, 0.8])
ones : 要素が1の配列を生成
np.ones
を用いることで、要素が1の配列を生成することができます。
引数には、タプル形式で配列の形状を入力します。
np.ones((2, 2))
<output>
array([[1., 1.],
[1., 1.]])
zeros : 要素が0の配列を生成
np.zeros
で要素が0の配列を生成することができます。
同様に、引数には、タプル形式で配列の形状を入力します。
np.zeros((3, 4))
<output>
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
eye : 単位行列を生成
np.eye
を用いることで、単位行列を生成することができます。
引数には、生成する行列のサイズを指定してください。
np.eye(5)
<output>
array([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.]])
Numpyによる乱数生成
次に、Numpyを用いて乱数を生成する方法を紹介します。
- random.seed : 乱数のシードを固定
- random.rand : 0〜1の一様乱数を生成
- random.randn : 標準正規分布から乱数生成
- random.randint : 指定した範囲の整数乱数を生成
random.seed : 乱数のシードを固定
乱数のシードを固定することで、乱数の再現性を担保することができます。
より簡単に説明すると、シードを固定することで毎回同じ乱数を生成するようになります!!
機械学習やデータ解析等では、再現性を担保することは大切なので最初に設定しておくことをオススメします。
具体的には、下記のコードで設定できます。
# 乱数のシードを固定
np.random.seed(1)
引数を他の数字にすることで、乱数のシードは変化します。
特に気にせず適当に数字を入力しましょう。
random.rand : 0〜1の一様乱数を生成
np.random.rand
を使用することで0〜1の一様乱数を生成することができます。
np.random.rand()
<output>
0.4728617697542056
下記のコードで多次元配列の一様乱数を生成することができます。
np.random.rand(5, 5)
<output>
array([[0.58949042, 0.2016367 , 0.6536451 , 0.96601509, 0.78657448],
[0.20699415, 0.38918657, 0.64385908, 0.21698741, 0.28100744],
[0.80928114, 0.15305058, 0.65002492, 0.86956368, 0.82423989],
[0.54919992, 0.93332536, 0.59593206, 0.99904918, 0.99065101],
[0.31950689, 0.67079156, 0.42423613, 0.64338711, 0.14761924]])
random.randn : 標準正規分布から乱数生成
np.random.randn
を使用することで、平均0分散1の標準正規分布から乱数を生成することができます。
下記のコードで乱数を生成できます。
np.random.randn()
<output>
1.6243453636632417
多次元配列の乱数も下記のコードで生成できます。
np.random.randn(5, 5)
<output>
array([[-0.61175641, -0.52817175, -1.07296862, 0.86540763, -2.3015387 ],
[ 1.74481176, -0.7612069 , 0.3190391 , -0.24937038, 1.46210794],
[-2.06014071, -0.3224172 , -0.38405435, 1.13376944, -1.09989127],
[-0.17242821, -0.87785842, 0.04221375, 0.58281521, -1.10061918],
[ 1.14472371, 0.90159072, 0.50249434, 0.90085595, -0.68372786]])
random.randint : 指定した範囲の整数乱数を生成
np.random.randint
を利用することで指定した範囲の整数乱数を生成することができます。
具体例を以下に示します。
# 0以上10未満の整数をランダムに生成
np.random.randint(0, 10)
4
配列のサイズを指定する場合は、引数size
を以下のように指定します。
np.random.randint(0, 10, size=(3, 3))
<output>
array([[4, 4, 3],
[6, 8, 3],
[0, 6, 0]])
numpy配列の演算
numpyの配列を生成する方法は理解できたと思うので、次は配列同士の演算を説明します。
一次元配列の演算
一次元配列の演算を以下にまとめます。
# サンプル
vec1 = np.array([1, 2, 3])
vec2 = np.array([4, 5, 6])
print("要素同士の足し算:", vec1+vec2)
print("要素同士の引き算:", vec1-vec2)
print("要素同士の掛け算:" ,vec1*vec2)
print("要素同士の割り算:", vec1/vec2)
print("数値との足し算:", vec1+2)
print("数値との引き算:", vec1-2)
print("数値との掛け算:", vec1*2)
print("数値との割り算:", vec1/2)
print("ベクトルの内積:", np.dot(vec1, vec2))
# @でも内積が計算できる
print("ベクトルの内積2:", vec1@vec2)
<output>
要素同士の足し算: [5 7 9]
要素同士の引き算: [-3 -3 -3]
要素同士の掛け算: [ 4 10 18]
要素同士の割り算: [0.25 0.4 0.5 ]
数値との足し算: [3 4 5]
数値との引き算: [-1 0 1]
数値との掛け算: [2 4 6]
数値との割り算: [0.5 1. 1.5]
ベクトルの内積: 32
ベクトルの内積2: 32
リストの場合は、足し算は『要素の結合』が実行されることに注意しましょう。
# リストの場合は配列の結合になる
lis1 = [1, 2, 3]
lis2 = [1, 2, 3]
lis1 + lis2
<output>
[1, 2, 3, 1, 2, 3]
多次元配列の演算
次に多次元配列(代表例として二次元)の四則演算をまとめました。
array1 = np.array([[1, 2, 3], [4, 5, 6]])
array2 = np.array([[1, 2, 3], [4, 5, 6]])
array3 = np.array([[1, 2], [3, 4]])
print("要素同士の足し算:\n", array1+array2)
print("要素同士の引き算:\n", array1-array2)
print("要素同士の掛け算:\n", array1*array2)
print("要素同士の割り算:\n", array1/array2)
print("数値との足し算:\n", array1+2)
print("数値との引き算:\n", array1-2)
print("数値との掛け算:\n", array1*2)
print("数値との割り算:\n", array1/2)
print("行列積:\n", np.dot(array3, array3))
print("行列積(形状に注意):\n", np.dot(array3, array1))
print("行列積1:\n", array3@array3)
print("行列積2(形状に注意):\n", array3@array1)
<output>
要素同士の足し算:
[[ 2 4 6]
[ 8 10 12]]
要素同士の引き算:
[[0 0 0]
[0 0 0]]
要素同士の掛け算:
[[ 1 4 9]
[16 25 36]]
要素同士の割り算:
[[1. 1. 1.]
[1. 1. 1.]]
数値との足し算:
[[3 4 5]
[6 7 8]]
数値との引き算:
[[-1 0 1]
[ 2 3 4]]
数値との掛け算:
[[ 2 4 6]
[ 8 10 12]]
数値との割り算:
[[0.5 1. 1.5]
[2. 2.5 3. ]]
行列積:
[[ 7 10]
[15 22]]
行列積(形状に注意):
[[ 9 12 15]
[19 26 33]]
行列積:
[[ 7 10]
[15 22]]
行列積(形状に注意):
[[ 9 12 15]
[19 26 33]]
numpy配列のインデキシング・スライシング
ここでは、Numpyのインデキシングとスライシングについて解説していきます。
まずは、インデキシングについて解説していきます。
具体的に以下のサンプル配列を使って説明していきます。
# sample
array1 = np.array([[1, 2, 3], [4, 5, 6]])
numpyのインデキシング
インデキシングとは、配列のインデックスを指定して対応する要素を取り出す方法です。
まずは、1次元配列のインデキシングを紹介します。
1次元配列のインデキシング
以下に1次元配列のインデキシングをまとめました。
# 一次元配列のインデキシング
array1 = np.array([1, 2, 3])
# 一番目の配列を取り出す
print(array1[0])
# 最後の配列を取り出す
print(array1[-1])
多次元配列のインデキシング
多次元配列(具体例として2次元)のインデキシングを以下にまとめます。
# 二次元配列のインデキシング
array2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 1行目を取り出す
print(array2[0])
# 最終行を取り出す
print(array2[-1])
# 1行2列目の要素を取り出す
print(array2[0, 1])
numpyのスライシング
『:』を使用して、取り出す要素を指定する方法をスライシングといいます。
具体的には、『a:b
』と指定することで、『a以上b未満の配列』を取り出すことができます。
また、a, bを指定しない場合は、以下がデフォルトで設定されます。
- aを指定しない場合は、先頭の配列がaに設定される
- bを指定しない場合は、最後の配列がbに設定される
少し、難しいので具体例を見て習得しましょう!!
1次元配列のスライシング
まずは、1次元配列のスライシングを紹介します。
# 1次元配列のインデキシング
array3 = np.array([1, 2, 3, 4, 5])
# インデックスが1以上3未満の要素を取り出す
print(array3[1:3])
# インデックスが3未満の要素を取り出す
print(array3[:3])
# インデックスが1以上の要素を取り出す
print(array3[1:])
<output>
[2 3]
[1 2 3]
[2 3 4 5]
多次元配列のスライシング
次に多次元配列(具体例として2次元)のスライシングを紹介します。
# 二次元配列のインデキシング
array4 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 1行目, 2行目を取り出す
print(array4[:2, :])
# 1列目を取り出す
print(array4[:, 0])
# 2列目の1行目と2行目を取り出す
print(array4[:2, 1])
<output>
[[1 2 3]
[4 5 6]]
[1 4 7]
[2 5]
*1列を取り出すと、1次元のndarray配列になることに注意しましょう。
2次元以上の多次元配列でもインデキシングとスライシングの方法は変わりません。
numpyでよく使うメソッド
ここからは、numpyでよく使用する基本的なメソッドを紹介していきます。
- copy : 配列のコピーを作成
- shape : 形状を確認
- reshape : 形状を変換
- dtype : データの型を確認
- astype : データの型を変更
copy : 配列のコピーを作成
例えば、以下のような例を考えます。
x = np.array([1, 2, 3])
y = x
x[0] = 4
print(x, y)
<出力>
[4 2 3] [4 2 3]
このようにy
の値も変更されてしまします。
しかし、状況によってはy
を変更したくない場合があります。
その場合にcopy
を使用します。
x = np.array([1, 2, 3])
# yの値をxの値を変更したときに変更したくないとき
y = x.copy()
x[0] = 4
print(x, y)
<出力>
[4 2 3] [1 2 3]
shape : 形状を確認
shapeで形状を確認することができます。
array1 = np.array([[1, 2, 3],
[4, 5, 6]])
# 配列の確認
array1.shape
<出力>
(2, 3)
こうすることで、2行3列の配列であることが確認できます。
reshape : 形状を変換
reshapeメソッドを用いて、形状を変換することができます。
具体的には、変更したい配列をReshapeの引数で指定してください
array1 = np.array([[1, 2, 3],
[4, 5, 6]])
# 配列の変更(変更したい配列をReshapeの後に指定)
print(array1.reshape(3, 2))
<出力>
array([[1, 2, 3],
[4, 5, 6]])
以下のように、reshapeの引数に-1を入力することで、片方の配列をオートで決定してくれます。
array1 = np.array([[1, 2, 3],
[4, 5, 6]])
# 配列の変更(-1を使用する)
array1.reshape(1, -1)
<出力>
array([[1, 2, 3, 4, 5, 6]])
dtype : データの型を確認
dtypeを利用することで、データの型を確認することができます。
array1 = np.array([[1, 2, 3],
[4, 5, 6]])
# データの型を確認
array1.dtype
<出力>
dtype('int64')
astype : データの型を変更
astypeメソッドを利用することで、データの型を変更することができます。
以下の具体例では、『np.float64』から『np.int32』に変更しています。
<Input>
array1 = np.array([1.0, 1.1, 1.2])
print(f'変更前 : {array1}')
array2 = array1.astype(np.int32)
print(f'変更後 : {array2}')
<output>
変更前 : [1. 1.1 1.2]
変更後 : [1 1 1]
numpyでよく使う関数
numpyでよく使う基本的な関数を紹介していきます。
- where : 条件によって要素を変換
- unique : 重複する要素を削除する
- concatenate : 既存の次元方向に配列を結合
- stack : 新たな軸方向に配列を結合
- expand_dims : 次元を一つ増やす
- squeeze : shapeが1の次元を減らす
詳しく説明していきます。
where : 条件によって要素を変換
whereを利用することで、条件によって要素を変換することができます。
where関数の引数は、(条件, Trueのとき変換する値, Falseのとき変換する値)です。
array1 = np.array([[1, 2, 3],
[4, 5, 6]])
# 条件によって要素を変換
array2 = np.where(array1 > 3, 1, 0)
array2
<出力>
array([[0, 0, 0],
[1, 1, 1]])
unique : 重複する要素を削除する
np.unique
を利用することで、重複する要素を削除することができます。
具体例を以下に示します。
array1 = np.array([1, 1, 2, 3, 3])
np.unique(array1)
<output>
array([1, 2, 3])
concatenate : 既存の次元方向に配列を結合
np.concatenate
を利用することで、既存の軸方向に、配列を結合することができます。
デフォルトでは、行方向の結合(axis=0
)となっています。
具体例を以下に示します。
array1 = np.array([[1, 2, 3], [4, 5, 6]])
array2 = np.array([[7, 8, 9], [10, 11, 12]])
# 行方向に結合(default : axis=0)
print("行方向:\n", np.concatenate([array1, array2]))
# 列方向に結合
print("列方向:\n", np.concatenate([array1, array2], axis=1))
<output>
行方向:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
列方向:
[[ 1 2 3 7 8 9]
[ 4 5 6 10 11 12]]
配列のサイズが合わないと結合ができないことに注意しましょう。
stack : 新たな軸方向に配列を結合
np.stack
を用いることで、新たな軸方向に結合することができます。
デフォルトでは、行方向の結合(axis=0
)となっています。
具体例を以下に示します。
array1 = np.array([1, 2, 3])
array2 = np.array([4, 5, 6])
# 新たな次元で行方向に配列を結合(default : axis=0)
print("行方向:\n", np.stack([array1, array2]))
# 新たな次元で列方向に配列を結合
print("列方向:\n", np.stack([array1, array2], axis=1))
<output>
行方向:
[[1 2 3]
[4 5 6]]
列方向:
[[1 4]
[2 5]
[3 6]]
np.concatenate
の違いを見るための具体例を以下に表示します。
array1 = np.array([1, 2, 3])
array2 = np.array([4, 5, 6])
# concatenate
print("行方向(concatenate):\n", np.concatenate([array1, array2]))
# stack
print("行方向(stack):\n", np.stack([array1, array2]))
print("列方向(stack):\n", np.stack([array1, array2], axis=1))
<output>
行方向(concatenate):
[1 2 3 4 5 6]
行方向(stack):
[[1 2 3]
[4 5 6]]
列方向(stack):
[[1 4]
[2 5]
[3 6]]
expand_dims : 次元を一つ増やす
np.expand_dims
を利用することで、numpy配列の次元を一つ増やすことができます。
axis
という引数を利用することで、追加する次元を指定することができます。
二次元配列の場合は、axis=0
が行方向, axis=1
が列方向に対応します。
具体例を以下に示します。
# 次元を一つ増やす
array1 = np.array([1, 2, 3])
# 次元を一つ増やす
new_array1 = np.expand_dims(array1, axis=0)
new_array2 = np.expand_dims(array1, axis=1)
# 最後の次元を増やす
new_array3 = np.expand_dims(array1, axis=-1)
print(array1.shape)
print(new_array1.shape)
print(new_array2.shape)
print(new_array3.shape)
<output>
(3,)
(1, 3)
(3, 1)
(3, 1)
squeeze : shapeが1の次元を減らす
np.squeeze
を使用すると、shapeが1の次元を減らすことができます。
具体例を以下に示します。
array1 = np.array([[1, 2, 3]])
# shapeが1の部分の次元を減らす
array2 = np.squeeze(array1)
print(array1.shape)
print(array2.shape)
<output>
(1, 3)
(3,)
Q & A |よくある質問
numpyの配列を保存する方法が知りたい
npy
, npz
の形式で保存したり、ロードしたりすることができます。
npy
は、一つのarrayを保管し、npz
は複数の配列を保管します。
保存するためには、一つの配列を保存する場合はnp.save()
関数を使用し、複数の配列を保存する際には、np.savez()
関数を使用します。
また、配列をロードするためには、np.load()
関数を使用します。
具体的な使い方を以下に示します。
# 保存する配列
sample_array = np.array([1, 2, 3])
sample_array_a = np.array([4, 5, 6])
sample_array_b = np.array([7, 8, 9])
# 第一引数にパス, 第二引数に配列を指定
np.save('PATH/sample_array', sample_array)
# 第一引数にパス, 第二引数以降は可変長引数(保存する際にkeyを適当につけることができる, 今回はa, bとした)
np.savez('PATH/sample_array_ab', a=sample_array_a, b=sample_array_b)
# 保存した配列をロード
load_array = np.load('PATH/sample_array.npy')
load_arrays = np.load('PATH/sample_array_ab.npz')
print(load_array)
print(load_arrays['a'])
print(load_arrays['b'])
リストのappend
のようにnumpyでも書きたい
私がよく使用する方法は、np.vstack
を使った方法です。
具体例を以下に示します。
history = np.zeros((0, 2))
for i in range(10):
array = np.random.rand(2)
# appendの代わり
history = np.vstack([history, array])
history
output
array([[0.60276338, 0.54488318],
[0.4236548 , 0.64589411],
[0.43758721, 0.891773 ],
[0.96366276, 0.38344152],
[0.79172504, 0.52889492],
[0.56804456, 0.92559664],
[0.07103606, 0.0871293 ],
[0.0202184 , 0.83261985],
[0.77815675, 0.87001215],
[0.97861834, 0.79915856]])
まとめ
numpyの基本的な使い方を紹介しました。
numpyを利用することで、機械学習や数式のプロットなどいろいろなことができるようになります。
さらに、numpyを利用することで、Pandas、Matplotlibというよう解析ツールも自由に使いこなすことが可能です。
Pythonを学習するのに効率的なサービスを紹介していきます。
まず最初におすすめするのは、Udemyです。
Udemyは、Pythonに特化した授業がたくさんあり、どの授業も良質です。
また、セール中は1500円定義で利用することができ、コスパも最強です。
下記の記事では、実際に私が15個以上の講義を受講して特におすすめだった講義を紹介しています。
他のPythonに特化したオンライン・オフラインスクールも下記の記事でまとめています。
自分の学習スタイルに合わせて最適なものを選びましょう。
また、私がPythonを学ぶ際に使用した本を全て暴露しているので参考にしてください。