niszetの日記

細かい情報を載せていくブログ

(R) skimrの表示をカスタマイズしたい 2回目

histをもっと幅広く表示させたい気持ちが起点。

さて前回、skimrパッケージのskim_with()関数にてskim()関数の表示のさせ方を変えてみました。

niszet.hatenablog.com

しかし、skim()のhistは他の関数と違って少し独特なのでこれをもう少し使いこなしたい気持ちになります。

ひとまずヒストグラムだけを表示させてみます。これはinline_hist()で出来ます。引数にはdata.frameは渡せず、vectorを与える必要があります。

> skimr::inline_hist(iris$Sepal.Length)
▂▇▅▇▆▅▂▂

なお、この関数は先に表示したskimmersの中にある関数と同じ、つまりskim()で表示するときに使用される関数と等しいわけですね。

# 以下で確認。
identical(skimr::get_skimmers()[["numeric"]][["hist"]], skimr::inline_hist)
#> [1] TRUE

さて、中身を見てみます。

View(inline_hist)

# 以下はView()での表示の結果を張り付けたもの
function (x) 
{
  if (length(x) < 1 || all(is.na(x))) 
    return(structure(" ", class = c("spark", "character")))
  if (all(x == 0)) 
    x <- x + 1
  hist_dt <- table(cut(x, options$formats$character$width))
  hist_dt <- hist_dt/max(hist_dt)
  structure(spark_bar(hist_dt), class = c("spark", "character"))
}

ここで、下から3行目で幅を制御しているらしいことが読み取れますが、skimr:::options内の環境の値を引き抜いているため、この部分を変えることが出来ません1。 そこで、この関数をコピーして編集、引数で表示幅を変えることが出来るようにしたものを作ってみます。

こんな感じ。

my_hist <- skimr::inline_hist
my_hist <- edit(my_hist)

edit()で対象の関数をエディタで書き換えることが出来ます。修正内容は改めて代入しないといけません(2行目) edit()で修正したあとのmy_hist() の中身はこんな感じです。引数にwidを加え、デフォルト値として8を与えておきます。これはskimrのデフォルトの値でした。

function (x, wid=8) 
{
  if (length(x) < 1 || all(is.na(x))) 
    return(structure(" ", class = c("spark", "character")))
  if (all(x == 0)) 
    x <- x + 1
  hist_dt <- table(cut(x, wid))
  hist_dt <- hist_dt/max(hist_dt)
  structure(skimr:::spark_bar(hist_dt), class = c("spark", "character"))
}

関数内部については差異を見てもらえればわかると思いますが、options$formats$character$widthを関数の引数widに置き換えただけです。

もともと、histはskimr::inline_hist()関数と同じものが使われていて、その実行結果はコンソール上にそのまま出力されるました。つまりここで作成した関数単体で使用すれば同じようにコンソール上に表示されるわけですね。やってみます。

> my_hist(iris$Sepal.Length, 20)
▂▂▃▇▆▁▆▇▅▆▂▇▃▆▂▁▂▁▂▁

こんな感じ。うーむ、irisだといまいち便利なのかどうなのか良く分かりませんな…。ひょっとしたら役に立つ場面があるのではと思いますが。 この自作histをskim()の仲間に加える、skim_with()の使い方については前回の記事を参照してください。

おわりに

ということで、skimrパッケージで表示をカスタマイズするというお話でした。

なお、skimは任意の型に対して関数を定義すれば表示をカスタマイズできますし、skim自体も総称関数です。
もう一歩踏み込んだ内容としては、vignette

vignette("Supporting_additional_objects")

で見れます。まぁ、今回の話に限らずですがvignette充実しているのでそちらを読めば大体わかってしまうような。。。

skim()は現時点で実装されているものはskimr:::skim.data.frame()skimr:::skim.default()skimr:::skim.grouped_df()だけのようですね。そのため、listを与えるとうまく表示してくれません。必要であれば自分で定義するとかですかね。うーむ、あまり必要はない?

ということで、skimrパッケージのinline_hist()のような関数を自分でカスタマイズして使ってみるお話でした。

Enjoy!!


  1. 多分…。パッケージ内のName spaceにある環境オブジェクトの値って変更出来ますかね…?多分出来ないはず…。