SE_BOKUのまとめノート的ブログ

SE_BOKUが知ってること・勉強したこと・考えたことetc

Numpyの基本構文や関数とかの個人的抜粋/Python文法

f:id:arakan_no_boku:20200325010924p:plain

目次

Numpyの基本構文や関数とかの抜粋/Python文法

Numpyをインポートしていることを前提にしています。

import numpy as np

初期化(Numpy配列の生成)

初期化に関するポイント抜粋です。

型(dtype指定)

Numpy配列は型を指定して生成できます。

データを与えて生成するとデータから適切な型を推定して生成します。

デフォルトはpythonのfloatと互換性のある「float_」型です。

dtype 互換性 コメント
float_ Pythonの「float」 Numpyのデフォルト
uint Pythonの「int」 符号なし
int_ Pythonの「int」 符号あり
bool_ Pythonの「bool」  
int8 8ビット整数 符号あり
int16 16ビット整数 符号あり
int32 32ビット整数 符号あり
int64 64ビット整数 符号あり
uint8 8ビット整数 符号なし
uint16 16ビット整数 符号なし
uint32 32ビット整数 符号なし
uint64 64ビット整数 符号なし
float16 16ビット浮動小数点数  
float32 32ビット浮動小数点数  
float64 64ビット浮動小数点数  

これ以外が必要なら、こちらで。

numpy.org

すべてを0のNumpy配列を生成
np.zeros((2, 2), dtype=np.float32)

結果は

[[0. 0.] [0. 0.]]

すべてを1でNumpy配列を生成
 np.ones((2, 2), dtype=np.float32)   

結果は

[[1. 1.] [1. 1.]]

対角要素に1それ以外に0をセットしたNumpy配列生成
np.eye(3, dtype=np.float32)   

結果は

[

[1. 0. 0.]

[0. 1. 0.]

[0. 0. 1.]

]

指定の値ですべてを埋めて生成
np.full((2, 2), 3.14)

結果は

[[3.14 3.14] [3.14 3.14]]

乱数を使って生成 
説明 結果
np.random.random((2, 2))
一様分布の乱数で初期化 [[0.83874852 0.25393169] [0.48973298 0.63288969]]
np.random.normal(1, 2, (2, 2))
平均1標準偏差2の正規分布 [[ 2.78714269 -1.10804489] [-0.13093131 1.58371071]]
np.random.randint(0, 10, (2, 2))
指定範囲の一様分布の整数 [[0 3] [5 2]]
np.random.rand(2, 2)
0.0以上1.0未満の乱数 [[0.2219319 0.16752553] [0.53437944 0.76555056]]
np.random.randn(2, 2)
平均0分散1の乱数で初期化 [[-2.27146338 -0.00306964] [-1.04215926 1.20743357]]

np.random のバリエーションは沢山あります。

もっと調べたい時はこちら。

numpy.org

等差数列の生成

note.nkmk.me

pythonのlistとNumpy配列の相互変換

pythonのlistからNumpy配列にしたり、戻したりします。

lstbase = [[1, 2, 3], [4, 5, 6]]
# listからNumpy配列
al1 = np.array(lstbase, dtype="float64")

# Numpy配列からlist
lstafter = al1.tolist()

リストに戻す時は、Numpy配列のdtypeと互換性のあるpythonの型になります。

Numpy同士の計算・比較

算術演算

Numpy配列同士の演算の例と計算結果を書いてます。

[[6 3]
[4 6]]


[[2 2]
[2 2]]

以下表の式の例は上の配列が「a」、下の配列を「b」と読み替えて結果を見てもらえるとわかりやすいです。

結果は

[[8 5] [6 8]]

のように行列になります。

算術演算子 説明 式の例
加算 a + b
- 減算 a - b
* 乗算 a * b
/ 除算(結果は少数) a / b
// 整数除算 a // b
** べき条 a ** b
% 余剰(あまり) a % b
比較演算子

演算子だけだとイメージしづらいので、以下のデータを使って例と結果を書きます。

[[6 3 4]
[4 6 3]]


[[-6 3 8]
[-4 6 4]]

演算の結果は

