NumPyの復習 

# 予備知識

- スカラー　階層が0のテンソルのこと
- ベクトル　階層が1のテンソルのこと
- 行列 階層が2のテンソルのこと

# 生成

## リストから生成する

```
import numpy as np
data1 = [1,2,3]
arr1 = np.array(data1)
data2 = [[1,2,3][1,2,3]]
arr2 = np.array(data2) 
```

## np.zerosシリーズ

```
np.zeros(3)
# int型のn行m列
l_2d = np.zeros((n,m), dtype=int)
#配列aと同じ大きさ
a = np.array([1,6,3][1,5,6])
np.zeros_like(a)
```

# NumPyのデータ形式は「ndarray」
- dim : ndarrayの次元 
    - arr.dim #2
- shape : ndarrayの大きさ 
    - arr.shape #(2,3)
- dtype : データ型 
    - arr.dtype dtype('Int32')

# ndarrayの要素へのアクセス

## 要素の取り出し
```
arr = np.array([1,2,3])
arr[0] #1
arr[1] = 9 #array([1,9,3])

# スライスで取り出す
indices = [[0,1],[2,4]] 
l_2d:[[0, 0, 0], [0, 0, 0]]
for index in indices: 
            l_2d[index[0],:] += 1
            l_2d[:,index[1]] += 1
            print(l_2d)
```

# bool値関係

## bool値を出力する

```
arr = np.array([1,2,3,4,5,6])
out = arr>4 
print(out)
# array([False,False,False,False,True,True])
print(arr[out])
# array([5,6])

l_2d = np.zeros((n,m), dtype=int)
# 奇数の要素がTrueで出力される
print(l_2d % 2 != 0)
```

## 要素のbool値のTrueの数
```
np.count_nonzero(l_2d % 2 != 0)
```

# ndarrayの演算

ndarrayは**すべて要素ごとの計算**になる
行列の積は「@」という演算を使う

```
arr = np.array([1,2,3])
arr * 2 # [2,4,6]
arr + 1 # [2,3,4]
```

## 転置

### 二次元配列の転置をするときは「T属性(arr.T)」または「transpose()」を使う
a_2dとそれを転置して初期化したa_2d_Tは**同じメモリのデータ**である
これは**np.shares_memory()**で確認できる
別々のデータとして処理したいときは「copy()」を使う

```
import numpy as np
a_2d = np.arange(6).reshape(2, 3)
>>> a_2d
# [[0 1 2]
#  [3 4 5]]
a_2d_T = a_2d.T
>>> a_2d_T
# [[0 3]
#  [1 4]
#  [2 5]]
# ===================================== #
a_2d = np.arange(6).reshape(2, 3)
a_2d_T_copy = a_2d.T.copy()
```

### 3次元以上の多次元配列の次元(軸)の入れ替えにも「T属性(arr.T)」または「transpose()」を使う
「T属性(arr.T)」や引数なしの「transpose()」を使うとき次元数は(2,3,4)が(4,3,2)になる
ndarrayのメソッドである**transpose()**では引数に任意の**順番(0番目、1番目、2番目)**を指定できる
npのメソッドである**transpose()**では**第二引数**に任意の**順番(0番目、1番目、2番目)**を指定できる

```
# 下記2つはndarrayのtranspose()
a_3d = np.arange(24).reshape(2, 3, 4)
print(a_3d.T.shape)
# (4, 3, 2)
# ===================================== #
a_3d.transpose(2, 1, 0)
print(a_3d.transpose(2, 1, 0).shape)
# (4, 3, 2)
# ===================================== #
# 下記はnpのtranspose()
print(np.transpose(a_3d, (2, 1, 0)).shape)
# (4, 3, 2)
```

## 行列積
**左の列数(axis=1)と右の行数(axis=0)が一致している必要がある**


### ベクトルの内積を求めるときは「np.dot」を使う
np.dot(a,b,out=None)
(a:左からかける行列, b:右からかける行列, out:結果を代入する配列)

```
# ベクトルの積
import numpy as np
a = np.array([1,2])
b = np.array([4,3])
>>> np.dot(a,b)
# 10 (1*4 + 2*3)
>>> np.dot(a,a)
# 5 (1*1 + 2*2)
```

### 行列の内積を求めるときも「dot」を使う

```
a = np.array([[1,2],[3,4]])
b = np.array([[4,3],[2,1]])
>>> np.dot(a,b)
# array([[8,5],[20,13]])
```

### 逆行列を求めるときは「np.linalg.inv()」を使う
逆行列とは行列Aに対して**A^-1**と表される
そして、AA^-1=I(I:単位行列)になる

```
import numpy as np
a = np.random.randint(-9,10,size=(2,2))
>>> a
# array([[-4,2],[7,2]])
>>> np.linalg.inv(a)
# array([[-0.09090909,  0.09090909], [ 0.31818182,  0.18181818]])
# ===================================== #
b = array([[8,-6,6],[-7,-1,-8],[-7,1,3]])
>>> np.linalg.inv(b)
# array([[-0.00988142, -0.04743083, -0.10671937],
       [-0.15217391, -0.13043478, -0.04347826],
       [ 0.02766798, -0.06719368,  0.09881423]])
```

## そのほかのNumPyモジュール
[参考サイト](https://www.python.ambitious-engineer.com/archives/1283)

### np.diag() (対数要素)
[参考サイト](https://www.sejuku.net/blog/73824)

### ndarray.trace() (トレース(対角行列の和))
```
import numpy as np
a = np.array([[1, 2], [3, 8]]) 
a.trace()
# 9
```
### np.linalg.det() (行列式)
```
import numpy as np
a = np.array([[1, 7], [3, 6]]) 
det_a = np.linalg.det(a)
# 1*6 - 7*3
```