F#でとにかくJupyterが使いたい人に捧ぐIFSharp

# イントロ

最近の機械学習などのデータ分析に関する情報のやり取りは、
コードに限らずグラフや表、数式も出力可能なJupyter Notebookが主流ですよね。

Jupyter使いたい、Pythonが憎い?とお嘆きのF#erにも朗報が。
MicrosoftがJupyter Notebookのweb版の[Azure Notebook](https://notebooks.azure.com)というサービスがあるんです。

~~ただ、まだpreview版のせいかレスポンスがもっさり。~~
~~なのでAzure上で動いている[IFSharp](https://github.com/fsprojects/IfSharp)というF#が実行可能なJupyterをDockerコンテナ上に配置して
ローカルでも利用出来るようにします。~~
（もちろんローカルにPython一式がインストールしてある方はifsharp.exeをそのまま実行するやり方もあります）
=> 今回はこれで行きます

## 使用環境

- ~~Ubuntu 16.04 LTS~~
- ~~Docker CE~~
- Windows 10
- Anaconda

## 環境構築

IFSharp.exeを[ここ](https://github.com/fsprojects/IfSharp/releases/tag/v3.0.1)からダウンロードして起動してください。
そのあとJupyter Notebookを起動すればOK。

~~Dockerをインストール。以下はUbuntuで実行していますが、他のOSはそれぞれのDockerのインストール手順に従ってください。~~


~~適当な作業フォルダにIFSharpをクローンしてコンテナを起動。
FOLDERNAMEはDockerと共有したいフォルダ名に置き換えてください。~~


実行後URLが表示されるのでクリックしてブラウザが起動しJupyterの画面が開きます。
これで完了。くれぐれもPythonを選ばないように。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661/70ff6de3-c484-94cc-0d70-841ee7fbd072.png)

## 使ってみる

Github上の[サンプル](https://github.com/fsprojects/IfSharp/blob/master/FSharp_Jupyter_Notebooks.ipynb)もありますが、
今までFSIで実行したのと違いや気になったことをまとめておきます。

### パッケージのインポート方法

Paketを用いて以下のようにかけます。paket.dependenciesみたいな感じですね。
公式ドキュメントは#Nでnuget出来るよって書いてあるんですけど現在は非推奨のようです。

```FSharp
#load "Paket.fsx"
Paket.Package ["Newtonsoft.Json";"Deedle"; "MathNet.Numerics"; "MathNet.Numerics.FSharp"; ]
#load "Paket.Generated.Refs.fsx"

open Deedle
open MathNet.Numerics
open Newtonsoft.Json
open MathNet.Numerics.LinearAlgebra
```

### グラフの出力

F#でグラフの出力というと、Windows.Formsを用いた[FSharp.Charting](https://fslab.org/FSharp.Charting/)が真っ先に思い浮かぶんですが、
AzureやDockerコンテナ上で動いているIFSharp上ではPaketで持ってきてもFSharp.Chartingは使えません。
(Gtk周りのエラーが出ます)
サンプルにもあるように[XPlot](https://tahahachana.github.io/XPlot/)を使うのがよいみたいです。

```fsharp
#load "XPlot.Plotly.Paket.fsx"
#load "XPlot.Plotly.fsx"
open FSharp.Core
open XPlot.Plotly

let x = [for i in -10.0 .. 10.0 -> (i, 1.0 / (1.0 + exp -i))]
Chart.Line x
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1661/c3e6268e-9ac2-7e4d-c4bc-6d3e46f09b17.png)


### ~~表はIFSharp.Utilを使う~~ DeedleのData Frameを表示する

PythonでいうところのPandasのようなイメージで、Deedleで作成したFrameを表としてJupyter上に表示させたいのですが、今のところ公式ではサポートしてません。そこでIFSharp.Utilを用いることでレコード型を表示出来るようです。

(2019/8/11 追記)
Formatterはこちらのものを使用。
機械学習でよく使うTitanicは[こちら](https://www.kaggle.com/c/titanic/data)からダウンロードできます。

#### 初期設定

Githubの[Issue](https://github.com/fsprojects/IfSharp/issues/146)にかいてありますが、
[このファイル](https://github.com/mndrake/IfSharpLab/blob/master/src/DeedleFormat.fs)をIFSharpフォルダにおいてあげてよみこめば出力可能。

```diff:DeedleFormat.fsx
module DeedleFormat


+ #I @"packages\Deedle\lib\net45"
+ #r "Deedle.dll"
+ #r "IfSharp.Kernel.dll"

open System
```

#### 表の出力

Deedleの[こちらの例](http://bluemountaincapital.github.io/Deedle/tutorial.html)を試しに実行してみます。

```fsharp
#load "DeedleFormat.fsx"
open Deedle
open FSharp.Core
// Read Titanic data & group rows by 'Pclass'
let titanic = Frame.ReadCsv(@"..\..\data\train.csv").GroupRowsBy<int>("Pclass")

// Get 'Survived' column and count survival count per clsas
let byClass =
  titanic.GetColumn<bool>("Survived")
  |> Series.applyLevel fst (fun s ->
      // Get counts for 'True' and 'False' values of 'Survived'
      series (Seq.countBy id s.Values))
  // Create frame with 'Pclass' as row and 'Died' & 'Survived' columns
  |> Frame.ofRows 
  |> Frame.sortRowsByKey
  |> Frame.indexColsWith ["Died"; "Survived"]

// Add column with Total number of males/females on Titanic
byClass?Total <- byClass?Died + byClass?Survived

// Build a data frame with nice summary of rates in percents
frame [ "Died (%)" => round (byClass?Died / byClass?Total * 100.0)
        "Survived (%)" => round (byClass?Survived / byClass?Total * 100.0) ]

byClass
```

実行結果はこちら

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661/326d502c-5fa3-550e-4594-98438d4d366b.png)


## まとめ

Alt-PythonとしてF#使ってみるといいのではないでしょうか！