Python for Data Analysis Chapter 4

#NumPy Basics: Arrays and Vectorized Computation

##ndarray
NumPyが提供するn次元配列オブジェクト
###Creating dnarrays

```py
#配列から作成
data1 = [6, 7.5, 8, 9]
arr1 = np.array(data1)

#多次元配列でも作成できる
data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2 = np.array(data2)

#pythonのrange関数
np.arange(10)

#零ベクトル
np.zeros(10)

#零行列
np.zeros((3, 6))

#初期化しないで生成
np.empty((2, 3, 2))

#次元の確認
arr2.ndim

#配列の形
arr2.shap

#データ型の確認
arr1.dtype

#データ型を指定して生成
arr1 = np.array([1, 2, 3], dtype=np.float64)

#文字列から生成
data3 = ["1.1", "2.2", "3.3"]
arr3 = np.array(data3, dtype=float64)
```

##Operations between Arrays and Scalars

```py
#配列同士の計算は同じ場所同士の計算
arr = np.array([[1, 2, 3], [4, 5, 6]])
"""
In [32]: arr
Out[32]: 
array([[1, 2, 3],
       [4, 5, 6]])
"""
arr * arr
"""
In [33]: arr * arr
Out[33]: 
array([[ 1,  4,  9],
       [16, 25, 36]])
"""

#スカラーとの計算は全要素に対して計算される
arr - 1
"""
In [34]: arr - 1
Out[34]: 
array([[0, 1, 2],
       [3, 4, 5]])
"""
1 / arr
"""
In [35]: 1 / arr
Out[35]: 
array([[1, 0, 0],
       [0, 0, 0]])
"""
```

##Basic Indexing and Slicing / Fancy Indexing
|\|0|1|2|
|:-:|:-:|:-:|:-:|
|0|0,0|0,1|0,2
|1|1,0|1,1|1,2|
|2|2,0|2,1|2,2|
要素の指定は数学の行列と同じで(row, col)

![](https://dl.dropboxusercontent.com/u/1990306/Qiita/FancySlice.png)

__配列スライスのコピーが欲しかったらcopyしないと元の配列が変わった時にスライスも変わってしまう__
`arr[5:8].copy()`

##Boolean Indexing
bool配列を使って配列のマスキングができる

```py
name = np.array(["bob", "martin" ,"feed","max","rosetta","john"])
"""
In [63]: name == "bob"
Out[63]: array([ True, False, False, False, False, False], dtype=bool)
"""
arr = np.arange(6)
"""
In [68]: arr[name=="rosetta"]
Out[68]: array([4])
"""
```
ブール演算子
`&` (and)
`|` (or)

```Python:
mask = (name=="rosetta") | (name=="martin")
"""
In [72]: mask
Out[72]: array([False,  True, False, False,  True, False], dtype=bool)
"""
```

比較演算子による選択

```py
data = randn(10)
"""
In [78]: data
Out[78]: 
array([-0.43930899, -0.18084457,  0.50384496,  0.34177923,  0.4786331 ,
        0.0930973 ,  0.95264648,  1.29876589,  0.96616151,  0.69204729])
"""
data[data < 0] = 0
"""
In [80]: data
Out[80]: 
array([ 0.        ,  0.        ,  0.50384496,  0.34177923,  0.4786331 ,
        0.0930973 ,  0.95264648,  1.29876589,  0.96616151,  0.69204729])
"""
```
##Transposing Arrays and Swapping Axes
！！！！！難しい！！！！！
ファンシースライスで欲しいとこだけ取ったほうが楽な気がする…

```py
arr = np.arange(15).reshape((3,5))

#転置
arr.T

#内積
np.dot(arr.T, arr)

arr = np.arange(45).reshape((3,5,3))

#軸指定で変形
arr.transpose((1, 0, 2))

#軸の交換
arr.swapaxes(1, 2)
```

##Universal Functions: Fast Element-wise Array Functions
###1引数関数
elementwise（要素単位）で操作を行う関数。
`np.func(x)`でxの要素それぞれについて関数を適用する。

|Function|Description|
|:--|:--|
|abs|絶対値|
|sqrt|x ** 0.5|
|square|x ** 2|
|exp|exp(x)|
|log, log10, log2|底をe, 10, 2でlog(x)|
|log1p|xがごく小さい時のlog(1+x)|
|sign|符号(1,0,-1)を返す|
|ceil|小数点以下切り上げ|
|floor|小数点以下切り捨て|
|rint|小数を最近の整数へ丸める|
|modf|小数を小数部と整数部へ分解|
|isnan, isinf, isfinite|NaN, 無限, 数値かのbool値を返す|
|logical_not|not xのbool値を返す|
###2引数関数
`np.func(x1, x2)`で用いる。

|Function|Description|
|:--|:--|
|add, subtract, multiply, divide, power, mod|x1 (+, -, *, /, **, %) x2|
|maximum, minimum|x1とx2の同じ位置の要素で(大きい, 小さい)方|
|copysign|x1 * (sign of x2)|
|greater, greater_equal, less, less_equal, equal, not_equal|x1 (>, >=, <, <=, ==, !=) x2|
|logical_and, logical_or, logical_xor|x1 (&, 丨, ^)  x2|

##Data Processing Using Arrays
二次元データを可視化する。
例としてsqrt(x^2, y^2)を計算したグリッドを表示する。

```py
#1000個の点を作成
points = np.arange(-5, 5, 0.01)
#2次元メッシュを作成
#xは行にxの配列を、yは列にyの配列を持つ2次元配列
xs, ys = np.meshgrid(points, points)
#計算
z = np.sqrt(xs ** 2 + ys ** 2)
#表示
plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()
plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values")
```
![](https://dl.dropboxusercontent.com/u/1990306/Qiita/PfDACh4-1.png)

##Expressing Conditional Logic as Array Operations
`np.where`は第1引数の値によって第2引数または第3引数のどちらかを返す関数。
すなわち、np.where(cond, xarr, yarr) = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)]

