株式会社ホクソエムのブログ

株式会社ホクソエムのブログ

RStudioServer から ShinyApp を直接デプロイしたい

現在 CentOS 7.5 サーバーに RStudioServer と ShinyServer を入れて RStuidio 上で ShinyApp を書いています。

デプロイするには /srv/shiny-server/ の下にフォルダを丸ごとコピーしていますが、サーバにいちいちログインするか RStudio の新機能である Terminal 上でコピーしちゃうんですが、これを R でやりたいというのが今日のお題です。

適当に書くと次のようになると思います。

deploy_shiny_app <- function() {
  # 現在のワーキングディレクトリに ShinyApp があるとする
  dir_path <- getwd()
  # ShinyApp のデフォルトのデプロイ場所は /srv/shiny-server/
  target_dir_path <- file.path("/srv/shiny-server", basename(dir_path))
  # ShinyApp のフォルダにある .R ファイルを全て取得
  files <- list.files(dir_path, pattern = "\.R$", full.names = TRUE)
  # sudo cp コマンドで全てコピー
  command <- sprintf("sudo cp -vfu %s %s", paste(files, collapse = " "), 
                     target_dir_path)
  system(command, input = rstudioapi::askForPassword("Enter password"))
}

rstudioapi::askForPassword() というのはコード上にパスワードを平打ちしたくない時にこれ書いとくと RStudio 上でパスワードを入力するプロンプト出してくれるナウいやつです。

さて、これを実行すると次のようなエラーが出ました。

sudo: no tty present and no askpass program specified

これはなんかセキュリティ的な制限で、デフォルトでは sudo 時のパスワードが表示されないようにしてるみたいです。 解除するには

$ sudo visudo

で sudoers ファイルを開いて

Defaults visiblepw

と書くと良いらしいです。

さて、これで実行するとうまくコマンドが実行されるわけですが、デプロイ先のフォルダがないとエラーが出てコピーできません。 なので、フォルダがなければ作るということをやります。

sudo_create_dir_if_not_exists <- function(dir_path) {
  if (!dir.exists(dir_path)) {
    command <- sprintf("sudo mkdir %s", dir_path)
    prompt <- sprintf("Create %s", basename(dir_path))
    system(command, input = rstudioapi::askForPassword(prompt))
  }
}

deploy_shiny_app <- function() {
  # 現在のワーキングディレクトリに ShinyApp があるとする
  dir_path <- getwd()
  # ShinyApp のデフォルトのデプロイ場所は /srv/shiny-server/
  target_dir_path <- file.path("/srv/shiny-server", basename(dir_path))
  # なければ作る
  sudo_create_dir_if_not_exists(target_dir_path)
  # ShinyApp のフォルダにある .R ファイルを全て取得
  files <- list.files(dir_path, pattern = "\.R$", full.names = TRUE)
  # sudo cp コマンドで全てコピー
  command <- sprintf("sudo cp -vfu %s %s", paste(files, collapse = " "),
                     target_dir_path)
  system(command, input = rstudioapi::askForPassword("Enter password"))
}

これでうまくいきそうなもんですが、ShinyApp の静的ファイルを www に入れたりモジュールをサブディレクトリに保存していたりという場合が考えられます。 なので指定したサブディレクトリもコピーするという記述も付け加えます。 このとき、フォルダからフォルダへコピーするという動作は共通なので関数化しちゃいます。

copy_files <- function(dir_path, target_dir_path) {
  # なければ作る
  sudo_create_dir_if_not_exists(target_dir_path)
  # ShinyApp のフォルダにある .R ファイルを全て取得
  files <- list.files(dir_path, pattern = "\\.R$", full.names = TRUE)
  # sudo cp コマンドで全てコピー
  command <- sprintf("sudo cp -vfu %s %s", paste(files, collapse = " "),
                     target_dir_path)
  system(command, input = rstudioapi::askForPassword("Enter password"))
}

