Python - Numpy、配列・行列の演算と処理

Odyssey CBTのPython3 エンジニア認定データ分析試験の学習を始めました。今回Numpyを使った行列(ndarray型)の演算について学びました。

# 1次元配列の基礎
まずは簡単な一次元配列＝ベクトルを作って基礎機能を確認します。
Numpyにおいては配列を`numpy.array`型で表します。Numpyのメソッドを使えば、配列のデータ型や次元数・形状を検証することができます。

```python
# 1次元配列
import numpy as np

a = np.array([1,2,3])
print(a)

# type - オブジェクトのデータ型を確認
print(type(a))
# ndim - オブジェクトの次元数を確認
print(a.ndim)
# shape - aの形状を確認する
print(a.shape)
```

```python
[1 2 3]
<class 'numpy.ndarray'>
1
(3,)
```
# 2次元配列の基礎
Numpyでは2次元配列＝行列を作成することができます。
用途に応じで3次元、4次元、...といった多次元配列を活用できます。

```python
b = np.array([[1,2,3],[4,5,6]])
print(b)
print(type(b))
print(b.shape)
```
```python
[[1 2 3]
 [4 5 6]]
<class 'numpy.ndarray'>
(2, 3)
```

# reshape, revel, flatten - 形状の変換
`reshape`は１次元配列→2次元配列に形状を変換、
`ravel`と`flatten`は逆に2次元配列→1次元配列に形状を変換することができます。
```python
## reshape: １次元配列→2次元配列に形状を変換
c1 = np.array([0,1,2,3,4,5])
print(c1)
c2 = c1.reshape((2,3))
print(c2)
```
```python
[0 1 2 3 4 5]
[[0 1 2]
 [3 4 5]]
```

```python
## ravel: 2次元配列→1次元配列に形状を変換
c3 = c2.ravel()
print(c3)
```
```python
[0 1 2 3 4 5]
```

```python
## flatten:１次元配列→2次元配列に形状を変換(※参照はせずにコピーを返す)
c4 = c2.flatten()
print(c4)
```
```python
[0 1 2 3 4 5]
```

# インデックスとスライス
`numpy.array`型の値を参照するには、インデックスで1つの値・スライスで複数の値を取得できます。
```python
# 1次元配列のインデックス・スライス
a = np.array([1,2,3])

print(a[0])
print(a[1:])
print(a[-1])
```
```python
1
[2 3]
3
```

```python
## 2次元配列のインデックス・スライス
b = np.array([[1,2,3],[4,5,6]])

print(b[0])
print(b[1,0])
print(b[1:])
print(b[-1])

print(b[:, 2])
print(b[0, 1:])
print(b[:, [0,2]])
```
```python
[1 2 3]
4
[[4 5 6]]
[4 5 6]
[3 6]
[2 3]
[[1 3]
 [4 6]]
add Code
```

# arange - 数列の作成
数列の作成には`arange`を活用します。0~(n-1)までの数列を作成することができます。

```python
# arange - 0~(n-1)までの数列を作成する
array = np.arange(10)
print(array)

# 第二引数までの前の整数がリストに加えられる
array = np.arange(1,101)
print(array)

# 第三引数 - 数列の差を指定して生成する
array = np.arange(1,101, 2)
print(array)
```
```python
[0 1 2 3 4 5 6 7 8 9]
[  1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
  91  92  93  94  95  96  97  98  99 100]
[ 1  3  5  7  9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47
 49 51 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95
 97 99]
```

# randon - 乱数の作成
乱数の発生には`random.default_rng`関数とそのメソッドを使用します。
シードの固定などができる他、一様乱数・正規乱数など種別を指定できます。

