15
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ExplorerのTidyverseシリーズをアップグレード

ElixirのNx Explorerが出たから半年が過ごして、新しいバージョン(0.4.0)が出ました。@RyoWakabayashiさんの「Queryを使うと、データ分析が更に捗る」記事を読んだから、私の「Explorer: LivebookでTidyverseの再訪」の記事も更新したくなりました。

では、始めましょう。

セットアップ

新しいLivebookのセッションを開いて、「Notebook dependencies and setup」に以下のモジュールをインストールします。

Mix.install([
  {:kino, "~> 0.7.0"},
  {:explorer, "~> 0.4.0"},
  {:download, "~> 0.0.4"}
])

両方:kino:explorerのバージョンが上げました。実行して、準備が終わりました。

データをインポートする

次は、データをインポートして、データフレームにロードしましょう。

alias Explorer.DataFrame, as: DF
alias Explorer.Series, as: S
alias Kino.DataTable
# Explorer.Queryのマクロのためにこの行が必要です。
require Explorer.DataFrame

# データファイルがローカルに保存されてない場合、読みます。
unless File.exists?("balls-in-play-2022.tsv"),
  do:
    {:ok, _filename} =
      Download.from(
        "https://raw.githubusercontent.com/westbaystars/first-pitch-homeruns/main/balls-in-play-2022.tsv"
      )

df = DF.from_csv!("balls-in-play-2022.tsv", delimiter: "\t")
#Explorer.DataFrame<
  Polars[13453 x 10]
  Player string ["Walker, Adam", "Walker, Adam", "Nakajima, Hiroyuki", "Nakajima, Hiroyuki",
   "Ohshiro, Takumi", ...]
  選手 string ["ウォーカー アダム", "ウォーカー アダム", "中島 宏之",
   "中島 宏之", "大城 卓三", ...]
  Team string ["YOM", "YOM", "YOM", "YOM", "YOM", ...]
  Date string ["2022-04-23", "2022-04-23", "2022-04-23", "2022-04-23", "2022-04-23", ...]
  Game integer [71798, 71798, 71798, 71798, 71798, ...]
  Pitch string ["curve", "split-finger", "cutter", "split-finger", "cutter", ...]
  Pitches integer [2, 4, 3, 3, 5, ...]
  Velocity integer [nil, nil, 130, 134, 125, ...]
  ResultType string ["hit", "hit", "hit", "hit", "hit", ...]
  Result string ["single", "double", "single", "double", "single", ...]
>

今まで、何も変わってません。利用するデータフレームを読みました。表で表示しましょう。

df
|> DataTable.new()

image.png

よっしゃ~。データをきれいに表示しています。

ホームランを集計する

以前のバージョンではDF.filter_with(...)が関数のコールバックパラメータがちょっと複雑でした。:explorer 0.4.0Queryのおかげでより読みやすくなります。

最初は0.3.0でこうしました:

df
|> DF.filter_with(&S.equal(&1["Result"], "home-run"))
|> DF.group_by(["選手", "Team"])
|> DF.summarise(Pitches: [:count])
|> DF.rename(Pitches_count: "本塁打")
|> DF.arrange(desc: "本塁打")
|> show_table.()

今度は:

df =
  df
  |> DF.rename_with(&String.downcase/1)
  |> DF.filter(result == "home-run")
  |> DF.group_by(["選手", "team"])
  |> DF.summarise(本塁打: count(pitches))
  |> DF.arrange(desc: 本塁打)

df |> DataTable.new()

image.png

それぞれのデータフレームの関数がQueryパラメータを取得して、マクロでシリーズ(Explorer.Series)の関数を呼んでいます。この読み方のほうがだいぶ書きやすくて、読みやすくなりました。

でも、注意点があります。

df
|> DF.rename_with(&String.downcase/1)
|> DF.filter(result == "home-run")
...

Resultという列名が変数に使えなさそうです。小文字のresultに変更するとマクロがうまく動いています。しないと、「型が違います」エラーがありました。

DF.group_byが変わってないので、そのままで行います。

DF.summarise(本塁打: count(pitches))Queryを利用して、シリーズの関数を書いて、変数のような列名をパラメータを取ります。この書き方がいいですよ。

最後に、DF.arrange(desc: 本塁打)では「本塁打」にクォートが必要なくなりました。そうです、Queryのパラメータです。先頭文字が大文字がなくて、漢字を使えそうですよ!

チーム名を漢字に変更しましょう

以前、チームを日本語にmutateするためにElixirのマップを利用することができました。

teams = %{
 "CHU" => "中", "HAN" => "阪", "HIR" => "広",
 "YAK" => "ヤ", "YOK" => "De", "YOM" => "巨",
 "LOT" => "ロ", "NIP" => "日", "ORX" => "オ",
 "RAK" => "楽", "SEI" => "西", "SFT" => "ソ"
}

...
|> DF.mutate([チーム: &S.transform(&1["Team"], fn team -> Map.get(teams, team) end)])
|> DF.group_by(["選手", "チーム"])

パイプラインにmutateを挿入して、「Team」から「チーム」の列で組み合わせました。

でも、もうExplorer.Backend.LazySeriesの関数(例えばmutate, filter, transform)でEnum, Map, などが使えなくなりました。どうすればElixirのマップを利用してmutateができると悩みました。

色々試してみて、やっとできました。必要なことはデータフレームから列をpullして、そのシリーズを使って、データフレームにputして、データフレームを戻す関数を作りました。何でも列をリマップすることができます。

teams = %{
  "CHU" => "中",  "HAN" => "阪",  "HIR" => "広",
  "YAK" => "ヤ",  "YOK" => "De",  "YOM" => "巨",
  "LOT" => "ロ",  "NIP" => "日",  "ORX" => "オ",
  "RAK" => "楽",  "SEI" => "西",  "SFT" => "ソ"
}

mutate_with_map = fn df, column, map, new_label ->
  new_series =
    DF.pull(df, column)
    |> S.transform(fn key -> Map.get(map, key) end)

  DF.put(df, new_label, new_series)
end

df
|> mutate_with_map.("team", teams, :チーム)
|> DF.select(["選手", "チーム", "本塁打"])
|> DataTable.new()

image.png

前より作業が必要ですが、まだわかりやすいと思います。

まとめ

大体3ヶ月づつでExplorerが更新しています。いつも新しいバージョンが良くなっています。0.3.0のときに「warning: mutate/2 with a callback is deprecated, please use mutate_with/2 instead」を心配しましたが、自分の関数でパイプラインで続ける方法を研究してよかった。

3月後でもっと強くなると信じてます。

15
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?