deploy_shiny_app <- function(dir_path = getwd(), dest = "/srv/shiny-server") {
  # ShinyApp のデプロイ先
  target_dir_path <- file.path(dest, basename(dir_path))
  # コピーの実行
  copy_files(dir_path, target_dir_path)
}

コピーすべき subdir も指定可能にして for 文で回します。

deploy_shiny_app <- function(dir_path = getwd(), dest = "/srv/shiny-server", 
                             subdir = c("www")) {
  # ShinyApp のデプロイ先
  target_dir_path <- file.path(dest, basename(dir_path))
  # コピーの実行
  copy_files(dir_path, target_dir_path)
  
  # サブディレクトリのコピー
  for (subdir_name in subdir) {
    subdir_path <- file.path(dir_path, subdir_name)
    if (dir.exists(subdir_path)) {
      target_subdir_path <- file.path(target_dir_path, subdir_name)
      copy_files(subdir_path, target_subdir_path)
    }
  }
}

これで多分うまくいきます。 最初デプロイ先のフォルダがない場合はフォルダの作成、サブフォルダの作成とパスワードを何度も聞かれてうざいですが、まあしょうがないかなと。

もっと良い方法があれば教えてください。

Enjoy!

雑記

こんにちは、ホクソエムです。雑記です。

今では当たり前のように使われている pipe演算子こと %>% 。

dplyrパッケージが発表された当初は「気持ち悪い」と評判だったのですが、みなさんもう慣れたのでしょうか。

そしてrlistパッケージの %>>% 。

%>% よりハヤイ!!!!と当時は盛り上がっていましたが誰か使っている方はいるのでしょうか(私は使っていない)。 私が知らないだけで%>>>%とか%>>>>%とかあるのかもしれません。 「私はこんなpipe類似演算子を使っているよ!!!」というご報告お待ちしております。

最後に、pipeを使いたくない方にpipeを使ったコードを従来の表記に戻してくれるパッケージも開発されていましたが、皆さんこちらはご存知でしょうか。

https://github.com/TobCap/demagrittr

どんなものにも歴史はあるもので、流行っているその時にしか味わえない現在性を堪能することも、技術を追いかける醍醐味です。 言語開発の片隅に咲いたそんな一輪の花たちをこれからもお伝えしていきたいと思います。

Rユーザ会でStanの紹介と応用事例について話しました

Rユーザ会@統計数理研究所で「StanとRでベイズ統計モデリング」について発表しました。資料は以下です。

Rには詳しいがStanをほとんど知らない人たちへのStan紹介と、(空間)統計モデリングに詳しい人たちへのちょっと凝った応用事例の二部構成にしたため、易しい部分とかなり難しい部分のどっちつかずの内容になりました。ありがち。藤野さんをはじめとする皆様、ありがとうございました!

最後の参考文献のところにあるリンク先は以下になります。

Enjoy!

awe.s3パッケージでRからのAWS S3とのファイルやりとりを行う

ドーモ。ホクソエムです。更新が久しくなってしまいました。ホクソエムでは現在、Amazon Web Service (AWS)を利用していないのですが、本職の方でS3に触れる機会があったので、RからS3への操作を行うためのパッケージ awe.s3 を紹介したいと思います。

ASW S3とは、AWSが提供するサービスの一つで、オンラインでのファイルストレージとして利用できます。ストレージするファイルの容量・種類は問わないので、一時的なデータや画像の保存先として使われているのではないでしょうか。また、柔軟にアクセス制限やファイルのライフサイクル(自動的な削除)がかけられるのも特徴です。S3では、バケットと呼ばれるフォルダのような構造と、オブジェクト(データ)を管理します。

awe.s3パッケージは、数多くの便利なRパッケージを行っているROpenSciのメンバーでもあるThomas J. Leeperらが活動するcloudyrというRのチームが開発しています。cloudyrのリポジトリには、今回紹介するawe.s3のほか、同じAWSのサービスであるES2管理やLambdaのためのaws.ec2aws.lambdaなども含まれています。

github.com