```python
# randon - ndarray型の乱数を作成する
# 3行2列の配列の中身を乱数で生成する
mg = np.random.default_rng()
f = mg.random((3,2))
print(f)

# シード - 乱数の発生に使うパターンを指定する。同じ乱数を検証時に利用したい時に活用する
# random.default_rng()のシードを固定すると毎回同じ乱数が出力される
mg = np.random.default_rng(123)
f = mg.random((3,2))
print(f)
```
```python
[[0.68216776 0.71435117]
 [0.29769839 0.82520329]
 [0.39418732 0.73010971]]
[[0.68235186 0.05382102]
 [0.22035987 0.18437181]
 [0.1759059  0.81209451]]
```
```python
# random.default_rng - 整数の乱数を生成する
mg = np.random.default_rng(123)

# for・rangeで乱数をappendするのを100回繰り返す
random_list = []
for i in range(1,101):
    f = mg.integers(1,100)
    random_list.append(f)

print(random_list)

# ndarray型の要素を乱数にする
array = mg.integers(1,10, size=(3,3))
print(array)
```
```python
[2, 68, 59, 6, 90, 22, 26, 19, 34, 18, 35, 81, 45, 92, 45, 28, 79, 82, 86, 89, 3, 51, 27, 25, 24, 82, 79, 22, 41, 74, 15, 63, 44, 92, 74, 23, 83, 80, 22, 52, 79, 23, 25, 17, 1, 50, 2, 58, 42, 19, 36, 2, 15, 47, 8, 73, 26, 91, 17, 62, 52, 91, 62, 86, 46, 22, 19, 86, 21, 73, 53, 28, 41, 79, 45, 86, 94, 30, 53, 53, 54, 8, 37, 58, 91, 24, 64, 76, 92, 18, 67, 31, 44, 2, 72, 4, 38, 50, 67, 47]
[[8 2 3]
 [3 4 1]
 [4 4 6]]
```
```python
# random.default_rng.uniform - 連続値の乱数を指定範囲で生成する(デフォルトは一様乱数)
mg = np.random.default_rng(123)
random01 = mg.uniform(0.0, 0.5, size=(3,3))
print(random01)

# random.default_rng.standard_normal - 標準正規分布に従う乱数を出力
mg = np.random.default_rng(123)
random02 = mg.standard_normal(size=(3,3))
print(random02)

# random.default_rng.normal - 正規分布に従う乱数を出力(平均・標準偏差を指定)
mg = np.random.default_rng(123)
random03 = mg.normal(50,10, size=(5,5))
print(random03)
```
```python
[[0.34117593 0.02691051 0.11017994]
 [0.09218591 0.08795295 0.40604725]
 [0.4616725  0.1382872  0.40987728]]
[[-0.98912135 -0.36778665  1.28792526]
 [ 0.19397442  0.9202309   0.57710379]
 [-0.63646365  0.54195222 -0.31659545]]
[[40.1087865  46.32213349 62.87925261 51.93974419 59.202309  ]
 [55.77103791 43.63536354 55.4195222  46.83404549 46.77610884]
 [50.97167319 34.74069593 61.92166104 43.28910325 60.0026942 ]
 [51.36321124 65.3203308  43.40030586 46.88205144 53.37769127]
 [27.92528902 58.27921442 65.41630395 61.26806793 57.54769644]]
```
# zeros, ones, eye, full - 多次元配列の生成
```python
# ones - 要素が全て0の配列を作成
array = np.ones(3)
print(array)

array = np.ones((3,3))
print(array)
```
```python
0. 0. 0.]
[[0. 0. 0.]
 [0. 0. 0.]]
```

```python
# ones - 要素が全て0の配列を作成
array = np.ones(3)
print(array)

array = np.ones((3,3))
print(array)
```
```python
[1. 1. 1.]
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
```

```python
# eye - 行・列がn個の単位行列を生成
array = np.eye(10)
print(array)
```
```python
[[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]]
```

```python
# full - 指定値で配列を埋め合わせる
array = np.full((5,5), np.pi)
print(array)
```
```python
[[3.14159265 3.14159265 3.14159265 3.14159265 3.14159265]
 [3.14159265 3.14159265 3.14159265 3.14159265 3.14159265]
 [3.14159265 3.14159265 3.14159265 3.14159265 3.14159265]
 [3.14159265 3.14159265 3.14159265 3.14159265 3.14159265]
 [3.14159265 3.14159265 3.14159265 3.14159265 3.14159265]]
```
# linspace,diff - 配列の均等割り
```python
# linspace - 0-1までの値を(n-1)個に分割する
lins = np.linspace(0,1,51)
print(lins)
# 円周率などの無理数も分割できる
lins = np.linspace(0,np.pi,51)
print(lins)
```
```python
[0.   0.02 0.04 0.06 0.08 0.1  0.12 0.14 0.16 0.18 0.2  0.22 0.24 0.26
 0.28 0.3  0.32 0.34 0.36 0.38 0.4  0.42 0.44 0.46 0.48 0.5  0.52 0.54
 0.56 0.58 0.6  0.62 0.64 0.66 0.68 0.7  0.72 0.74 0.76 0.78 0.8  0.82
 0.84 0.86 0.88 0.9  0.92 0.94 0.96 0.98 1.  ]
[0.         0.06283185 0.12566371 0.18849556 0.25132741 0.31415927
 0.37699112 0.43982297 0.50265482 0.56548668 0.62831853 0.69115038
 0.75398224 0.81681409 0.87964594 0.9424778  1.00530965 1.0681415
 1.13097336 1.19380521 1.25663706 1.31946891 1.38230077 1.44513262
 1.50796447 1.57079633 1.63362818 1.69646003 1.75929189 1.82212374
 1.88495559 1.94778745 2.0106193  2.07345115 2.136283   2.19911486
 2.26194671 2.32477856 2.38761042 2.45044227 2.51327412 2.57610598
 2.63893783 2.70176968 2.76460154 2.82743339 2.89026524 2.95309709
 3.01592895 3.0787608  3.14159265]
```