[[False True False] [False True False]]

のような行列になります。

 上を「a」、下を「c」として例と結果を書いています。

算術演算子・関数 説明 式の例
== 等しい a == c
!= 等しくない a != c
< より小さい a < c
<= より小さいか等しい a <= c
> より大きい a > c
>= より大きいか等しい a >= c
np.any 条件に一致するものがひとつでもあればTrue np.any(a == 4)
np.all すべての値が条件に一致すればTrue np.all(a == 4)

Python3.5からはドット積「np.dot(A, B) 」を「A@B」と書ける行列積演算子も追加されました。

ドット積についてのリンクです。

deepage.net

属性確認

Numpy配列の形状やサイズなどの情報

Numpy配列の形状やサイズなどの情報を取り出します。

イメージしづらいので、こんな3行2列の配列の属性を取得する例を書きます。

[[6.32486041 1.82922998]
[1.91987168 0.40812655]
[2.4821602 1.54720082]]

上記配列の名前は「a12」としています。

書き方(配列をarとする) 意味 結果
a12.shape 配列形状のタプル (3, 2)
a12.shape[0] 2次元の場合なら「行」 3
a12.shape[1] 2次元の場合なら「列」 2
a12.ndim 配列の次元数 2
a12.dtype 配列の型 float64
a12.size 配列の合計サイズ 6 : 3×2だから
a12.itemsize 各要素のバイト数 8 (バイト)
a12.nbytes 配列の合計バイト数 48(バイト:size×itemsize)

 のように取得できます。

他にもありますが、それはこちらで。

numpy.org

Numpy配列のndimとaxis

ちなみに

  • ndimは「次元数」
  • axisは「軸」

です。

例えば、以下のような3行4列の配列は2次元配列なので、ndimは「2」です。

axis=0を指定すると列が軸、axis=1を指定すると行が軸です。

f:id:arakan_no_boku:20200327101512p:plain 

ループ

Numpy配列の値をとりだして、forループを回す例です。

こんな感じの3行2列のNumpy配列を使ってやってみます。

[[0.83751433 0.02594981]
[2.8441739 3.17256053]
[0.04499033 2.14228941]]

以下の例で「a12」という名前の変数が上記Numpy配列です。

データだけを取り出してループする
for x in np.nditer(a12):
    print(x)

出力結果はこんな感じでデータだけを順番に取得します。

0.8375143297961567
0.025949813102027264
2.8441738981495615
3.1725605261342964
0.04499033206824665
2.142289407822542

インデックスとデータを取り出してループする

インデックスは、multi_indexで参照できます。

 it = np.nditer(a12, flags=['multi_index'])
for x1 in it:
    print(it.multi_index, ":", x1)  

出力結果はこんな感じになります。 

(0, 0) : 0.8375143297961567
(0, 1) : 0.025949813102027264
(1, 0) : 2.8441738981495615
(1, 1) : 3.1725605261342964
(2, 0) : 0.04499033206824665
(2, 1) : 2.142289407822542

データの取り出し

Numpy配列もPythonのリストと同じように添え字で値を参照します。

上記例で使った配列「a12」をそのまま使うなら。

a12[1,0] 

 とすると

2.8441738981495615

が取得できる感じで。

スライス

同様に、スライスもできて、記述方法とルールも同じです。

anylist[start:end:stride] 

start:指定した添え字を含む、省略すると「0」(つまり添え字の先頭)

end:指定した添え字を含まない。省略すると「最後の要素まで」

stride:カウントアップする幅、省略すると「1」。-1だと逆順になる。

arakan-pgm-ai.hatenablog.com

こういう配列データを使って例(結果列)を書いてます。。

[[2 2 5 5]
[4 3 0 2]
[0 3 2 1]]

 この配列を「a7」という名前で参照してます。

Numpy配列のスライスの例です。

書き方 意味 結果
a7[2:, :] 3行目から取り出し

[

[0 3 2 1]

]