awe.s3はCRANに登録されていますので、次のコマンドでインストールしましょう。また、S3の操作に必要なアクセスキーとIDは、IAM (Identity and Access Management) Management Consoleから発行しておいてください。

install.packages("aws.s3", dependencies = TRUE)

library(aws.s3)

アカウントとの紐付け

早速、ストレージしたファイルへのアクセスを行いたいところですが、まずはアクセスキーIDとシークレットキーを使った認証を行うことが必要です。

cloudyrが携わるAWS関係のRパッケージでは、Sys.setenv()で設定されている環境変数を利用します。これらが.Rprofile等に記載されていない場合は、コンソールでSys.setenv()を行いましょう。必要な情報は、アクセスキーID、シークレットキー、利用しているリージョン(地域)です。

# 環境変数の値を確認
Sys.getenv("AWS_DEFAULT_REGION")
# [1] ""

Sys.setenv("AWS_DEFAULT_REGION" = "<リージョン>", # us-east-2 など
           "AWS_ACCESS_KEY_ID" = "<アクセスキーID>",
           "AWS_SECRET_ACCESS_KEY" = "<シークレットキー>")

複数アカウントがある場合、AWSの発行するcredentialsファイルを使った署名を行うこともできます。これにはawe.s3インストール時に依存パッケージとしてインストールされるaws.signatureuse_credentials()を使います。

# defaultのアカウント情報を用いた署名
aws.signature::use_credentials()

# hoxouri ユーザのアカウント情報を利用する場合
aws.signature::use_credentials(profile = "hoxouri")

接続が成功しているかを確かめるため、バケットの一覧を表示してみます。

bucketlist()
#              Bucket             CreationDate
# 1 aws.s3.test170418 2017-04-18T04:35:22.000Z
# 2        hoxom-blog 2017-07-18T11:02:47.000Z

うまくできているようですね。

特定のバケットのオブジェクトを出力するにはget_bucket()を使います。

get_bucket("aws.s3.test170418")
# Bucket: aws.s3.test170418 
# 
# named list()

どうやらこのバケットにはまだ何も入っていないようです。

オブジェクト操作

それでは、バケットに対してオブジェクト(データ)を保存したり、バケット内のオブジェクトへの操作を行いましょう。awe.s3では、次のようなオブジェクト操作が可能です。

  • Rオブジェクト(.Rdata, .rds)の読み書き (s3save(), s3saveRDS())
  • R関数を使ったRへの読み書き (s3read_using(), s3write_using())
  • ローカルファイルのバケットへの保存 (put_object())
  • バケットからのローカルへの保存 (get_object())
  • バケット、オブジェクトの削除 (delete_bucket(), delete_object())

例として、mtcarsオブジェクト(データフレーム)をS3に保存します。Rオブジェクトとして保存したい時はs3save()で行います。

s3save(mtcars, bucket = "aws.s3.test170418", object = "mtcars.rds")

第一引数で対象のRオブジェクト、第二引数で対象のバケット名、第三引数のobject引数ではオブジェクト名を与えます。関数の実行後、コンソールには何も表示されませんが、エラーがでなければアップロードは成功しているはずです。改めてバケットの中身を出力してみましょう。

get_bucket("aws.s3.test170418")
# Bucket: aws.s3.test170418 
# 
# $Contents
# Key:            mtcars.rds 
# LastModified:   2017-07-18T11:33:04.000Z 
# ETag:           "1bf2269b855ca97b628582dc29962eb1" 
# Size (B):       1235 
# Owner:          suika1127 
# Storage class:  STANDARD

次はcsvをアップロードする例です。Rオブジェクトではなくcsvなどのファイルで保存したい時はreadr::write_csv()などの関数を使いテキストファイルにしておきましょう。またその際はput_object()を使い、ファイルのアップロードを行います。

mtcars %>% 
  readr::write_csv("sample_mtcars.csv")
put_object(file = "sample_mtcars.csv", 
           object = "sample_mtcars.csv", 
           # バケットにはフォルダを作ることができますが、bucket引数で指定(なければ作成される)できます
           bucket = "aws.s3.test170418/csv")

