本記事はコネヒト Advent Calendar 2019 24日目の記事になります。
はじめに
Jupyter Notebookはプログラムコードや数式、図、説明文などを含む文書を作成し、共有することが出来る、データ解析用のWebアプリケーションです。一見するとJupyter NotebookとKotlinはあまり関連性がなさそうに見えますが、Jupyter NotebookでもKotlinが使えるようになったので、触ってみた内容を共有したいと思います。
Jupyter NotebookでKotlinが利用できることを知った
KotlinConf 2019にて、Kotlin 1.4、Coroutines、Multiplatform、Spaceなど、Kotlinの最新情報からチーム開発を円滑に進めるためのツールまで様々なセッションがありました。たくさんのセッションがあった中にKotlinを用いたデータサイエンスに関連するセッションが3つありました。
その中でもRoma BelovさんのセッションではKotlinを用いたデータサイエンスについて発表されて、主にツールやライブラリなどの側面からデータサイエンス に適用される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のライブラリになります。
![スクリーンショット 2019-12-24 7.07.24.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2Fa63c0a5e-b0c8-62e3-1d4d-753978690626.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=2c7e63da0dac00cd0188c253aa95e163)
lets-plotライブラリ
いくつかKotlinライブラリがあることがわかりましたが、ここからはlets-plotとkranglのデータ操作とチャートに関するライブラリに絞って紹介したいと思います。まずはlets-plotで、これはチャートを簡単に描画できるライブラリです。具体的には以下のチャートがサポートされており、描画サンプルは以下の通りです。
チャート | メソッド名 |
---|---|
Area chart | geom_area() |
Bar chart | geom_bar() |
Boxplot chart | geom_boxplot() |
Contour chart | geom_contour(), geom_contourf() |
Density chart | geom_density() and geom_density2d() |
Error bar chart | geom_errorbar() |
Historgam | geom_histogram() |
Line chart | geom_line() |
Scatter chart | geom_point() |
Polygon chart | geom_polygon() |
Rectangle chart, Tile chart | geom_rect(), geom_tile() |
Image plot | geom_image() |
Boxplot chart
![スクリーンショット 2019-12-24 12.03.33.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2Fe0e8b699-0600-1fb1-2aa9-c434ccbb8611.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=42739773e070bbc84e9629103f2144f8)
Historgam chart
![スクリーンショット 2019-12-24 12.18.08.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2F59454fab-ccb0-f4af-157e-4506ccbf9fb7.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=af4f9e9651409544fda131d383562a83)
Line chart
![スクリーンショット 2019-12-24 12.31.16.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2Fe2c0c024-c18a-2495-1c9a-eca35cf6bcbc.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=c4adc114f7f625ecad9190fcdb3c4c92)
Bar chart
![スクリーンショット 2019-12-24 12.37.20.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2Fd6d3d63f-5ec2-37a6-50f4-ffcd02813f1c.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=94f622fc043303dbf902c22eecb11005)
Scatter chart
![スクリーンショット 2019-12-24 12.42.40.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2Fbd6af568-35fc-8887-c064-702dad4a6360.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=e383df5bf5a9726e530015ce68e29750)
Tile chart
![スクリーンショット 2019-12-24 12.47.03.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2F24dfc97e-f14c-a4ba-821d-8ccb94586c43.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=af18d19c330d548411ac13b289630aa4)
Density chart
![スクリーンショット 2019-12-24 12.53.07.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2F949e253f-c83c-09cf-cb37-2ab3cd2eb412.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=1ffaee70b46bd93ef821ef48ad4ed1c8)
kranglライブラリ
次にkranglライブラリについて説明します。データを行列のデータ形式に変換、集計、フィルタリングなど、データフレームの基本的な操作が行えます。kranglにはirisDataがバンドルされているのでそれらも用いてサンプルを作ってみます。
irisDataの表示
![スクリーンショット 2019-12-24 13.05.38.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2F54098b32-f635-2908-9b2d-a3f4e17a4a50.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=1470b0df95ded1ec8567898308ca75f8)
データフレームの作成と表示
![スクリーンショット 2019-12-24 13.16.24.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F23391%2Fa30f4baf-2e71-abda-6f63-49a35e4a4546.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=d08975702ec32591b8f198da6264e05b)
Slackデータを用いたデータ分析
ここまで、Jupyter NotebookとKotlin Kernelとチャートとデータ操作ライブラリについて説明しました。では、Slackデータを用いて簡単なデータ分析をしてみましょう。Slackデータに関しては、権限があればワークスペースからデータを簡単にエクスポートできます。ワークスペースのデータをエクスポートすると、メッセージの履歴やファイルへのリンクにアクセスできる .zip ファイルをダウンロードできます。 データエクスポートには以下2種類あり、ワークスペースのオーナーと管理者によってのみ実行可能です。
公開データ | ワークスペースの全データ | |
---|---|---|
channels.json | | |
dms.json | | |
groups.json | | |
integration_logs.json | | |
mpims.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やサーバサイドで利用されている事例は増えていますが、データサイエンスの事例がとても少なかったので興味深かったです。すでに多くのライブラリが開発されており、何かしらコミュニティに貢献できればと考えています。
PR
コネヒトではエンジニアを募集しています!家族向けサービスをつくりたいエンジニアの皆さん、お待ちしています。
家族の課題を解決するサービスのMAUを増やすAndroidエンジニア募集!