```py
arr = randn(5, 5)
"""
In [5]: arr
Out[5]: 
array([[-0.63774199, -0.76558645, -0.46003378,  0.61095653,  0.78277454],
       [ 0.25332127,  0.50226145, -1.45706102,  1.14315867,  0.28015   ],
       [-0.76326506,  0.33218657, -0.18509161, -0.3410194 , -0.29194451],
       [-0.32247669, -0.64285987, -0.61059921, -0.38261289,  0.41530912],
       [-1.7341384 ,  1.39960857,  0.78411537,  0.25922757, -0.22972615]])
"""
arrtf = np.where(arr > 0, True, False)
"""
In [6]: arrtf
Out[6]: 
array([[False, False, False,  True,  True],
       [ True,  True, False,  True,  True],
       [False,  True, False, False, False],
       [False, False, False, False,  True],
       [False,  True,  True,  True, False]], dtype=bool)
"""
```
これを組み合わせれば複数の条件で分類をすることも可能。

```py
cond1 = np.where(randn(10) > 0, True, False)
cond2 = np.where(randn(10) > 0, True, False)
"""
In [16]: cond1
Out[16]: array([False,  True, False, False,  True,  True,  True,  True,  True,  True], dtype=bool)

In [17]: cond2
Out[17]: array([False, False, False, False, False,  True, False,  True,  True,  True], dtype=bool)
"""
result = np.where(cond1 & cond2, 0, np.where(cond1, 1, np.where(cond2, 2, 3)))
"""
In [19]: result
Out[19]: array([3, 1, 3, 3, 1, 0, 1, 0, 0, 0])
"""
```

ifとelseの書き換えも可能。

```py
result = []
for i in range(n):
    if cond1[i] and cond2[i]:
        result.append(0)
    elif cond1[i]:
        result.append(1)
    elif cond2[i]:
        result.append(2)
    else:
        result.append(3)
```
数式でも可能。（他のとは0と3が入れ替わっている事に注意）
`result = 1*cond1 + 2*cond2`

##Mathematical and Statistical Methods
統計的な関数も用意されている。

```py
arr = randn(5, 4)
arr.mean()
#軸の指定も可能
arr.mean(0)
arr.mean(1)
"""
In [60]: arr.mean()
Out[60]: 0.51585861805229682

In [62]: arr.mean(0)
Out[62]: array([ 0.65067115, -0.03856606,  1.06405353,  0.38727585])

In [63]: arr.mean(1)
Out[63]: array([ 1.18400902,  0.84203136,  0.50352006,  0.07445734, -0.0247247 ])
"""
```

