備忘ログ

チラシの裏的備忘録&メモ

RStudioのCheck for Package Updatesはupdate.packages()と微妙に挙動が異なる ほか2本

R関係で最近知った些末なことをメモしておく。一つずつ書くほどでもないので三本建て。

RStudioのTools > Check for Package Updatesはupdate.packages()と微妙に挙動が異なる

RStudioを使っていてRのパッケージに更新があるか確認しようと思ったときにRStudioの提供する機能を使って、上のメニューのTools > Check for Package Updatesでチェックするか、PackagesのペインにあるUpdateのボタンをクリックしてチェックすることができる。

RStudioのCheck for Package Updateはold.pakages()で表示できる今インストールされている更新があるパッケージとインストール中のバージョン番号と新バージョンのバージョン番号を比較表示してくれるだけでなく、CRANのwebページ上でパッケージのNEWSが見られる場合はNEWSをクリックするとそのページに飛ぶことができ更新情報をすぐに確認できるというのがとてもいいと個人的には感じている。

これは勝手に、update.packages()GUI版(ラッパー的なもの)なのかな、などと思っていたが微妙にそうではなく、RStudioのTools > Check for Package Updatesで更新の有無の確認対象となるパッケージは一般ユーザー(管理者権限じゃないという意味)でRStudioを起動するとUser Libraryにインストールしているパッケージだけで、System Libraryは範囲外となる様子。管理者としてRStudioを実行(スーパユーザーとして実行)するとSystem Libraryも確認対象となる模様で、その時のファイルパーミッションで更新できるパッケージのみが更新の有無の確認対象となる様子。

一方でupdate.packages()は特に指定しないと、一般ユーザーで実行しても.libPaths()で検索できるパッケージがインストールされているディレクトリすべて、つまりUser Libraryに加えて、System Libraryもアップデートの対象になる。ただし、一般ユーザーではファイルパーミッションの関係でSystem Libraryのパッケージは更新できずエラーになるので、結局System Libraryのパッケージを更新する場合には管理者として実行(スーパユーザーとして実行)することが必要になる。

結局System Libraryのパッケージを更新するすためには管理者権限が必要になるのは双方変わりないが、RStudioのTools > Check for Package UpdatesではそもそもSystem Libraryにインストールされているパッケージにアップデートがあるかどうかすら確認されないので、普段一般ユーザーとしてRStudioを使っていてTools > Check for Package Updatesだけでパッケージのアップデートを行っている場合はSystem Libraryにインストールされているパッケージにアップデートがあるのかどうかもわからない。

この差はR本体をリリースごとにアップデートして使っている範囲ではほとんど気にする機会はなくR本体のアップデートのタイミングでSystem Libraryのパッケージもアップデートされるので多くの場合はそのタイミングのアップデートで問題ないが、極稀にR本体のリリース間でSystem Libraryにインストールされているパッケージがアップデートされていないためにトラブルが起こるということを経験するとちょっと嵌まる。

たとえばこの間経験した、{lme4}など。

indenkun.hatenablog.com

これは{Matrix}が1.6-2以前と以降でバイナリ互換性がないためのよう。

stackoverflow.com

現状としては、普段一般ユーザー(管理者権限じゃないという意味)としてRStudioを使用している場合はこの問題に嵌りたくないのであれば、たまにold.packages()で、System Libraryを含めたパッケージの更新の有無を確認するしてSystem Libraryのパッケージのアップデートがあれば管理者権限でRやRStudioを起動してパッケージをアップデートするしかないかもしれない。

または管理者権限でRStudioを起動するスタイルにするというのも手だが、個人的には管理者権限でなくても基本的には問題なく動くソフトウェアを常に管理者権限で動かすのは運用上自分の好みではないので微妙である。

この件については実環境的には、User Libraryを指定しているディレクトリのパーミッションなど個別の環境依存の問題があり、それぞれで多少事情は異なるとは思う。

::で関数を呼び出してもパッケージはロードされている

今まで勝手に、library()を使わずに::をつかってパッケージの関数を呼び出したときには、パッケージの::で呼び出した関数をそのタイミングだけ読んで、あとはさっと捨てているのかと思いこんでいた(呼び出したタイミングだけふわっとでてきて、終わったらふわっと消えていくイメージ)。

しかし、挙動をよく見ると::でパッケージの一部関数を呼び出すとパッケージがロードされている模様。

ドキュメントにも次のようにちゃんと書いている。

For a package pkg, pkg::name returns the value of the exported variable name in namespace pkg, whereas pkg:::name returns the value of the internal variable name. The package namespace will be loaded if it was not loaded before the call, but the package will not be attached to the search path.

つまり検索パスにattachされないだけで、ちゃんとロードされているとのこと。

Hadley WickhamのR Packagesにも

Loading will load code, data, and any DLLs; register S3 and S4 methods; and run the .onLoad() function. After loading, the package is available in memory, but because it’s not in the search path, you won’t be able to access its components without using ::. Confusingly, :: will also load a package automatically if it isn’t already loaded.

ってちゃんと書いてる。

r-pkgs.org

ロードされているから::で読み込んだパッケージのS3、S4クラスのジェネリック関数のメソッドも登録される。

たとえば、{ggplot2}::で読み込む前は、

methods(`+`)
## [1] +.Date   +.POSIXt
## see '?methods' for accessing help and source code

となるが、適当に1回でも{ggplot2}::で読み込んだだけで+.ggなどの{ggplot2}などで定義されるジェネリック関数のメソッドが登録されている。

ggplot2::qplot(Sepal.Length, Sepal.Width, data = iris)
## Warning: `qplot()` was deprecated in ggplot2 3.4.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

methods(`+`)
## [1] +.Date        +.gg*         +.glue*       +.POSIXt      +.vctrs_vctr*
## see '?methods' for accessing help and source code

たしかに、::でパッケージを呼び出した関数しか使えなかったらそもそも、qplot()でつくったggplotオブジェクトを描画するplot()の適当なメソッドがなくうまい具合に表示されないことになってしまう。

{purrr}パッケージのmap_df()系がsupersededになった理由について最近知った

{purrr}パッケージが今年頭辺りに1.0.0になったときにmap_df()系の出力がデータフレームにできるmapファミリー関数がsupresededになった。

データフレームを直接出力してくれるので便利であったがsupresededになって、代替案として新たな関数が用意されるのではなくmap()で出したリストをlist_rbind()などで結合すべしとのことで手間が一つ増えた印象だった。

ドキュメントには

The functions were superseded in purrr 1.0.0 because their names suggest they work like ⁠_lgl()⁠, ⁠_int()⁠, etc which require length 1 outputs, but actually they return results of any size because the results are combined without any size checks.

と書いてあるが、いまいちよく分からなかった。

そんなふうに思っていたらPosit社のYoutubeチャンネルにあるHadley氏の{purrr}について話している動画がRecomendされて来たので見る機会があった。

www.youtube.com

だたい11分10秒くらいからmap_df()系の話をしているのだけど、要約すると「『map系関数は入力した値の長さと同じ長さの値を返すべき』という設計に基づくとmapとして不適切だろ、というわけでsupresededな」ということのよう。

統一感とか設計思想って大事だよね、と思った。