a7[:, :2] 2列目までとりだし [[2 2] [4 3] [0 3]]
a7[::2, ::2] 行列共に1つおきに取り出し [[2 5] [0 2]]
a7[:, ::-1] 列を逆順にソート [[5 5 2 2] [2 0 3 4] [1 2 3 0]]
a7[::-1, :] 行を逆順にソート [[0 3 2 1] [4 3 0 2] [2 2 5 5]]
a7[::-1, ::-1] 行と列を共に逆順にソート [[1 2 3 0] [2 0 3 4] [5 5 2 2]]
a7[:, 1] 2列目をとりだす [2 3 3]
a7[1, :] 2行目をとりだす [4 3 0 2]

ソート

ソート:配列の昇順(axisの指定無し)

スライスの応用の逆順ソートがでてきたので、続けて昇順にソートする方法です。

Numpyの昇順ソートは、np.sort()を使います。

ソート例の元にする配列は「a7」という変数名にします。

内容は以下です。

[[5 4 8 6]
[9 5 6 1]
[2 0 3 0]]

これをソートするのは

 np.sort(a7)

この結果はこうです。

[[4 5 6 8]
[1 5 6 9]
[0 0 2 3]] 

行単位で小さい数値が左から並ぶようにソートされています。

ソート:axis=0を指定

axis=0は列を軸にするイメージでした。
f:id:arakan_no_boku:20200327101512p:plain

 np.sort(a7, axis=0)

この結果はこうです。 

 [[2 0 3 0]
[5 4 6 1]
[9 5 8 6]]

列単位で小さい数値順に上から並び替えられているので、行でみるとシャッフルされたような感じになってます。

ソート:axis=1を指定

axis=1は行を軸にするソートです。 

np.sort(a7, axis=1)

結果はこうです。 

 [[4 5 6 8]
[1 5 6 9]
[0 0 2 3]]

行単位で左から小さい数字がならんでます。

つまり」、無指定の場合と同じです。 

Numpy配列を処理の都合にあわせて形状変更するのはよくあります。

それらの代表的なやり方だけまとめます。 

形状変換

一次元から二次元行列へ

元になるNumpy配列はこんな1次元配列にします。

[1 2 3 4 5 6 7 8 9]

配列の名前は「aj1」としています。

これを「3×3」の二次元行列に変換するのは

aj33 = aj1.reshape((3, 3))
print(aj33)

返還後はこんな感じ

[[1 2 3]
[4 5 6]
[7 8 9]] 

1次元から2次元の行へ

これも頻繁に使います。

[1 2 3 4 5 6 7 8 9]