今度は保存したオブジェクトをRで利用可能な状態にします。対象がRオブジェクトであればs3loadreadrreadxlで読み込めるファイルであればs3read_using()を用います。

s3load("mtcars.rds", bucket = "aws.s3.test170418")
ls()
# [1] "mtcars"

s3read_using(readr::read_csv, object = "sample.csv", 
             bucket = "aws.s3.test170418/csv")

rdsファイルに保存したmtcarsオブジェクトが利用できるようになりました。

私も使い始めたばかりで、aws.s3パッケージの全てを紹介しきれませんが、基本的なことはできたかと思います。つどコンソールを叩かず、集計結果等を保存できる、データを引っ張ってこれるので便利ですね。

Enjoy!

RStudioアドイン 10選

Rユーザのみなさん、RStudio使っていますか。RStudioを使うなら、RStudioアドインも使いましょう。便利です。

… でも、\どんなアドインがあるのかわからない!

という声をしばしば聞きます。というわけでお気に入りのアドインを10個まとめました。用途ごとに部門を設けて紹介します。

RStudioアドインとは

そもそもRStudioアドインとは何か。それを説明しておかないといけませんね。

RStudioアドインとは、0.99.878以降のバージョンで実装されているRStudioの一機能です。複雑な処理をボタン一発で実行したり、ショートカットとして利用したり、GUI操作で処理を実行できるようになります。

RStudioアドインはメニューバーの「Addins」というボタンあるいは設定されたショートカットから呼び出すことができます。アドインは、Rの関数と同様にパッケージによって提供されているため、該当のパッケージをインストールすることで利用可能になります。

使い方やアドインの作成方法は公式のドキュメントまたはこちらの記事 (RStudioで気軽にLGTM)をご覧ください。

それではおすすめアドインの紹介に入ります。実用、可視化、文書作成、ネタ系の4つに分けます。簡単な説明と動作画像を貼りますので雰囲気を感じてください!カッコ内でアドインが含まれるパッケージを表示しています。

実用系

Rを使った作業一般で役立ちそうなアドインです。こちらからは5つ。

Reformat R Code (addinexamples)

適当なスペースはコードの可読性を高めます。GoogleもHadley Wickhamも演算子の後にはスペースを含めることを推奨しています。

このアドインは、選択したコードの可読性を高めるために実行することができます。具体的には、先の演算子間のスペースの自動挿入と、インデントの調整、一行のコードを任意の長さで改行するという機能をもちます。背景の処理にformatrパッケージが使われています。

https://github.com/HOXOMInc/blog/blob/master/docs/img/rs_addins_top10_1.gif?raw=true

pipefittr (pipefittr)

見やすいコードにするためには、どんどんmagrittrパッケージのパイプ演算子を使うと良いです。でも古いコードなど、パイプが使われていないものもあります。そういった場合にこのアドインが役立ちます。このアドインは従来の、複数の関数の処理を入れ子で記述したコードをパイプ処理での書き方に直します (時々失敗してしまうのが玉に瑕)。

https://github.com/HOXOMInc/blog/blob/master/docs/img/rs_addins_top10_2.gif?raw=true

Render reprex (reprex)

GitHubやStackOverflowなど、自分の環境で発生した状況を説明するには、言葉だけで再現性を成立させることはできません。やはり、状況を引き起こしているコードがなければいけません。ですが実際は、質問をあげる多くの人が問題の記述だけでコードを書きません。この問題を解決するのに大きく役立つのがreprexパッケージです。このパッケージは、GitHub、StackOverflowにRコードと実行結果をコピーできる状態で出力する関数を備えていますが、アドインとしてもその機能を実行することが可能です。

https://github.com/HOXOMInc/blog/blob/master/docs/img/rs_addins_top10_3.gif?raw=true

対象を、コピーされているコードか、現在の選択範囲か、Rファイル全体かといったものを選んで実行できます。

なおこのパッケージの使い方は、こちらのブログ記事にも書かれています。ちなみにパッケージ名にもなっているreprexはreproducible exampleの略だそうです。再現性、大事!

