source関数で自作関数を呼び出す

R
Analysis
Tips
作者

azumaya

公開

2024年8月24日

はじめに

自作関数をはじめ、他ファイルで定義したオブジェクトを簡単に呼び出したい。

source関数を使って、ファイルの壁を飛び越える。

関数を自作した

前回、記述統計表を出力する関数summary_stats()を自作した。

summary_stats <- function(df, g) { 
  # gをシンボルに変換
  g <- rlang::enquo(g)
  
  # グループごとのサンプル数を計算
  n <- df %>% 
    filter(Species == !!g) %>% 
    nrow()
  
  df %>%
    filter(Species == !!g) %>% #
    summarise(across(where(is.numeric), 
                     list(Mean = ~ mean(.x, na.rm = TRUE),
                          S.D. = ~ sd(.x, na.rm = TRUE),
                          Min. = ~ min(.x, na.rm = TRUE),
                          Max. = ~ max(.x, na.rm = TRUE)),
                     .names = "{col}-{fn}")) %>% 
    round(2) %>% 
    format(nsmall = 2) %>% 
    pivot_longer(cols = everything(), 
                 names_to = c("variable", "stat"), 
                 names_sep = "-") %>% 
    pivot_wider(names_from = stat, 
                values_from = value) %>% 
    cbind(num = c(1:4),.) %>% 
    gt() %>% 
    cols_label(num = "",
               variable = "") %>% 
    tab_header(title = rlang::as_name(g)) %>%  # タイトルにグループ名gを指定
    tab_options(heading.align = "left") %>%   
    tab_footnote(footnote = paste("*",n, "observations.")) # サンプル数nをここで使う
}

自作関数をいつでも使いたい

なぜ呼び出したい?

1. 一度作った関数を何度も使いたい

頑張って関数を作ったはいいものの、これを毎回コピペするのは面倒。 これみなさんどうしているんでしょうか。

自作関数を集めたRファイルを作っていつでも呼び出せるようにしておくと便利な気がしている。

他にもグラフ描画だったり、相関行列のテンプレにも応用できそう。 グラフによく使うカラーパレットを指定しておいたり。(.scssの設定みたいだな)

2. .qmdに長いコードを書きたくない

雑多な分析を.Rで行い、その一部を取り出して.qmdのプレゼンテーションやドキュメントにまとめたい場面が多々ある。

そんな時、.qmd上で長々と複雑なコードを書きたくないというのが正直なところ。 レンダリングに時間がかかるし、書き換え忘れのエラーが面倒だし、cacheオプションが使いこなせていない…。

今回作ったような自作関数だけでなく、もはやオブジェクトのすべてを呼び出せた方がありがたい。

呼び出してみる

自作関数含むオブジェクトは、source関数で呼び出せる。

source関数がないとき

functions.Rに作った関数summary_stats()を使いたいとき、fuga.qmd上で直接定義していない場合はエラーとなる。

fuga.qmd
summary_stats(df)
Error in summary_stats(df): could not find function "summary_stats"

source関数があるとき

fuga.qmd上で、summary_stats()を定義したfunctions.Rを呼び出すことで関数を使えるようになる。

fuga.qmd
source("./functions.R")

functions.Rを開いたときのEnvironmentペインが再現されるみたいなイメージと認識している。 そのため、関数以外にも変数やデータがそのまま使えるようになる。

functions.Rのコードを全て実行するので、あまりにも重いと時間がかかるし、ここでエラーが出ると先に進めない。 上から下まで順番に実行されることを前提で、変数名の定義やコメントアウトを上手いことする必要がある。

ほかの発想?

source()では、.Rを上から下まで実行してオブジェクトを呼び出していたけど、functions.Rのオブジェクト自体を保存して、それを呼び出す方法もある。

functions.R上で作ったsummary_stats()saveRDS()で保存しておく。 引数に変数名を入れて実行すると、summary_stats.objが作成される。

functions.R
saveRDS(summary_stats)

fuga.qmd上で使いたい場合は、readRDS()で呼び出して変数に代入する。

fuga.qmd
summary_stats <- readRDS("./summary_stats.obj")

source()と違って、.Rファイルの中身を実行するわけではないので、時間は短縮できる。 ただ、summary_stats()の定義を書き換えた場合、同時にsaveRDS()も実行しないとsummary_stats.objの中身が上書きされない。自作関数が増えていくと全然面倒かも。

おわりに

ファイルをまたいで呼び出したい内容によって、いろいろな方法がありそう。

雑多な分析の.Rと、きれいにまとめたい.qmdの行き来が永遠の課題だ~~~。

cacheオプションを使いこなすしかないのか。