Jupyter事始め

## はじめに
Jupyter初心者なので、AWS EC2上の環境構築方法、簡単な使い方を半年後の自分用にチラシの裏しておきます。

細かい設定はさておき、手っ取り早くEC2上にJupyter環境を構築し、Jupyter上で簡単なPython scriptを動かして、JupyterのUI操作方法の初歩を覚える所までを目標とします。Linux戦闘力が低いので、極力コピペで手順がなぞれる様に心がけます。



なお、Amazon EMRを使ってSpark Cluster上にJupyterを作りたい場合には[こちらを参照下さい](http://qiita.com/taka4sato/items/377a9dedb6842f056e60)。また、Jupyter Notebookは次期Versionより**Juypter Lab**となり大きくUI/機能が変わる予定です。Jupyter Labの環境構築方法は[こちらを参照下さい](http://qiita.com/taka4sato/items/378782763dec3dacb1ee)。


## Jupyter環境構築
まずは、Jupyter環境を構築する手順です。

### EC2の作成
Jupyterを動かすEC2を起動して、sshでloginします。

* Ubuntu 16.04を前提 (Amazon Linuxを使う場合には、aptをyum等に置き換えて下さい)
* EC2はm4.largeぐらいは合った方が良い
* EC2のSecurity GroupでPort `8080`を開けておく


### 必要なmoduleのinstall
`atp-get`で必要なmoduleを入れて、pipをupdateして、ipython[notebook]をinstallします。 `export LC_ALL=C`はssh login時に`WARNING! Your environment specifies an invalid locale.`みたいなメッセージが表示されたら追加してください。

```bash
$ export LC_ALL=C
$ sudo apt-get update
$ sudo apt-get install -y python-pip libpq-dev python-dev libpng12-dev libjpeg8-dev libfreetype6-dev libxft-dev
$ sudo pip install -U pip
$ sudo pip install numpy pandas matplotlib seaborn scikit-learn plotly ipython[notebook]
```

### Jupyterの設定

以下のコマンドを実行すると、Jupyterの設定ファイルの雛形(`~/.jupyter/jupyter_notebook_config.py`)を作成してくれます。

```bash
$ jupyter notebook --generate-config
```

続いて、`~/.jupyter/jupyter_notebook_config.py`を編集します。全て`#`でComment outされたデカイfileなので、fileの先頭など好きな場所に以下5行を入れて保存します(以下の設定は、誰でもそのJupyter serverにアクセスできる設定となります、ご注意ください)。

```
c = get_config()
c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.open_browser = False
c.NotebookApp.port = 8080
c.NotebookApp.token = ''
```

### Jupyter LoginにPasswordをかけたい場合
最近のJupyterからSecurity対策としてpasswordかtokenでのLoginが必須になっています。↑の例では、`c.NotebookApp.token = ''`でtoken無しのアクセスを許可しています。

Login passwordを設定したい場合には、Passwordのhash文字列を事前に調べておく必要が有ります。以下のコマンドを実行するとPasswordを入れるPromptがでるので、設定したいPasswordを入力します。

```bash
$ python -c "import IPython;print(IPython.lib.passwd())"
```

すると`sha1:3be1549bb425:1500071094720b33gf8f0feg474931dc5e43dfed`の様な`sha1:`で始まるhash文字列を返してくれるのでCopyしておきます。

そして、↑で編集した`~/.jupyter/jupyter_notebook_config.py`の内容を、以下のようにします。`c.NotebookApp.password`の後のhash文字列は、上で事前に調べたhash文字列に置き換えて下さい

```
c = get_config()
c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.open_browser = False
c.NotebookApp.port = 8080
c.NotebookApp.password = u'sha1:3be1549bb425:1500071094720b33gf8f0feg474931dc5e43dfed'
```


### Jupyterの起動

以下のコマンドを実行すると、Jupyterが起動します。

```bash
$ jupyter notebook
```

Browser上で`ec2-53-239-93-85.ap-northeast-1.compute.amazonaws.com:8080`など、EC2にアクセスに行きます。portの`8080`をお忘れ無く。 Jupyterのlogin画面が出て、上のほうで設定したpasswordを入力してloginが出来たら成功です。Background実行させたければ、`nohup jupyter notebook > /dev/null 2>&1 &`としておくと、sshを切断してもJupyterが動き続けます。

### Jupyterの自動起動の設定

`start_jupyter.sh`というscriptを作成し、それを`/etc/rc.local`に登録して、EC2起動時に、BackgroundでJupyterが実行される様に設定します。

* `touch ~/start_jupyter.sh`
* `start_jupyter.sh`を編集し、中に`/usr/local/bin/jupyter notebook`、と書いておく
* `chmod 777 ~/start_jupyter.sh`
* root権限で`/etc/rc.local`を編集し、`su - ubuntu /home/ubuntu/start_jupyter.sh &`の1行を`exit 0`の前に入れる
* root権限で`shutdown -r now`でEC2を再起動させる
* Browserから、EC2にアクセスに行き、jupyterのlogin画面が出たら成功です

## Jupyterの使い方

超簡単ですが、Jupyterの使い方をチラ裏します。

### Jupyter notebookを作成する
Loginしたら、`New`から`Python2`を選択し、Python2のnotebookを作成します。

![Setting1.png](https://qiita-image-store.s3.amazonaws.com/0/67592/7c261d38-b295-6979-54f9-c6c3003017dd.png)

### 各種iconについて
Jupyterは、**Cell**という箱(?)の中に、Codeや説明(Markdown)を記載していき、順次実行させる事で動かします。各種iconの機能は以下の通り

* `+`アイコンがCellの追加(`Insert` > `Insert Cell Above`か`Insert Cell Below`でもCell追加可能)
* `はさみ`アイコンがCellの削除
* `上下の矢印`アイコンがFocusが当たっているCellの位置の上下移動
* Pulldownで追加するCellの種類の選択
  * `Code`は、PythonなどのCodeの入力時に選択
  * `Markdown`は、Markdown言語を使い(Codeや処理結果への)説明をつける時に選択。[Mathjax](https://www.mathjax.org/)を使い数式の表記も可能
  * `Raw NBConvert`は、Latexで数式を入力する時に選択
  * `Heading`は、`Markdown`と似た用途らしい(将来的にはなくなる予定)

![Setting2.png](https://qiita-image-store.s3.amazonaws.com/0/67592/6634bd1a-4e49-7fcf-4a6f-700009ea0594.png)


### Python code入力してみる
以下のPython codeをCellに入力してみます。現在の時刻を1秒おきに10回printするだけのcodeです。


```py
import datetime, time

def main():
  for count in range(0, 10):
    print_current_time()
    time.sleep(1)

def print_current_time():
  print (datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'))

if __name__ == '__main__':
  main()
```

以下の様に4つのCodeのCellに、上記Python codeを入力してみて下さい。

* 入力が終わったら、`Cell` > `Run All` を実行すると、実行されます
* Cellの処理の順番がぐちゃぐちゃになったら、`Kernel` > `Restart` で`Clear all outputs & restart`を選択後、再度`Cell` > `Run All` を実行すると上から順番に処理されます

![Setting3.png](https://qiita-image-store.s3.amazonaws.com/0/67592/09b1c37f-c8ae-9cae-b838-59e6424458dc.png)


### コメントを入力してみる

以下の様にMarkdownのCellを追加して、中にMarkdownでコメントを入力してみて下さい。`Cell` > `Run All` を実行すると、MarkdownはRenderingされた状態で上から順番に処理されます。

![Setting5.png](https://qiita-image-store.s3.amazonaws.com/0/67592/5db90cd9-1c14-0fe1-62f4-209badf19552.png)

### 2D Chartを作成してみる
2D Chartの作成には`matplotlib`を使うのが一般的です。以下のCodeをJupyter上で実行させればChartが作成/表示されます。`%matplotlib inline`はmatplotlibの出力ChartをJupyter上に表示させる為に必要なオマジナイで、そのNotebook上のどこかで1回宣言/実行されていればOKです。

```py
%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt

x = np.random.randint(0, 100, 10000)
plt.hist(x, bins=20)
plt.plot()
```

`np.random.randint(0, 100, 10000)`で、0-99の範囲の乱数intを10,000個作り、その乱数の分布を柱の数を20個のヒストグラムとして表示します。

![matplotlib.png](https://qiita-image-store.s3.amazonaws.com/0/67592/e49c7a95-cb7f-c120-8a75-57f81125eac8.png)


なお、`matplotlib`は昔からある2D Chart 作成Libraryで、細かい設定ができる反面、パラメータの設定方法がやや複雑という意見あり、`seaborn`という短いCodeで今風のデザインのChartが作成可能なLibraryもあります([ここら辺を参考](https://nkmk.github.io/blog/python-seaborn-matplotlib/))。ただし、matplotlibはサポートだけどseabornはサポートされていないChartがあったりもするので要注意です。


### ３D Chartを作成してみる
3DのChartは`plotly`というLibraryを使うと作成可能です。機械学習等で3Dのデータ分布を確認したい時などに有効で、3Dだと[Scatter, Surface, Mesh](https://plot.ly/python/reference/#scatter3d)がサポートされています。以下のCodeをJupyter上で実行すれば、[こんな感じで3D Scatter Chartが表示されます](http://nbviewer.jupyter.org/github/taka4sato/qiita_articles/blob/master/plotly_3D_Scatter.ipynb)。DragやPinch in/outで視点変更や拡縮できる事をお楽しみください。

`np.random.multivariate_normal([0,0,0], [[0.1, 0, 0], [0, 1, 0], [0, 0, 2]], 1000).T`は、平均が[0,0,0]で、分散がそれぞれ[0.1, 1, 2]である３次元正規分布な乱数を1000個作る関数です。

```py
import plotly
import numpy as np
plotly.offline.init_notebook_mode()

x1, y1, z1 = np.random.multivariate_normal([3,3,3], [[0.5, 0, 0], [0, 0.5, 0], [0, 0, 0.5]], 1000).T
trace1 = plotly.graph_objs.Scatter3d(x=x1, y=y1, z=z1, mode='markers', marker=dict(size=1, line=dict(color='b')))

x2, y2, z2 = np.random.multivariate_normal([0,0,0], [[0.1, 0, 0], [0, 1, 0], [0, 0, 2]], 1000).T
trace2 = plotly.graph_objs.Scatter3d(x=x2, y=y2, z=z2, mode='markers', marker=dict(size=1, line=dict(color='r')))

fig = plotly.graph_objs.Figure(data=[trace1, trace2])
plotly.offline.iplot(fig, show_link=False)
```

### 数式を入力してみる
Jupyter上で数式を表現する方法は幾つかあります。

* `Raw NBConvert`のCell上でLatexで記載する
* `Markdown`のCell上で[Mathjax（Latex等の数式をBrowserで表示するlibrary）](https://www.mathjax.org/)で記載する

ここでは、Markdown上でMathjaxを使って記載してみます。

```text
$$r=\frac{1}{f}$$
$$\left(x + y\right)^{5}$$
```
**Markdown Cell**に上記を入力しそのCellを実行させ、以下の様にRenderingされればOKです。

![mathinput.jpg](https://qiita-image-store.s3.amazonaws.com/0/67592/f6c7e610-d1e0-6881-0ace-08ea11dfa387.jpeg)

Jupyter上でMathjaxを使った数式のサンプルは[この記事](http://jupyter-notebook.readthedocs.io/en/latest/examples/Notebook/Typesetting%20Equations.html)や、[この記事](http://www.suluclac.com/Wiki+MathJax+Syntax)にあります。また、Mathjaxの文法は[この記事(英語)が纏まって居ます](http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference)。



### notebookを保存してみる

`file` > `rename`で、作成したnotebookに名前を付け、`file` > `Download as`で`*.ipynb`形式で保存が可能です。

## その他Jupyter機能

### Jupyter上でshell scriptの実行
使っていてShell commandを実行したい、というケースはちょいちょいあります。Pythonのlibraryを追加したい、や、wgetで別のserverからfileを持ってきたい、など。

Master nodeにsshで入ってScriptを実行しても良いのですが、以下のいずれかの方法で、Jupyter上で直接shell scriptの実行も可能です。Jupyterを起動したuser権限でScriptが実行されます。

##### **commandsを使う**
commandsというpython libraryは、python上でshell scriptを実行してくれます。

```py
import commands
commands.getoutput("date")
commands.getoutput("curl yahoo.co.jp")
```

##### **Jupyterの`!`を使う**
Jupyter固有の機能として、`!`の後にshell scriptを書くと実行してくれます。

```bash
!date
!curl yahoo.co.jp
```

以下の様に`sudo`してshell scriptの実行も可能ですが、script実行後にJupyterがずっと処理中になるので、Interrupt等で復旧させる必要が有ります。

```bash
!sudo su
!find / -name 'hoge.txt'
```


### Jupyter notebook extensions
[Jupyter/IPythonのextension](https://github.com/ipython-contrib/IPython-notebook-extensions)と言うのが、(Jupyterの本家開発teamとは別で)開発されています。どんな機能があるかは、[こちらの記事](http://qiita.com/sasaki77/items/30a19d2be7d94116b237)がとても良く纏まって居ます。

ExtensionのInstall方法は、上記の`jupyterの設定`で`~/.jupyter/jupyter_notebook_config.py`を編集後、`jupyter notebook`でJupyterを起動させる前に、以下の2行を実行させればOKです。

```bash
mkdir -p ~/.local/share/jupyter
sudo pip install https://github.com/ipython-contrib/IPython-notebook-extensions/archive/master.zip
```

白状するとExtensionは自分は正直使っていません...。`ExecuteTime`は便利ですが。

### Jupyter Magic Commands
Jupyter/IPythonには、`Magic Commands`という専用機能があります。`ipython magic command`でググるといろいろ出てきますが、以下の様な物が有名です。

* `%who`で、宣言されている変数一覧の表示
* `%whos`で、宣言されている変数一覧の詳細表示(型と値)
* `%%timeit`で、Cellの処理に要した時間の計測
* `object名+?`で、Objectの型と値の表示
* `%quickref`で、サポートされるMagic Commandの一覧の表示

Cellに`%whos`と入力した状態でそのCellを実行すると、Magic commandが実行されます。が、白状するとMagic Commandは自分は正直使っていません...。`%whos`は便利なのでたまに使いますが。


## 最後に

良いJupyter生活を！