tidydata (tidyshiny)

こちらのアドインは、現在ワークスペースにロードされているデータを対象にtidyr::gather()を実行する関数です。列の除外指定ができないようですが、コードが吐き出されるのでそれを編集すれば良いですね。

https://github.com/HOXOMInc/blog/blob/master/docs/img/rs_addins_top10_4.gif?raw=true

githubinstall (addin4githubinstall)

GitHub上のパッケージをインストールするにはgithubinstallパッケージ一択ですが、適当なキーワードでパッケージを探したい…。そんな時が、あると思います!そこで役立つのがこのアドインです。キーワードを入力して、パッケージのリストから検索・インストールすることができます。

https://github.com/HOXOMInc/blog/blob/master/docs/img/rs_addins_top10_5.gif?raw=true

こちらのアドインは

githubinstallが提供しているものでなく、こちらのリポジトリからパッケージをインストールして利用します。

可視化系

続いてプロットや何かの色を決めるのに便利なアドインを2つ。

colourPicker (colourpicker)

プロットで使われている色を変更したいけどカラーコードなんて覚えていない…。カラーピッカーというアドイン名の通り、色を表示しながら選択するのにこのアドインが便利です。同色の色のパターンも生成することができます。

https://github.com/HOXOMInc/blog/blob/master/docs/img/rs_addins_top10_6.gif?raw=true

さらにこのパッケージでは、下記画像のようにプロットされた画像で使われている色を選択・変更可能なアドインも提供されています。

https://github.com/HOXOMInc/blog/blob/master/docs/img/rs_addins_colourpicker.png?raw=true

なお、shinyjsパッケージでも同じアドインが提供されていましたが、現在はcolourpickerパッケージとして独立したようです。そちらを使いましょう。

ggplot Theme Assistant (ggThemeAssist)

ggplot2の図は各種の要素に対して変更を加えることが可能です。しかし自由度が高いぶん、覚えるのが困難でもあります。このアドインは、その問題を解決します。

既存のggplot2でのプロットを実行するコードを選択した状態でアドインを実行すると、各要素を変更するためのGUIが起動します。あとは煮るなり焼くなり。お好みの図に調理して、コードを出力しましょう。

https://github.com/HOXOMInc/blog/blob/master/docs/img/rs_addins_top10_7.gif?raw=true

文書作成 (rmarkdownまわり)系

Rmd形式のファイルで効果的なアドインを2つ。この他にも論文執筆の際の文献管理に役立つアドインやblogdown、bookdownなどでボタン一発ビルドを実行するアドインなどがあります。

Word count (wordcountaddin)

選択中のコードに含まれる単語数などを数えて出力します。日本語だと精度が高くないですが、読み終わる時間の目安も出ます。文章を書いている際に良いのではないでしょうか。

f:id:u_ribo:20180815193850g:plain

ちなみにMacで利用する場合、Javaのバージョンでエラーになることがあるかもしれません。その際は次の記事にあるコードを実行することで解決する可能性があります。

WrapRmd

RMarkdown内で実行するRコード(インラインコード)の改行を、レンダーに影響を与えずによしなにしてくれるアドインです。パッケージはCRANに登録されていないのでGitHubからインストールしてください。

f:id:u_ribo:20180815194055g:plain

ネタ系

最後にとっておきのアドインを紹介します。

Add gifs (giphyr)

Rの作業に疲れた時、ネコに癒されたくなった時、Shia LaBeoufに喝を入れてもらいったくなる時… そんな時にオススメのアドインです。

このパッケージはGiphyAPIを利用し、おもしろGifを取得するものです。アドインとして、画像の検索機能、貼り付け先や保存先を選べます。

https://github.com/HOXOMInc/blog/blob/master/docs/img/rs_addins_top10_10.gif?raw=true

ここに挙げた以外にも、みなさまオススメのアドインがございましたらホクソエムhoxom_incまでご一報ください!

Enjoy!