+ sum
+ mean
+ std, var
+ min, max
+ argmin, argmax（最大・最小値のインデックスを返す）
+ cumsum（累進合計）
+ cumprod（累積合計）

##Methods for Boolean Arrays
ブール型のTrueは1、Falseは0と数えられることから、sum関数によるカウントなどがよく用いられる。

```py
arr = randn(100)
sumnum = (arr > 0).sum()
"""
In [75]: sumnum
Out[75]: 43
"""
```

他のブール関数は

+ any（一つでもTrueがあったらTrue）
+ all（全てTrueだったらTrue）

##Sorting
ソートもできる。
`arr.sort()`

##Unique and Other Set Logic
Python純正のset関数のようなものも使える。

+ unique(x)
+ intersect1d(x, y)（unique(x) & unique(y)）
+ union1d(x, y)（unique(x) | unique(y)）
+ in1d(x, y)（yの要素がxに含まれているかブール値の配列を返す）
+ setdiff1d(x, y)（yにないxの値）
+ setxor1d(x, y)（yにないxの値 & xにないyの値）

##File Input and Output with Arrays
NumPyのarray objectを外部ファイルに保存する事ができる。
もちろん、保存したファイルを読み込んで復元することもできる。

```py
arr = np.arange(10)

#バイナリ形式で保存
np.save("array_name", arr)
#バイナリ形式のファイルをロード
arr = np.load("array_name.npy")
#複数配列をzipで保存
np.savez("array_archive.npz", a=arr, b=arr)
#複数配列のzipをロード
arr_a = np.load("array_archive.npz")["a"]
arr_b = np.load("array_archive.npz")["b"]

#csv形式で保存
np.savetxt("array_ex.txt", arr, delimiter=",")
#csv形式のファイルを読み込み
arr = np.loadtxt("array_ex.txt", delimiter=",")
```

##Linear Algebra
線形代数の計算もできる。

|Function|Description|
|:--|:--|
|diag|対角要素を抜き出す|
|dot|内積|
|trace|対角要素の和|
|det|行列式|
|eig|固有値と固有ベクトルへ分解|
|inv|転置|
|pinv|ムーア-ペンローズの擬似逆行列|
|qr|QR分解|
|svd|SVD分解|
|solve|Aが正方行列のときAx=bのxを求める|
|stsq|最小二乗解を計算|

##Random Number Generation
高速に様々な分布のランダム値を得ることができる。

|Function|Description|
|:--|:--|
|seed|シード値によるランダム生成|
|permutation|シーケンスの要素をランダムに並べ替える|
|shuffle|シーケンスの要素をランダムに並び替える|
|rand|引数で渡された次元数のランダム配列を生成|
|randint|引数で渡された次元数のランダム整数配列を生成|
|binomial|二項分布からランダムサンプリング|
|normal|正規分布からランダムサンプリング|
|beta|ベータ分布からランダムサンプリング|
|chisquare|chi-square分布からランダムサンプリング|
|gamma|ガンマ分布からランダムサンプリング|
|uniform|与えられた範囲の正規分布からランダムサンプリング|

##Example: Random Walks
以下をipythonで実行

```py
nsteps = 1000
draws = np.random.randint(0, 2, size=nsteps)
steps = np.where(draws > 0, 1, -1)
walk = steps.cumsum()
plt.plot(walk)
```
![](https://dl.dropboxusercontent.com/u/1990306/Qiita/PfDACh4-2.png)

###Simulating Many Random Walks at Once

```py
nwalks = 100
nsteps = 1000
draws = np.random.randint(0, 2, size=(nwalks, nsteps))
steps = np.where(draws > 0, 1, -1)
walks = steps.cumsum(1)
plt.plot(walks)
```

![](https://dl.dropboxusercontent.com/u/1990306/Qiita/PfDACh4-3.png)
拡大
![](https://dl.dropboxusercontent.com/u/1990306/Qiita/PfDACh4-4.png)
あんまり高品質なランダム値じゃないように見えるけど実際はメルセンヌツイスタを使っているから相当に高品質なはず…。