【Python】蛇使いへの道 (4) Numpyを手なずける

Pythonを使ったデータサイエンティストになるための修行です。
ついにNumpyを使っていきます。
Numpyは大規模な多次元配列や行列を操作したりするためのライブラリです。
これなくしてはPythonでデータを解析できません。

**PREV** →[【Python】蛇使いへの道 (3) Pythonのクラス](http://qiita.com/Morinikki/items/73d45aa065eaef6c22d6)
**NEXT** →[【Python】蛇使いへの道 (5) Matplotlibと戯れる](http://qiita.com/Morinikki/items/f44cdc6d50c536b8fc9e)

# 配列の生成

まずはnumpyをインポートします。

```python
>>> import numpy as np
```

1次元、2次元、3次元のarrayを生成。


```python
>>> a1 = np.array([1, 2, 3], int)
>>> a2 = np.array([[1, 2, 3], [4, 5, 6]])
>>> a3 = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
```

data型(dtype)と形状(shape)を調べる。


```python
>>> a2.dtype, a1.shape, a2.shape, a3.shape
    (dtype('int64'), (3,), (2, 3), (2, 2, 3))
```



     


    



arrayを型変換する。


```python
>>> a1.astype(float), a1.astype(complex)
    (array([ 1.,  2.,  3.]), array([ 1.+0.j,  2.+0.j,  3.+0.j]))
```



    


    


all 0のarrayを生成。


```python
>>> np.zeros((2, 3), int)
    array([[0, 0, 0],
           [0, 0, 0]])
```




    


all 1のarrayを生成。

```python
>>> np.ones((2, 3),int)
    array([[1, 1, 1],
           [1, 1, 1]])
```




    




3x3単位行列を生成。

```python
>>> np.identity(3, int)
    array([[1, 0, 0],
           [0, 1, 0],
           [0, 0, 1]])
```







対角成分から対角行列を生成。

```python
>>> a5 = np.diag([1, 2, 3]); a5
    array([[1, 0, 0],
           [0, 2, 0],
           [0, 0, 3]])
```






正方行列から対角成分を取り出す。

```python
>>> np.diag(a5)
    array([1, 2, 3])
```








# 形状変化

shape=(2,3)のarrayを生成する。

```python
>>> a1 = np.array([[1, 2, 3], [4, 5, 6]]); a1
    array([[1, 2, 3],
           [4, 5, 6]])
```

shape=(6,)の一次元形状に変更。

```python
>>> a1.reshape(6,)
    array([1, 2, 3, 4, 5, 6])
```







shape=(3,2)の2次元形状に変更。

```python
>>> a1.reshape(3, 2)
    array([[1, 2],
           [3, 4],
           [5, 6]])
```








# 部分配列

## slice

sliceとは等差数列型index listのことであり、これを[...]に与えて部分配列を取得する。

```python
>>> a1 = np.array(range(1, 10)).reshape(3, 3); a1
    array([[1, 2, 3],
           [4, 5, 6],
           [7, 8, 9]])
```



1以上3未満の行番号、 1以上3未満の列番号を取り出す。




```python
>>> a1[1:3, 1:3]
    array([[5, 6],
           [8, 9]])
```


sliceの第3parameterを負の値にすると逆順を意味します。


```python
>>> a1[::-1, ::-1]
    array([[9, 8, 7],
           [6, 5, 4],
           [3, 2, 1]])
```



このようにslice objectを利用することもできます。





```python
>>> slice1 = slice(0, 3, 2) # 0:3:2
>>> a1[slice1, slice1]
    array([[1, 3],
           [7, 9]])
```








## fancy indexing

fancy indexingとは任意のindex列を[...]に与えて部分配列を取得する方式です。

第0行と第2行と取り出す。

```python
>>> a1[[0, 2], :]
    array([[1, 2, 3],
           [7, 8, 9]])
```




第0列と第2列と取り出す。




```python
>>> a1[:, [0, 2]]
    array([[1, 3],
           [4, 6],
           [7, 9]])
```


両軸でfancy indexing。
[0,0]成分と[2,2]成分を取り出す。




```python
>>> a1[[0, 2], [0, 2]]
    array([1, 9])
```



上の結果は1D arrayであり、以下とは別物なので注意が必要です。





```python
>>> a1[[0, 2], :][:, [0, 2]]
    array([[1, 3],
           [7, 9]])
```







fancy indexingはこのようにデータの並べ替え(permutation)の目的でも使用できます。

```python
>>> a1[[2, 0, 1], :]
    array([[7, 8, 9],
           [1, 2, 3],
           [4, 5, 6]])
```








## boolean indexing

boolean indexingとはboolean arrayを[...]に与えてTrueのindexだけの部分配列を取得する方式です。

値が偶数の場合のみTrueとなるboolean arrayを作成。

```python
>>> a1=np.array(range(1,10)).reshape(3,3); a1
    array([[1, 2, 3],
           [4, 5, 6],
           [7, 8, 9]])

>>> a2 = (a1 % 2 == 0); a2
    array([[False,  True, False],
           [ True, False,  True],
           [False,  True, False]], dtype=bool)
```






indexがTrueに対応する成分だけを1D arrayとして取り出す。


```python
>>> a1[a2]
    array([2, 4, 6, 8])
```


## 部分配列の一般規則
Numpyの部分配列は、indexがsliceの場合は参照です。
その他の場合(fancy index等)は コピーです。
`a1[[0, 2], :]`のようにsliceとfancy indexingが 混在している場合もコピーとなります。




# 配列の結合

まず、2x2の2次元配列を2つ用意します。

```python
>>> a1 = np.array(range(1, 5)).reshape(2, 2); a1
    array([[1, 2],
           [3, 4]])

>>> a2 = np.array(range(5, 9)).reshape(2, 2); a2
    array([[5, 6],
           [7, 8]])
```

行方向に結合する。(行方向:第0軸)
shape=(4,2)となる。


```python
>>> np.vstack((a1,a2)) # np.concatenate((a1,a2),axis=0) を使っても同じ
    array([[1, 2],
           [3, 4],
           [5, 6],
           [7, 8]])

```



列方向に結合する。(列方向:第1軸)
shape=(2,4)となる。



```python
>>> np.hstack((a1,a2))  #  np.concatenate((a1,a2),axis=1) を使っても同じ
    array([[1, 2, 5, 6],
           [3, 4, 7, 8]])
```








# 軸の入れ替え

shape=(2,3)の2次元arrayを用意します。

```python
>>> a1 = np.array(range(2 * 3)).reshape(2, 3); a1
    array([[0, 1, 2],
           [3, 4, 5]])
```




転置(第0軸(行)と第1軸(列)の入れ替え)する。

```math
B_{ji} = A_{ij}
```



```python
>>> a1.T
    array([[0, 3],
           [1, 4],
           [2, 5]])
```

shape=(2,3,4,5)の4次元arrayを用意します。


```python
>>> a2 = np.array(range(2 * 3 * 4 * 5)).reshape(2, 3, 4, 5)
>>> a2.shape
    (2, 3, 4, 5)
```


第1軸と第3軸を入れ替える。

```math
B_{ilkj} = A_{ijkl}
```



```python
>>> a2.swapaxes(1, 3).shape
    (2, 5, 4, 3)
```





第1,2,3,0軸を新しい第0,1,2,3軸とする。

```math
B_{jkli} = A_{ijkl}
```



```python
>>> a3=a2.transpose(1, 2, 3, 0)
```

einsumを使うと同じ処理を視覚的に分かり易く表現できます。

```python
>>> a4=np.einsum('ijkl->jkli', a2)
>>> a3.shape, a4.shape, (a3 == a4).all()
    ((3, 4, 5, 2), (3, 4, 5, 2), True)
```




    



# outerとkron

次のような行列を用意する。

```math
A =
\left(
\begin{matrix}
1 & 2 \\
3 & 4 
\end{matrix}
\right)
　　
I =
\left(
\begin{matrix}
1 & 0 \\
0 & 1 
\end{matrix}
\right)
```


```python
>>> A = np.array([[1, 2], [3, 4]]); A
    array([[1, 2],
           [3, 4]])

>>> I = np.identity(2); I  # 2x2単位行列
    array([[ 1.,  0.],
           [ 0.,  1.]])
```


I,Aを1次元化して、2つのvectorのtensor積を計算する。

```math
C =
\left(
\begin{matrix}
1\\
0\\
0\\
1 
\end{matrix}
\right)
⊗
\left(
\begin{matrix}
1\\
2\\
3\\
4 
\end{matrix}
\right)
=
\left(
\begin{matrix}
1&2&3&4\\
0&0&0&0\\
0&0&0&0\\
1&2&3&4 
\end{matrix}
\right)
```
　　


```python
>>> C = np.outer(I, A); C
    array([[ 1.,  2.,  3.,  4.],
           [ 0.,  0.,  0.,  0.],
           [ 0.,  0.,  0.,  0.],
           [ 1.,  2.,  3.,  4.]])
```




Kroneckerのtensor積(いわゆる演算子としてのtensor積)を計算する。

```math
D =
\left(
\begin{matrix}
1&0\\
0&1 
\end{matrix}
\right)
⊗
\left(
\begin{matrix}
1&2\\
3&4 
\end{matrix}
\right)
=
\left(
\begin{matrix}
1&2&0&0\\
3&4&0&0\\
0&0&1&2\\
0&0&3&4 
\end{matrix}
\right)
```



```python
>>> D = np.kron(I, A); D
    array([[ 1.,  2.,  0.,  0.],
           [ 3.,  4.,  0.,  0.],
           [ 0.,  0.,  1.,  2.],
           [ 0.,  0.,  3.,  4.]])
```

**NEXT** →[【Python】蛇使いへの道 (5) Matplotlibと戯れる](http://qiita.com/Morinikki/items/f44cdc6d50c536b8fc9e)