「東京ベイエリア・タワーマンション地図」の作成

はじめに

キュッキュキュッキュ🎧こんばんはDJタカヤナギです😤。

今日で連休が終わるという方が大半なのではないでしょうか? 長い連休明けの月曜日はいつだって嫌なものですね。

さて、東京オリンピックまであと3年ということで、その中心地となるであろう東京湾周辺、通称、東京ベイエリアが熱いわけです。 特にここ数年で高騰したタワーマンション(以下、タワマン)や、 これからもガンガン建設されていく予定のまだ見ぬタワマンに対し、投資対象として強い興味があるわけです。

主に、弊社の社長が。

ただ、東京ベイエリアのタワマンと言いましても数がたくさんありすぎて覚えられないぞと、 一目で、どれがどのタワマンかわかるような地図が必要だぞというわけで、それをR言語を用いて作ってみましたので、その方法を公開します。

R言語での実装

さて、問題となるのはタワマン一覧のデータソースですが、ここではアクセルホームさんが公開されている

あたりをソースとさせていただきました(実際には当該ページから次のページへと遷移した数ページも使用)。 こちら、よくまとまっており、大変助かります。 なお、中央区(chuo)・江東区(koto)ともに3ページ分のデータが存在することについては目視確認です。

なお、スマホ用のページが存在することに後から気が付いたのですが、今回はPC用のサイトでそのままがんばりました。 スマホ用のページの方が、一般に構造が簡単なので、スクレイピングするにはお勧めです。

これらのページから、必要な情報を取得するためのスクレイピング関数を作成します。 詳細はコード中のコメントとして記載しています。 コードはすべて

にあります。

どこのHTMLタグのどのデータを抜けば良いのかの"当たり"を付けるためにはGoogle Chromeの「検証ツール」を用いました。

関数自体はやっつけで書いたので、汚いです…

東京ベイエリアタワーマンション地図

出来上がった結果がこちらです。ベイエリアと言いながら街中まで入ってしまっているのを除くのは読者への課題とします。

Enjoy!!!

R の強制型変換と NA の取り扱い

はじめに

R において欠損値を表す NA は非常に便利です。 NA は普通の R ユーザにとって自然に取り扱うことのできる概念ですが、それを支える内部の仕組みはわりと複雑です。 例えば、NA の型は論理値型ですが、一体それはなぜでしょうか? 今日は R における強制型変換の話とからめてその謎をひも解いていきます。

ベクトルと型

R のベクトルは型を持ちます。

例えば、1から3までの数値ベクトルを作成してみます。

x <- 1:3
x
#> [1] 1 2 3

ベクトルの型を確認するには typeof() 関数を使います。

typeof(x)
#> [1] "integer"

ベクトル x の型は整数型(integer)であることがわかります。

他にも、例えば次のようなベクトルを作成してみます。

x <- c("U", "NA", "DON")
x
#> [1] "U"   "NA"  "DON"
typeof(x)
#> [1] "character"

この場合、ベクトル x は文字列型(character)になります。

このように、Rのベクトルは必ず型を持ちます。

では、1つのベクトルの中に異なる型の要素を含めるとどうなるでしょうか。

x <- c("U", 2, "DON")
x
#> [1] "U"   "2"   "DON"
typeof(x)
#> [1] "character"

この場合、ベクトル x 中に含まれる数値の 2 は、文字列型の "2"強制型変換されます。

強制型変換

R のベクトルは、1つだけしか型を持つことができません。1

したがって、異なる型の要素を結合してベクトルを作成しようとすると、型を統一するために、型の自動変換が行われます。これが強制型変換です。

強制型変換にはルールがあります。結合しようとする要素の型の中で、最も柔軟性の高い型に変換されます。

型の柔軟性は次の通りです。

logical < integer < double < complex < character
(論理値型 < 整数型 < 倍精度小数点型 < 複素数型 < 文字列型)

先ほどの例で言うと、"U" は character、2 は double、"DON" は character なので、最も柔軟性の高い character 型に変換されたと言うわけです。

