本記事はコネヒト Advent Calendar 2019 24日目の記事になります。
はじめに
Jupyter Notebookはプログラムコードや数式、図、説明文などを含む文書を作成し、共有することが出来る、データ解析用のWebアプリケーションです。一見するとJupyter NotebookとKotlinはあまり関連性がなさそうに見えますが、Jupyter NotebookでもKotlinが使えるようになったので、触ってみた内容を共有したいと思います。
Jupyter NotebookでKotlinが利用できることを知った

Jupyter NotebookでKotlinを利用するには?
Jupyter NotebookでKotlinを使うには、Kernelが必要になります。Kernelとは、入力されたコードをインタラクティブに処理して結果を返すプロセスのことを表します。すでに様々なKernelがあり、KotlinのKernelはkotlin-jupyter-kernelになります。Jupyter Notebook自体のインストール方法については割愛させていただきますが、kotlin-jupyter-kernelは、以下のようにCondaパッケージを使ってインストールします。kotlin-jupyter-kernelをインストール後にJupyter Notebookを起動し、「New -> Notebooks -> Kotlin」とKotlinのNotebookを作成できることがわかります。
$ conda install kotlin-jupyter-kernel -c jetbrains
$ jupyter notebook

Notebookを新規作成して、Hello Worldを試した例です。また、ローカル環境だけでなくBinderというサービスからJupyter NotebookをWeb上で簡単に試すこともできます。

データサイエンスのライブラリについて
ここまでJupyter NotebookでKotlinを使う部分について紹介しました。では、実際にデータ分析をするにはどうするのでしょうか。Kotlinには、以下のようにすでに多くのライブラリが存在します。下図の青い項目がKotlinのライブラリになります。

lets-plotライブラリ
いくつかKotlinライブラリがあることがわかりましたが、ここからはlets-plotとkranglのデータ操作とチャートに関するライブラリに絞って紹介したいと思います。まずはlets-plotで、これはチャートを簡単に描画できるライブラリです。具体的には以下のチャートがサポートされており、描画サンプルは以下の通りです。
Boxplot chart

Historgam chart

Line chart

Bar chart

Scatter chart

Tile chart

Density chart

kranglライブラリ
次にkranglライブラリについて説明します。データを行列のデータ形式に変換、集計、フィルタリングなど、データフレームの基本的な操作が行えます。kranglにはirisDataがバンドルされているのでそれらも用いてサンプルを作ってみます。
irisDataの表示

データフレームの作成と表示

Slackデータを用いたデータ分析
ここまで、Jupyter NotebookとKotlin Kernelとチャートとデータ操作ライブラリについて説明しました。では、Slackデータを用いて簡単なデータ分析をしてみましょう。Slackデータに関しては、権限があればワークスペースからデータを簡単にエクスポートできます。ワークスペースのデータをエクスポートすると、メッセージの履歴やファイルへのリンクにアクセスできる .zip ファイルをダウンロードできます。 データエクスポートには以下2種類あり、ワークスペースのオーナーと管理者によってのみ実行可能です。
groups.json
integration_logs.jsonmpims.json
users.json全チャンネルのフォルダ
いくつかサンプルを紹介しますが、コネヒトのSlackデータを用いてデータ抽出を行いましたので、一部モザイクをかけています。
channels.jsonから参加者の多い上位のチャンネルを抽出する
// krangl, lets-plotのインポート
%use krangl, lets-plot
// Json配列からList型に変換
fun readFromJsonString(s: String) =
s.removePrefix("JsonArray(value=[")
.removeSuffix("])")
.split(",")
.dropLastWhile { it.isEmpty() }
.toList()
// データフレームの生成
val channels = DataFrame.fromJson("channels.json")
.addColumn("channle_members") { it["members"].map<String> { value -> readFromJsonString(value) } }
.addColumn("count") { it["channle_members"].map<List<String>> { it.count() } }
.filter { it["is_archived"] eq false }
.select("id", "name", "channle_members", "count")
.sortedByDescending("count")
// 出力用にデータの整形
val data = mapOf(
"name" to channels["name"].asStrings().toList(),
"count" to channels["count"].asInts().toList()
)
// グラフの描画
lets_plot(data) +
geom_bar(stat = Stat.identity) {
x = "name"
y = "count"
}

users.jsonからTimeZone別にユーザを抽出する
// krangl, lets-plotのインポート
%use krangl, lets-plot
// データフレームの生成
val channels = DataFrame.fromJson("users.json")
.filterByRow { (it["tz"] as? String)?.isNotEmpty() == true }
.filterByRow { (it["deleted"] as Boolean) == false }
.select("id", "name", "tz")
.sortedByDescending("id")
// tz毎にグルーピング
val groupData = channels.groupBy("tz").count()
// 出力用にデータの整形
val data = mapOf(
"name" to groupData["tz"].asStrings().toList(),
"count" to groupData["n"].asInts().toList()
)
// グラフの描画
lets_plot(data) +
geom_bar(stat = Stat.identity) {
x = "name"
y = "count"
}

integration_logs.jsonからSlackのインテグレーションタイプ別に抽出する
// krangl, lets-plotのインポート
%use krangl, lets-plot
// データフレームの生成
val channels = DataFrame.fromJson("integration_logs.json")
.filterByRow { (it["service_type"] as? String)?.isNotEmpty() == true }
.select("service_type")
// service_type毎にグルーピング
val groupData = channels.groupBy("service_type").count()
// 出力用にデータの整形
val data = mapOf(
"name" to groupData["service_type"].asStrings().toList(),
"count" to groupData["n"].asInts().toList()
)
// グラフの描画
lets_plot(data) +
geom_bar(stat = Stat.identity) {
x = "name"
y = "count"
}

最後に
KotlinでJupyter Notebookを触ってみました。KotlinはAndroidやサーバサイドで利用されている事例は増えていますが、データサイエンスの事例がとても少なかったので興味深かったです。すでに多くのライブラリが開発されており、何かしらコミュニティに貢献できればと考えています。