RとRStudioのmacOSでのインストール

Homebrewをインストールしている前提で。mac環境構築参照。

brew cask install r-app rstudio

で終了。

Rの種類

macOSでHomebrewを用いてインストールできるのは

  1. brew install rでインストールされるR
  2. brew cask install r-appでインストールされるR for Mac OS Xと基本的に同じもの

の2種類になる。1. のbrew install r版はopenblasなどでカスタムができること、brew doctorでWarningが出ないメリットがあるが、CRAN的には非公式ビルド扱いのためにパッケージのインストールの際に毎回ソースからビルドすることになる。という大きなデメリットがある。またtcl/tkサポートがない?ためEZRがうまく動かなかったような記憶がある。EZRに関してはplotの出力の問題もあり、仮想マシンを使うなどしてWindows版を利用するのがスムーズではある。

一方2. のbrew cask install r-appでインストールされる方は基本的には公式ビルドのためパッケージのインストールなどで問題は生じない。代わりに一緒にインストールされるtcl/tkなどがあまりお行儀が良くないらしく、以下のようなbrew doctorでのWarningがでるようになってしまう。Warningを消すにはこれらのファイルを削除するしかないが、消さなくてもとりあえず気づけるような問題は生じていないのでそのままにしている。

$ brew doctor
Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry or file an issue; just ignore this. Thanks!

Warning: Unbrewed dylibs were found in /usr/local/lib.
If you didn't put them there on purpose they could cause problems when
building Homebrew formulae, and may need to be deleted.

Unexpected dylibs:
  /usr/local/lib/libtcl8.6.dylib
  /usr/local/lib/libtk8.6.dylib

Warning: Unbrewed header files were found in /usr/local/include.
If you didn't put them there on purpose they could cause problems when
building Homebrew formulae, and may need to be deleted.

Unexpected header files:
  /usr/local/include/fakemysql.h
  /usr/local/include/fakepq.h
  /usr/local/include/fakesql.h
  /usr/local/include/itcl.h
  /usr/local/include/itcl2TclOO.h
  /usr/local/include/itclDecls.h
  /usr/local/include/itclInt.h
  /usr/local/include/itclIntDecls.h
  /usr/local/include/itclMigrate2TclCore.h
  /usr/local/include/itclTclIntStubsFcn.h
  /usr/local/include/mysqlStubs.h
  /usr/local/include/odbcStubs.h
  /usr/local/include/pqStubs.h
  /usr/local/include/tcl.h
  /usr/local/include/tclDecls.h
  /usr/local/include/tclOO.h
  /usr/local/include/tclOODecls.h
  /usr/local/include/tclPlatDecls.h
  /usr/local/include/tclThread.h
  /usr/local/include/tclTomMath.h
  /usr/local/include/tclTomMathDecls.h
  /usr/local/include/tdbc.h
  /usr/local/include/tdbcDecls.h
  /usr/local/include/tdbcInt.h
  /usr/local/include/tk.h
  /usr/local/include/tkDecls.h
  /usr/local/include/tkPlatDecls.h

Warning: Unbrewed .pc files were found in /usr/local/lib/pkgconfig.
If you didn't put them there on purpose they could cause problems when
building Homebrew formulae, and may need to be deleted.

Unexpected .pc files:
  /usr/local/lib/pkgconfig/tcl.pc
  /usr/local/lib/pkgconfig/tk.pc

Warning: Unbrewed static libraries were found in /usr/local/lib.
If you didn't put them there on purpose they could cause problems when
building Homebrew formulae, and may need to be deleted.

Unexpected static libraries:
  /usr/local/lib/libtclstub8.6.a
  /usr/local/lib/libtkstub8.6.a

Rの起動手順と設定ファイル