他の例を挙げると、例えば、整数型と論理値型を結合すると、整数型に強制型変換されます。2

x <- c(1L, 2L, 3L, TRUE, FALSE)
x
#> [1] 1 2 3 1 0
typeof(x)
#> [1] "integer"

複素数型と倍精度小数点型を結合すると、複素数型に強制型変換されます。

x <- c(1 + 1i, 2 + 2i, 3, 4)
x
#> [1] 1+1i 2+2i 3+0i 4+0i
typeof(x)
#> [1] "complex"

おわかりのように、型の柔軟性は、低い方から高い方に自然に変換できるように決められています。

どんな型でも文字列に変換することができるので、文字列の型が最も柔軟性が高いことがわかります。

x <- c(TRUE, 1L, 1.0, 1+0i, "hoge")
x
#> [1] "TRUE" "1"    "1"    "1+0i" "hoge"
typeof(x)
#> [1] "character"

強制型変換における NA の取り扱い

R には値が欠測していることを表すために NA という特別な値が用意されています。

x <- c(1, NA, 3)
x
#> [1]  1 NA  3

しかし、この NA の型を調べてみると、logical になっています。

typeof(NA)
#> [1] "logical"

したがって、NA は論理値型であると思われるかもしれませんが、それは違います。

実は、Rでは、全部の型に対して NA が用意されています。

type NA
論理値型 logical NA
整数型 integer NA_integer_
倍精度小数点型 double NA_real_
複素数 complex NA_complex_
文字列型 character NA_character_

その理由は強制型変換と深いつながりがあります。

まず、NA は最も柔軟性の低い論理値型で定義されています。

すなわち、論理値型のベクトルに NA が含まれている場合、強制型変換は行われません。

x <- c(TRUE, NA, FALSE)
x
#> [1]  TRUE    NA FALSE
typeof(x)
#> [1] "logical"

次に、整数型のベクトルに NA を含めたいとします。 NA は論理値型ですので、整数型に強制型変換しなければなりません。 そこで使用されるのが整数型の NA である NA_integer_ というわけです。

x <- c(1L, NA, 3L)
x
#> [1]  1 NA  3
typeof(x)
#> [1] "integer"

表面上は NA と表示されますが、NA_integer_ に変換されていることは次のようにして確認できます。3

identical(x[2], NA)
#> [1] FALSE
identical(x[2], NA_integer_)
#> [1] TRUE

他の型でも同様に、NA は強制型変換のルールに従い、ベクトル中で最も柔軟性の高い型の NA に変換されます。

例えば、文字列型に含まれる NA は NA_character_ に変換されます。

x <- c("U", NA, "DON")
x
#> [1] "U"   NA    "DON"
identical(x[2], NA_character_)
#> [1] TRUE

デフォルトの NA が論理値型である理由は、ここにあります。

NA を柔軟性の最も低い論理値型とすることで、強制型変換のルールがうまく働き、最も自然な形で型変換を行うことができるのです。

まとめ

デフォルトの NA が論理値型であることで、強制型変換のルールとうまく組み合わさり、自然な動きをすることがわかりました。

すべての型の NA は、is.na() を適用すると TRUE となります。

sapply(list(NA, NA_integer_, NA_real_, NA_complex_, NA_character_), is.na)
#> [1] TRUE TRUE TRUE TRUE TRUE

したがって、ユーザは特に型を意識することなく NA を取り扱うことができます。

このように、便利な機能の裏側には様々な仕組みが動いています。

Rのこのような仕組みに興味を持った方は、参考文献に挙げた『R言語徹底解説』を読んでみてください。 Rの世界が広がると思います。

参考文献

R言語徹底解説

R言語徹底解説


  1. もし、複数の型を持つベクトルが必要ならば、リスト を使うことになります。

  2. 細かいことですが、R で 1 と書くと通常は倍精度小数点型とみなされます。整数型リテラルを表現するには 1L のように数字の後に L を加える必要があります。

  3. identical() は、オブジェクトが同じかどうかを判定する関数です。