本記事はコネヒト Advent Calendar 2019 24日目の記事になります。

はじめに

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

Jupyter NotebookでKotlinが利用できることを知った

スクリーンショット 2019-12-24 7.06.27.png

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
スクリーンショット 2019-12-24 11.31.44.png

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

スクリーンショット 2019-12-24 11.39.22.png

データサイエンスのライブラリについて

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

スクリーンショット 2019-12-24 7.07.24.png

lets-plotライブラリ

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

チャートメソッド名Area chartgeom_area()Bar chartgeom_bar()Boxplot chartgeom_boxplot()Contour chartgeom_contour(), geom_contourf()Density chartgeom_density() and geom_density2d()Error bar chartgeom_errorbar()Historgamgeom_histogram()Line chartgeom_line()Scatter chartgeom_point()Polygon chartgeom_polygon()Rectangle chart, Tile chartgeom_rect(), geom_tile()Image plotgeom_image()

Boxplot chart

スクリーンショット 2019-12-24 12.03.33.png

Historgam chart

スクリーンショット 2019-12-24 12.18.08.png

Line chart

スクリーンショット 2019-12-24 12.31.16.png

Bar chart

スクリーンショット 2019-12-24 12.37.20.png

Scatter chart

スクリーンショット 2019-12-24 12.42.40.png

Tile chart

スクリーンショット 2019-12-24 12.47.03.png

Density chart

スクリーンショット 2019-12-24 12.53.07.png

kranglライブラリ

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

irisDataの表示

スクリーンショット 2019-12-24 13.05.38.png

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

スクリーンショット 2019-12-24 13.16.24.png

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"
    }
plots1.png

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"
    }

スクリーンショット 2019-12-23 18.32.44.png

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"
    }
plots2.png

最後に

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

PR

Connehito Image
广告
将在 10 秒后关闭
bannerAds