[

[1 2 3 4 5 6 7 8 9]

にするわけです。

当然ながら、上と同じように「reshape(1, 9)」とやってもできます。

でも、スライスで「np.newaxis」を使った以下のやり方を良く見ます。

元になる1次元配列は「aj1」で参照しています。

ajg2 = aj1[np.newaxis, :]
print(ajg2)

結果はreshape(1,3)とした場合と全く同じです。

[

[1 2 3 4 5 6 7 8 9]

]  

1次元から列ベクトルへ

これは、ようするに。

[1 2 3 4 5 6 7 8 9]

[[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]]

にすることです。

当然ながら「reshape(9, 1)」とやってもできます。

でも、こちらもスライスで「np.newaxis」を使ったパターンをよく見ます。

元になる1次元配列は「aj1」で参照しています。

ajg2 = aj1[:, np.newaxis]
print(ajg2)

結果は「(9,1)でreshape()」した場合と同じです。

多次元から1次元に

ようするに、例えば

[[1 2 3]
[4 5 6]
[7 8 9]] 

 を

[1 2 3 4 5 6 7 8 9]

に戻すことです。

flatten()を使います。

以下に一旦3×3にして、1次元に戻す例をやってます。

元の3×3配列を「aj33」として参照しています。

af = aj33.flatten()
print(af)

flatten()の結果はこんな感じ。 

[1 2 3 4 5 6 7 8 9] 

いけてます。

転置

転置とは、例えば「3×4」の配列を、「4×3」にするみたいに、行と列を入れ替えることです。

具体例でいえば

[[4 4 3 1]
[1 0 6 1]
[8 6 6 6]]

[[4 1 8]
[4 0 6]
[3 6 6]
[1 1 6]] 

にする感じです。

これは、Numpy配列を「a7」とすると

転置後の配列 = a7.T

 とすればいいです。 

連結

垂直(行が下に追加される感じ)で連結

例えば。

[[4 3 5]
[2 5 9]
[0 1 8]]

[[5 2 3]
[4 1 6]
[3 5 5]]

という2つの3×3配列を連結します。

便宜上、上を「g1」、下を「g2」とします。

垂直の連結は、2つやり方があります。

結果はどちらも同じです。

# 方法1
cg1 = np.concatenate([g1, g2])
# 方法2
cg3 = np.vstack([g1, g2])

どちらも結果は以下のように行追加の形になります。 

[[4 3 5]
[2 5 9]
[0 1 8]
[5 2 3]
[4 1 6]
[3 5 5]]

水平(列が後ろに追加される感じ)で連結

こちらも2通りのやり方があり、結果はどちらも同じです。

# 方法1
cg2 = np.concatenate([g1, g2], axis=1)
# 方法2
cg4 = np.hstack([g1, g2])

結果は以下のように列が追加される感じになります。 

[[4 3 5 5 2 3]
[2 5 9 4 1 6]
[0 1 8 3 5 5]] 

連結があれば、分割がある・・ということで。

さきほどの最終結果の

[[8 7 6 4 9 9]
[7 7 1 5 7 5]
[9 4 3 6 0 0]]

を分割してみます。

分割

垂直方向(行単位でわかれていく感じ)に分割

とりあえず3つに分けます。

2つの方法があります。

# 方法1
d1, d2, d3 = np.vsplit(cg2, 3)
# 方法2
ds1, ds2, ds3 = np.split(cg2, 3, axis=0)

どちらも結果は同じです。

注意するのは分割する数にあわせ、左辺の受取側を増やさないといけないところです。

3つを続けて表示すると。

[

[8 7 6 4 9 9]

]

[

[7 7 1 5 7 5]

]
[

[9 4 3 6 0 0]

]

水平方向(列単位でわかれていく感じ)に分割

 これも2つの方法があります。

# 方法1
h1, h2, h3 = np.hsplit(cg2, 3)

# 方法2
hs1, hs2, hs3 = np.split(cg2, 3, axis=1)

結果はこんな感じで列方向に3つにわかれます。

[[8 7]
[7 7]
[9 4]]


[[6 4]
[1 5]
[3 6]]


[[9 9]
[7 5]
[0 0]] 

 左辺の受取側を分割する数にあわせて増やさないといけないのは同じです。

組み込み関数

主に集約や最大値・最小値を取得する関数です。

イメージしやすいように、以下の配列を引数にした結果を表に書いてます。

[[-6 3 8]
[-4 6 4]]

 上記は「d」として表現しています。 

組込み関数(例) 説明 結果
np.absolute(d) 絶対値 [[6 3 8] [4 6 4]]
np.sum(d) 配列全たの合計 11
d.sum(axis=0) 列単位の合計 [-10 9 12]
d.sum(axis=1) 行単位の合計 [5 6]
np.max(d) 配列全体の最大値 8
d.max(axis=0) 列単位の最大値 [-4 6 8]
d.max(axis=1) 行単位の最大値 [8 6]
np.argmax(d) 配列全体の最大値のインデックス 2
d.argmax(axis=0) 行単位の最大値のインデックス [1 1 0]
d.argmax(axis=1) 列単位の最大値のインデックス [2 1]
np.min(d) 配列全体の最小値 -6
d.min(axis=0) 列単位の最大値 [-6 3 4]
d.min(axis=1) 行単位の最大値 [-6 -4]
np.prod(d) 要素の籍を計算 13824
np.mean(d) 要素の平均値を計算 1.83333333333333
np.median(d) 要素の中央値を計算 3.5
np.dot(a, c) ドット積 [[-72 48 92] [-66 57 80] [-66 57 80]]

他にも沢山あります。 

numpy.org

Universal functions(ufunc)は、Numpyの配列(ndarray)に対して、要素ごとに演算等の処理を行い、結果をNumpyの配列(ndarray)で返す関数のことです。

とりあえず、このくらいです。