```python
# diff - 要素間の差分を返す(長さが1つ減る)
array = np.array([2,2,6,1,3])
diffs = np.diff(array)
print(diffs)
```
```python
[ 0  4 -5  2]
```
# concatenate, hstack, vstack, hsplit, vsplit- 連結、分割

```python
# concatenate - 配列を連結する
lins01 = np.linspace(1,50,50)
lins02 = np.linspace(51,100,50)
print(lins01)
print(lins02)

lins_all = np.concatenate([lins01, lins02])
print(lins_all)

# hstack - 列方向に結合する。1次元配列同士の場合は列数が増えた1次元配列となる
lins_all = np.hstack([lins01, lins02])
print(lins_all)

# vstack - 行方向に結合する。1次元配列同士の場合は行数が2となり2次元配列となる
lins_all = np.vstack([lins01, lins02])
print(lins_all)
```
```python
[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36.
 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50.]
[ 51.  52.  53.  54.  55.  56.  57.  58.  59.  60.  61.  62.  63.  64.
  65.  66.  67.  68.  69.  70.  71.  72.  73.  74.  75.  76.  77.  78.
  79.  80.  81.  82.  83.  84.  85.  86.  87.  88.  89.  90.  91.  92.
  93.  94.  95.  96.  97.  98.  99. 100.]
[  1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.  12.  13.  14.
  15.  16.  17.  18.  19.  20.  21.  22.  23.  24.  25.  26.  27.  28.
  29.  30.  31.  32.  33.  34.  35.  36.  37.  38.  39.  40.  41.  42.
  43.  44.  45.  46.  47.  48.  49.  50.  51.  52.  53.  54.  55.  56.
  57.  58.  59.  60.  61.  62.  63.  64.  65.  66.  67.  68.  69.  70.
  71.  72.  73.  74.  75.  76.  77.  78.  79.  80.  81.  82.  83.  84.
  85.  86.  87.  88.  89.  90.  91.  92.  93.  94.  95.  96.  97.  98.
  99. 100.]
[  1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.  12.  13.  14.
  15.  16.  17.  18.  19.  20.  21.  22.  23.  24.  25.  26.  27.  28.
  29.  30.  31.  32.  33.  34.  35.  36.  37.  38.  39.  40.  41.  42.
  43.  44.  45.  46.  47.  48.  49.  50.  51.  52.  53.  54.  55.  56.
  57.  58.  59.  60.  61.  62.  63.  64.  65.  66.  67.  68.  69.  70.
  71.  72.  73.  74.  75.  76.  77.  78.  79.  80.  81.  82.  83.  84.
  85.  86.  87.  88.  89.  90.  91.  92.  93.  94.  95.  96.  97.  98.
  99. 100.]
[[  1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.  12.  13.  14.
   15.  16.  17.  18.  19.  20.  21.  22.  23.  24.  25.  26.  27.  28.
   29.  30.  31.  32.  33.  34.  35.  36.  37.  38.  39.  40.  41.  42.
   43.  44.  45.  46.  47.  48.  49.  50.]
 [ 51.  52.  53.  54.  55.  56.  57.  58.  59.  60.  61.  62.  63.  64.
   65.  66.  67.  68.  69.  70.  71.  72.  73.  74.  75.  76.  77.  78.
   79.  80.  81.  82.  83.  84.  85.  86.  87.  88.  89.  90.  91.  92.
   93.  94.  95.  96.  97.  98.  99. 100.]]
```
```python
# hsplit - 2次元配列を列数で分割する
first, second = np.hsplit(lins_all, [25])
print(first)
print(second)
```
```python
print(second)
[[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
  19. 20. 21. 22. 23. 24. 25.]
 [51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68.
  69. 70. 71. 72. 73. 74. 75.]]
```
```python
# vsplit - 2次元配列を行数で分割する
first, second = np.vsplit(lins_all, [1])
print(first)
print(second)
```
```python
[[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
  19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36.
  37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50.]]
[[ 51.  52.  53.  54.  55.  56.  57.  58.  59.  60.  61.  62.  63.  64.
   65.  66.  67.  68.  69.  70.  71.  72.  73.  74.  75.  76.  77.  78.
   79.  80.  81.  82.  83.  84.  85.  86.  87.  88.  89.  90.  91.  92.
   93.  94.  95.  96.  97.  98.  99. 100.]]
```
次回はPandasについて学習します。これで40%ほどが学習できました。