Pythonを改めてちゃんと学ぶメモ #5

# はじめに
ここは、Pythonを改めて学んでいるメモを都度書き出していきます。
※ 筆者のバックグラウンドは#1をご覧ください。

1. https://qiita.com/hideh_hash_845/items/58241f0ce0283e457a87
1. https://qiita.com/hideh_hash_845/items/56c7a2c5594261f380b2
1. https://qiita.com/hideh_hash_845/items/b5e2264fc650c3e9d4b6
1. https://qiita.com/hideh_hash_845/items/6ebfcbf1682dcc696b76
1. ここ
1. https://qiita.com/hideh_hash_845/items/b46d2d82287f10bfb7c4

# numpy
- 多次元配列における数値計算を効率的に行うことをサポートする数学関数ライブラリ
- Pandasやscikit-learnなど、機械学習でよく使われるライブラリも、NumPyを元に設計されている
- numpyをインポートする時は、慣例として`np`という名前にする

~~~
import numpy as np
~~~

## `array()`と`ndarray`型
- `ndarray`とは*N-dimensional array*のこと。すなわち、N次元配列を扱う型。
- `array()`の引数は[リスト](https://qiita.com/hideh_hash_845/items/56c7a2c5594261f380b2#%E3%83%AA%E3%82%B9%E3%83%88)。`array()`の返り値が`ndarray`型のオブジェクト。
- N次元で、行・列がそれぞれいくつあるかは `shape`**プロパティ**に入っている（メソッドではないので注意）

~~~
import numpy as np
# アレイを作成
a = np.array([1,2,3,4,5,6,7])
b = np.array([[1,2,3,4], [5,6,7,8]])
print(type(a))
print(a.shape)
print(a)
print(type(b))
print(b.shape)
print(b)
~~~

## `arange()`, `ones()`, `zeros()`
- `arange()`は、基本的には`range()`関数と同じ
- `ones()`は引数で指定された形の配列をすべて1で埋める
- 'zeros()'は引数で指定された形の配列をすべて0で埋める
- 「すべて10で埋められた配列」は最初に`ones()`か`zeros()`を作って全部に同じ数を足す操作で簡単に作れる

~~~
c = np.arange(10)
# この場合、dの各要素は`float`になっているので注意
d = np.ones(10)
# 要素をintにしたければ、`dtype`を指定
e = np.zeros((2,5), dtype='int64')
# すべて10で埋める=ゼロで作って、10を足す
f = e + 10
~~~

## アレイの四則演算、累乗
- 「普通に」計算すればOK
- 代入演算子も使える
- 要素の型不一致だとエラーになるので注意（`int`と`float`など）

~~~
# すべての要素に5が足し算される
c = c + 5
print(c)

c -= 5
print(c)

#c -= d
# `int`と`float`の型不一致でエラー
d = np.ones((10), dtype='int64')
c -= d
print(c)

c *= c
print(c)

g = np.array([7,8,7,8,7,8,7,8,7,8])
h = c / g
print(h)
h **= 3
print(h)
~~~

## 要素の抽出
- スライスを使う
- 要素が一つならそのままプリミティブな型のように扱える（※ 正確には`numpy`のオブジェクト） 

~~~
# 1次元の場合
arr1 = np.arange(10) + 1
print(arr1)
i = arr1[5]
print(type(i)) # <class 'numpy.int32'>
# arrayで取れる
j = arr1[2:9]
print(type(j)) # <class 'numpy.ndarray'>

# N次元の場合も同様
arr2 = np.array([[1,2,3], [4,5,6], [7,8,9]])
k = arr2[1][2]
l = arr2[1, 2]
# arrayで取れる
m = arr2[2]
~~~

## 様々な演算子・関数
- xの平方根 `sqrt(x)`
- y=e^xを計算 `exp(x)`
- 乱数の生成 `random`
  - `numpy.random.rand()`: 一様分布（0以上1未満）
  - `numpy.random.randn()`: 標準正規分布（平均0、分散1（標準偏差1））
  - `numpy.random.randint()`: 一様分布（任意の範囲の整数）
- 要素ごとの符号（正は1、負は-1） `sign()`
- 平均 `mean()`
- 標準偏差 `std()`

## サンプルコード

~~~python:numpy_test.py
#!/usr/bin/env python
# coding: utf-8
import numpy as np
# アレイを作成
a = np.array([1,2,3,4,5,6,7])
b = np.array([[1,2,3,4], [5,6,7,8]])
print(a.shape)
print(a)
print(b.shape)
print(b)

# arange
#- 基本的には、pythonのrange関数と同じ
c = np.arange(10)

# ones
# 引数で指定された形の配列をすべて1で埋める
# この場合 `float`になっているので注意
d = np.ones(10)

# zeros
# 引数で指定された形の配列をすべて0で埋める
e = np.zeros((2,5), dtype='int64')
# 「すべて10で埋める」は最初に`ones`か`zeros`を作って全部に同じ数を足すで簡単に作れる
f = e + 10
print(c.shape)
print(c)
print(d.shape)
print(d)
print(e.shape)
print(e)
print(f.shape)
print(f)

# アレイの四則演算、累乗
# 「普通に」計算すればOK
# すべての要素に5が足し算される
c = c + 5
print(c)
# 代入演算子でもOK
c -= 5
print(c)
#c -= d
# `int`と`float`の型不一致でエラー
d = np.ones((10), dtype='int64')
c -= d
print(c)
c *= c
print(c)
g = np.array([7,8,7,8,7,8,7,8,7,8])
h = c / g
print(h)
h **= 3
print(h)
print('-----')

# 要素の抽出
# 1次元の場合
arr1 = np.arange(10) + 1
print(arr1)
i = arr1[5]
print(i)
# arrayで取れる
j = arr1[2:9]
print(j)
# N次元の場合も同様
arr2 = np.array([[1,2,3], [4,5,6], [7,8,9]])
k = arr2[1][2]
print(k)
l = arr2[1, 2]
print(l)
# arrayで取れる
m = arr2[2]
print(m)

# 様々な演算子・関数
# 平方根の計算
n = np.sqrt(arr1)
print(n)
# 自然対数の底eの累乗
o = np.exp(arr1)
print(o)
# 標準正規分布に従う乱数を生成
# 一様分布の生成には
p1 = np.random.rand(10)
p2 = np.random.randn(10)
p3 = np.random.randint(4,10,10)
print(p1)
print(p2)
print(p3)
# ランダムなどで毎回異なる
# 要素ごとの符号を返す（正は1、負は-1）
q = np.sign(p2)
print(q)
# 平均
r = p2.mean()
print(r)
# 標準偏差を出力
s = p2.std()
print(s)
~~~