Livebook 0.10 + KinoExplorer でもっと便利なデータフレーム

## はじめに

Livebook 0.10.0 の機能追加に、データフレームのファイルエクスポートがあります

https://www.youtube.com/watch?v=_VYiYlmOOlk&t=20s

ただし、エクスポートするためには KinoExplorer が必要です

https://github.com/livebook-dev/kino_explorer

KinoExplorer の機能について紹介していきます

## Kino とは

Kino は Livebook の UI/UX を強化するモジュールです

[Kino](https://github.com/livebook-dev/kino) 本体では、入力フォームの作成やアニメーションなどが実装できます

![form_animate.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/c0a7aa07-d0be-96df-cd07-351d527a4996.gif)

他にも [KinoVegaLite](https://github.com/livebook-dev/kino_vega_lite) （グラフ表示）や [KinoMapLibre](https://github.com/livebook-dev/kino_maplibre) （地図表示）などの Kino シリーズが存在しています

![cake_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/3262f690-49ee-1fe6-4447-bf4d6e482297.png)

![oco2_map.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/66cfdc38-c0a4-8a71-28a3-afcb1205a198.png)

## Explorer とは

[Explorer](https://github.com/elixir-explorer/explorer) は Elixir でデータ解析をするためのモジュールです

データをデータフレームという形式にして、抽出、集計などの操作を行います

![data_table.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/47f8a476-c834-b7a6-73c0-c1002e5acc9b.png)

![joined.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/7b380b67-da32-efc6-0c1a-eaf78b56a9ae.png)

## KinoExplorer とは

KinoExplorer　は Explorer を Kino に統合したもの、つまり Explorer を Livebook で更に使いやすく、見やすくするためのモジュールです

その効果を具体的に見ていきましょう

## KinoExplorer がない場合

まず KinoExplorer がない場合を見てみましょう

新しいノートブックを開き、セットアップセルに以下のコードを入力して実行します

```elixir
Mix.install([
  {:explorer, "~> 0.6"},
  {:kino, "~> 0.10"}
])
```

Kino と Explorer を個別にインストールしています

この状態で適当なデータフレームを作成してみます

```elixir
sample_df =
  %{
    "labels" => ["a", "b", "c", "c", "c"],
    "values" => [1, 2, 3, 2, 1]
  }
  |> Explorer.DataFrame.new()
```

実行結果は以下のようになります

![スクリーンショット 2023-07-17 15.00.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/b8f66848-c8c5-5cc5-eb3b-21a781e94512.png)

これを表（テーブル）として表示したい場合、 `Kino.DataTable.new()` を使うことになります

```elixir
Kino.DataTable.new(sample_df)
```

![スクリーンショット 2023-07-17 15.01.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/5ae0cba0-8dd1-d061-2136-b7dd1539f4e3.png)

このとき、 Livebook 0.10.0 でも、データテーブル表示にファイルエクスポートの機能はありません

Livebook からデータをダウンロードしたい場合、以下のようにコードを書く必要があります

- CSV
    
    ```elixir
    Kino.Download.new(
      fn -> Explorer.DataFrame.dump_csv!(sample_df) end,
      filename: "sample.csv"
    )
    ```

- NDJSON

    Newline Delimited JSON (改行区切りの JSON)

    ```elixir
    Kino.Download.new(
      fn -> Explorer.DataFrame.dump_ndjson!(sample_df) end,
      filename: "sample.ndjson"
    )
    ```

- [Parquet](https://parquet.apache.org/)

    効率の良いデータ形式で、大量のデータを少ないファイルサイズで保存できます

    ```elixir
    Kino.Download.new(
      fn -> Explorer.DataFrame.dump_parquet!(sample_df) end,
      filename: "sample.parquet"
    )
    ```

## KinoExplorer がある場合

セットアップセルに KinoExplorer を追加して再度実行します

```elixir
Mix.install([
  {:explorer, "~> 0.6"},
  {:kino, "~> 0.10"},
  {:kino_explorer, "~> 0.1"}
])
```

:::note info
KinoExplorer を追加しておけば Explorer は自動的にインストールされますが、今回は明示的に入れたままにしておきます
:::

再びデータフレームを作ってみます

```elixir
sample_df =
  %{
    "labels" => ["a", "b", "c", "c", "c"],
    "values" => [1, 2, 3, 2, 1]
  }
  |> Explorer.DataFrame.new()
```

すると、この時点で表として結果が表示されます

![スクリーンショット 2023-07-17 15.35.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/5fa31d3f-78dd-b686-9f71-72c183663c91.png)

しかも、列毎に集計値が表示されています

- 文字列の場合
  - 重複排除した件数
  - 最も多い値
  - 最も多い値の件数
  - null （欠損値）の件数
- 数値の場合
  - 最小値
  - 最大値
  - 平均値
  - null （欠損値）の件数

そして左上、　"DataFrame 5 entries" の右に見慣れないアイコンが増えています

これをクリックすると、エクスポート形式の選択肢が表示されます

- CSV
- NDJSON
- Parquet

![export.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/716f8808-0769-37d2-5425-9d67718d92aa.gif)

それぞれを選択すると、以下のようなファイルがブラウザからダウンロードされます

- CSV
    
    ```text
    labels,values
    a,1
    b,2
    c,3
    c,2
    c,1
    ```

- NDJSON
    
    ```text
    {"labels":"a","values":1}
    {"labels":"b","values":2}
    {"labels":"c","values":3}
    {"labels":"c","values":2}
    {"labels":"c","values":1}
    ```

- Parquet

    そのままテキストとしては読めないので、 [parquet-cli](https://github.com/apache/parquet-mr/blob/master/parquet-cli/README.md) (macOS の場合は `brew install parquet-cli` でインストール可能)を使って読んでみます

    ```bash
    $ parquet cat DataFrame-1689576651258.parquet
    {"labels": "a", "values": 1}
    {"labels": "b", "values": 2}
    {"labels": "c", "values": 3}
    {"labels": "c", "values": 2}
    {"labels": "c", "values": 1}
    ```

## データの読込

ちなみに、データをファイルから読み込む場合は以下のようにします

```elixir
file_input =
  "Data file"
  |> Kino.Input.file()
  |> Kino.render()
  |> Kino.Input.read()

if is_nil(file_input) do
  Kino.interrupt!(:normal, "Upload data file!")
end

file_input
|> Map.get(:file_ref)
|> Kino.Input.file_path()
|> Explorer.DataFrame.from_csv!()
```

![スクリーンショット 2023-07-17 23.02.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/df73288a-81d3-0565-19aa-dda999d763ad.png)

ファイルを選択して "Continue" をクリックすると、読み込まれます

![スクリーンショット 2023-07-17 23.03.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/ee7979a4-94b8-20b9-2e7c-c94536502df2.png)

NDJSON の場合は最終行を `|> Explorer.DataFrame.from_ndjson!()` 、 Parquet の場合は `|> Explorer.DataFrame.from_parquet!()` に変更してください

## まとめ

Livebook では画像表示やデータ入出力など、 UI/UX をほとんど Kino や Kino シリーズのモジュールがやってくれます

そのため、ユーザーはデータ解析などの実装に集中することが可能です