Numpy覚書

# ライブラリのインポート
```
import numpy as np
```

# 配列 NdArray
数値処理系の作業と相性が良く、非常に良く利用される。

## 生成方法 np.array()関数
`NdArray`のコンストラクタ `__init__(self, ...)`を使うこともできるが、通常は`np.array()`を使うことが多い。

入力値 list：リスト型
出力値 a: ndarray型

```
list = [[1,2][3,4]]
a = np.array(list)
```

## np.zeros(shape), np.ones(shape), np.eye(N)

- np.zeros(shape): 要素全てが０の配列を生成。
- np.ones(shape): 要素全てが1の配列を生成。
- np.eye(N): N*Nの単位行列を生成。

`.astype('float32')`などで、要素の型を指定しないとうまく行かないことがあるので、要注意。

```
# 重み (入力の次元数: 2, 出力の次元数: 1)
W_or = np.random.uniform(low=-0.08, high=0.08, size=(2, 1)).astype('float32')
b_or = np.zeros(shape=(1,)).astype('float32')
```

## 要素数取得
```
list = [[1,2,3],[4,5,6]]
a = np.array(list)
print(a.size) # 全要素数：6 = 2 * 3
print(a.shape) # 形状（行数、列数）をTaple型で表示：(2,3)
print(a.shape[0]) # タプル型の第０要素：2
```

# 乱数

## 乱数のseedを固定
結果の再現性のため。
seedを固定しないと、例えば、notebook上で2回同じ計算を回すと、異なる結果を得ることになる。
理由は不明だが、seed=42がMagic numberとか書かれていたりする。

```
np.random.seed(34)
```

## 乱数生成

```
# Uniform (一様乱数)
u = np.random.uniform(low=-0.08, high=0.08, size=(2, 1)).astype('float32')

# Gauss (ガウス（正規）乱数)
z = np.random.normal(loc=-0.1, scale=2.0, size(2, 1)).astype('float32')
```

# 関数

## Log関数
底はeのlog関数。logの中身が0になるのを防ぐため、np.clipを利用する。

```math
nplog(x)=\ln(\max(x,10^{-10}))
```

```
def np_log(x):
    return np.log(np.clip(a=x, a_min=1e-10, a_max=x))
```

## Sigmoid関数
2クラス分類で使われる。

```math
\sigma(x)=\frac{1}{1+\exp(-x)}
```
ここでは、expのオーバーフローを防ぐため、numpy組み込みのtanhを利用する（tanhのオーバーフロー処理に関して、詳細は未調査）。

```
def sigmoid(x):
    return np.tanh(x * 0.5) * 0.5 + 0.5
```

## Softmax関数
多クラス分類で使われる。

```math
\mathrm{softmax}(x)_k = \frac{\exp(x_k)}{\sum^K_{k'=1} \exp(x_{k'})} = \frac{\exp(x_k-\max_{k'=1}^{K}(x_k'))}{\sum^K_{k'=1} \exp(x_{k'}-\max_{k'=1}^{K}(x_k'))} \hspace{10mm} \text{for} \, k=1,\ldots, K
```

sigmoid関数と同様、exp関数のオーバーフローとアンダーフローを防ぐように実装。

```
def softmax(x):
    x -= x.max(axis=1, keepdims=True) # expのunderflow & overflowを防ぐ
    x_exp = np.exp(x)
    return x_exp / np.sum(x_exp, axis=1, keepdims=True)

# 以下、使い方一例
l = [[0.4,0.3,0.6],[0.5,0.1,0.4],[0.8,0.1,0.1],[0.2,0.2,0,6]] # shape: (batch_size=4, nclass=3)
x = np.array(l)
y = softmax(x)
```
<!--
#Broadcast
【工事中】

1. ndarrayの最後の次元の後に、新たに1次元増やしたい場合
2. 増やした次元のサイズを変更したい場合
-->

#演算

##`np.max`

- `axis`: 最大値を計算する方向（次元）を決める。
- `keepdims=True/False`：Trueにすると、最大値を取る前と、次元を同じに保つ。

```
list = [[1,2],[4,3],[2,2]]
x = np.array(list)
max_true = x.max(axis=1, keepdims=True) # np.array([[2],[4],[2]])
max_false = x.max(axis=1, keepdims=False) # np.array([2,4,2])
```

##Positive/Negative Part

```
A = np.array([[-1, 2, -3], [4, -5, 6], [-7, 8, -9]])
B = np.where(A > 0, A, 0)
C = np.where(A < 0, A, 0)
```
<!--
3. 複数の軸方向に一気にmaxを取る方法
【工事中】

4. `mean()`
【工事中】
-->

#行列演算
## 転置
```
x = np.array([[1,2,3],[4,5,6]]) # shape: (2,3)
xt = x.T # np.array([[1,4],[2,5],[3,6]]), shape: (3,2)
```

## 行列積
```
b = np.array([[1,1,1],[1,1,1]]) # (2,3)
c = np.array([[1,1],[1,1],[1,1]]) # (3,2)

#　以下3つは、全て同じ結果を生む。
# a = b * c = np.array([[3,3],[3,3]])
a = np.matmul(b, c)
a = np.dot(b, c)
a = b.dot(c)
```

## 行列要素の抽出
分類問題で、整数値の答え（例：0,1,...,9の10クラス分類）をOne-hotベクトル表現に変換したい。以下で簡単にできる。

```
tgt_class = [1,9,0,5,8] # batch_size=5のケースで、10クラス分類の答えの配列
x = np.eye(N=10)[tgt_class]

# [[0,1,0,0,0,0,0,0,0,0],
#  [0,0,0,0,0,0,0,0,0,1],
#  [1,0,0,0,0,0,0,0,0,0],
#  [0,0,0,0,0,1,0,0,0,0],
#  [0,0,0,0,0,0,0,0,1,0]]
```

<!--
# データの読み書き
## データの読み込み np.load()
# 図関連
## matplotpyplot
-->