help("Startup")
  1. .Renviron--no-environでスキップ)
    1. $R_ENVIRON
    2. $R_HOME/etc/Renviron.site
    3. $R_ENVIRON_USER
    4. ./.Renviron
    5. ~/.Renviron ←これを用意している
  2. Rprofile.site(あれば。--no-site-fileでスキップ)
    1. $R_PROFILE
    2. $R_HOME/etc/Rprofile.site
  3. .Rprofile--no-init-fileでスキップ)
    1. $R_PROFILE_USER.Renvironで設定しているとこれが優先される
    2. ./.Rprofile ←するとプロジェクト毎のこれが読み込まれていなかった
      • このプロジェクト.Rprofile中でsource("packrat/init.R")によりpackratが起動
    3. ~/.Rprofile
  4. ./*.RDataの読み込み(あれば。--no-restore-dataでスキップ)
  5. .First関数が定義されていれば実行される
  6. (baseの).First.sys()関数が実行される
    • options("defaultPackages")のパッケージ群をrequireする
    • methodsパッケージが含まれていると先に.OptRequireMethods()で読み込まれてnamespaceの初期化が正しく行われる、らしい

なおR --vanillaとすると--no-site-file, --no-init-file, --no-environ and (except for R CMD) --no-restoreの扱いになるので問題の切り分けをしたいときに。

.Renviron

R起動時に読み込まれ、環境変数を設定するファイル。

読み込まれる順番は上記のようになっており、プロジェクト(カレントディレクトリ)では通常は作られないので最後の~/.Renvironが読み込まれることになる模様。この後に.Rprofileの読み込みになり、その際にはこのファイル内でR_PROFILE_USERを設定していると優先される。

.Rprofile

や各所を参考に作っている。

.Rprofileの読み込み確認

最初と最後にメッセージを表示させることで、こっそりエラーになって止まっていても気づけるようにしておく。

message("\n*** Loading user .Rprofile (~/.Rprofile) ***\n")

...

message("*** Successfully loaded user .Rprofile ***\n")

パッケージのインストールパス

.RenvironR_LIBS_USERとともに.libPathsを設定する。「パッケージのインストール先」と「インストールされたパッケージの読込先」を両方とも設定しておく必要がある模様。R_LIBS_USERは読込先、.libPathsはインストール先の指定になる?。これらの設定はpackrat管理の初期化処理で上書きされるため、プロジェクトの.Rprofileとの読み込み順に注意が必要になる。.Renvironの設定にも依存するが、自分の設定ではR_PROFILE_USERが設定されているため、その中でこのインストールパス処理してから下記のプロジェクトの.Rprofile読み込みが行われるようにしている。

install.packagesでインストールするpathを変更する - Qiita

なんか設定してもうまくいかないと思ったらあらかじめディレクトリは作っておく必要がある(存在しないディレクトリは読み込まない)のが原因だった。エラーは出してくれない。.Renviron$R_LIBS_USERを、.Rprofile.libPaths()を設定。

# set .libPaths to "~/.R_LIBS"
if (dir.exists(file.path("~", ".R_LIBS")) || dir.create(file.path("~", ".R_LIBS"))) {
  .libPaths(file.path("~", ".R_LIBS"))
} else {
  warning("\n******* .libPaths was undefined !!! *******\n")
}

なおこっそり.bashrcにも入れている。ついでにaliasもここに記載。

# create directory for installed packages
if [ ! -d ~/.R_LIBS ]; then
    mkdir ~/.R_LIBS
    echo "Created '~/.R_LIBS' for R_LIBS_USER."
fi

alias R='R --no-save --no-restore-data'

CRANのレポジトリ設定

brew cask install r-appの方を使っている分には基本的には問題なくCRANのバイナリが利用できるはずだが、それだけでは足りないものもあるようで、bookdownパッケージほか多くのパッケージ作者でもあるYihui Xie氏の用意してくているCRANextra用のサーバーがあるようなのでそちらも設定。

# CRAN repos from rstudio and extra from macos.rbind.org by Yihui Xie
options(repos = c(
  CRAN = 'https://cran.rstudio.com',
  CRANextra = 'https://macos.rbind.org'
))

プロジェクトの.Rprofile読み込み設定

~/.Renviron$R_PROFILE_USER~/.Rprofileに設定し、カレントディレクトリの./.Rprofileよりも優先して読み込むようにしているため、プロジェクトの.Rprofileが存在しても~/.Rprofileが常に読み込まれることになる。特にPackratで管理しているプロジェクトでは(プロジェクトのルート)/.Rprofile

#### -- Packrat Autoloader (version 0.4.9-8) -- ####
source("packrat/init.R")
#### -- End Packrat Autoloader -- ####

のような初期化処理が追記されているため、気づかずにいるとPackrat管理しているつもりで何もしていなかったということになりかねない(なった)。そのため以下のコードを$R_PROFILE_USER(実質~/.Rprofile)のインストールパスの設定よりあとかつ起動時のパッケージ追加処理より前に入れてプロジェクトの.Rprofileを読み込むようにしている。またR --vanilla環境ではSys.getenv("R_USER")""を返すため、無限ループにハマらないようにunset = getwd()を入れている。

# source projectdir/.Rprofile
# R --vanilla returns "" to Sys.getenv("R_USER")
if ((Sys.getenv("R_USER", unset = getwd()) != getwd()) && (file.exists(file.path(getwd(), ".Rprofile")))) {
  message("* Project .Rprofile is detected. *\nLoading Project .Rprofile...")
  source(file.path(getwd(), ".Rprofile"))
  message("Successfully loaded Project .Rprofile\n")
}

起動時に追加でパッケージを読み込む

.Rprofileにlibrary(tidyverse)とすると、

  1. .Rprofileでtidyverseを読み込む
  2. .First.sys()options("defaultPackages")のパッケージをロードする

の順になるためbase::search()でのパスの順番が変わり、dplyr::filter()ではなくstats::filter()が優先されてしまったりする。そのため、“defaultPakcages”に追記する形をとる必要がある。

options(defaultPackages = c(getOption("defaultPackages"), "tidyverse"))

ただしこれだとPackratを利用するプロジェクトなど、指定したパッケージがインストールされていない場合にはエラーが出てしまう。これを抑制するためにrequireNamespace(x, quietly = TRUE)を用いてインストールされているか判定し、存在するものだけを加えるようにしていたが、requireNamespaceではPackrat管理下のプロジェクトにパッケージがインストールされていなくてもTRUEが返ってしまう。 require()suppressWarnings()suppressMessages()を使えば余分な表示は消せるが、結局.First.sys()で外部パッケージを読み込ませていると、そのあとに立ち上がるpackrat環境ではインストールされていないのでafterPackratModeOn -> cleanSearchPath -> forceUnload -> unloadNamespaceのようなエラーが出る……。しかも先にrequireを呼び出してしまうせいか結局元々の"defaultPackages"よりも先に追加パッケージがsearch()のパスに入ってしまう。

  • requreNamespaceだとpackrat環境でのみ問題が生じる
    • .Rprofileを実行している時点ではインストールされていると判断される
    • その後のpackratが読み込まれた環境ではインストールされていないのでエラー
  • もしかしたらこの処理の前にプロジェクトの.Rprofileを読み込んでpackratの読み込み処理をさせるとうまくいく?

解決方法として

  1. Packrat環境の時は何も追加しない
  2. Packrat環境でなければrequireNamespaceを利用して(も問題ないので)requireの順番を崩さずにインストールされているかだけチェックして追加

の処理にすることで解決できる。

Packrat環境かどうかを確認するには!is.na(Sys.getenv("R_PACKRAT_MODE", unset = NA))が使えるはずなのだが、これはpackratが開始してからしかわからない。packratの読み込みはプロジェクトの.Rprofile中のsource("packrat/init.R")で行われるので、先にプロジェクトの.Rprofile読み込みを行っておけば正しく判定可能になる。読み込み前だと常にFALSEになってしまう。代替手段としてはgetwd()/packrat/init.Rpackrat.lockが存在するかどうかで判定する。Packrat環境の場合はdefaultPakagesはいじらずに、プロジェクトの中でインストールおよび読みこむパッケージを管理するようにする。Packratの使用目的からもこの方が道理にかなっているだろう。大人しくセットアップファイルでも作って管理することにする。先にプロジェクトの.Rprofileを読み込んでいる前提なので、そちらか.RenvironSys.setenv("NO_ADDITIONAL_PACKAGES" = TRUE)NA以外なら何でも)を設定しておけば追加処理をスキップできるようにしてある。

if (!is.na(Sys.getenv("R_PACKRAT_MODE", unset = NA))) {
  message("* This project is under control of packrat. No additional packages will be loaded in global .Rprofile. *\n")
} else if (!is.na(Sys.getenv("NO_ADDITIONAL_PACKAGES", unset = NA))) {
  message("* This project is set to use 'defaultPackages'. No additional packages will be loaded in global .Rprofile. *\n")
} else {
  local({
  original_default <- getOption("defaultPackages")
  pkgs <- c("tidyverse", "magrittr", "skimr")
  pkgs <- pkgs[sapply(pkgs, function(x) {return(ifelse((requireNamespace(x, quietly = TRUE)), TRUE, FALSE))})]
  options(defaultPackages = c(original_default, pkgs))
  message(paste0("* These additional packages will be loaded. *\n", paste(pkgs, collapse = ", "), "\n"))
})
}

一応require版もメモとして取っておく。こちらだとgetOption("defaultPackages")で得られるリストは全く同じものになるが、先にrequire()してしまうせいかnamespace initializationがうまく行かず、filter()dplyr::filter()ではなくstats::filter()が呼び出される状態になってしまう。

pkgs[sapply(pkgs, function(x) {return((suppressMessages(suppressWarnings(require(x, character.only = TRUE)))))})]

Packratを使用しているかの判定がSys.getenv("R_PACKRAT_MODE")ではsource("packrat/init.R")処理前の時点ではうまくいかないことを確認するためのコード。

# .Rprofileに書いてもpackrat起動前なので常に"Not Packrat!"になってしまう
if (!is.na(Sys.getenv("R_PACKRAT_MODE", unset = NA))) {
  message("Packrat!")
} else {
  message("Not Packrat!")
}

プロジェクトで終了時にセッション情報を記録する

R for Enterprise: Understanding R’s Startup · R Views

の下の方の「Record sessionInfo automatically」を元にrstudioapiを使わなくてもいいように改造。ただし.Last起動時(RStudio終了時)にgetwd()がプロジェクトルートから変わっていないことを前提にしている。

.Last <- function(){
  if (interactive() && !is.na(Sys.getenv("RSTUDIO", unset = NA)) && as.logical(sum(grepl(".Rproj", list.files())))) {
     ## append date + sessionInfo to a file called sessionInfoLog
    cat("Recording session info into the project's sesionInfoLog file...")
    info <- capture.output(sessionInfo())
    info <- paste("\n----------------------------------------------",
                  paste0('Session Info for ', Sys.time()),
                  paste(info, collapse = "\n"),
                  sep  = "\n")
    f <- file.path(getwd(), "sessionInfoLog")
    cat(info, file = f, append = TRUE)
  }
}

CPUコア数の設定

Speeding up package installation | R-bloggers Use parallel option of boot function in R - Stack Overflow

parallelパッケージとかもあるが、ここではinstall.packages()boot用のオプションのみ。CPUコア数は以下のコードで。

parallel::detectCores()
## [1] 8

install.packagesNcpus Argumentの説明より

the number of parallel processes to use for a parallel install of more than one source package. Values greater than one are supported if the make command specified by Sys.getenv(“MAKE”, “make”) accepts argument -k -j Ncpus.

boot::bootncpus Argumentの説明より

integer: number of processes to be used in parallel operation: typically one would chose this to the number of available CPUs.

# set CPU cores to use in install.packages and boot::boot
# to know the number of cores in your PC, use parallel::detectCores()
options(Ncpus=4,
        boot.ncpus=4)

# set boot parallel method
# options(boot.parallel="multicore")

環境変数

一覧を見るには

Sys.getenv()