初めてのR Markdownテンプレート作成法

この記事は,ベイズ塾 Advent Calendar 2020 - Adventar14日目の記事です。

R Markdownって本当に便利ですよね。Rコード,結果,文章を統合してHTMLやPDFに出力してくれます。コピペすることで生じるミスもなくなります。ベイズ塾では,@kazutanの影響もあり,随分と前からR Markdownが使われてきました。

R Markdownでは,投稿する雑誌や用途に合わせて作られたテンプレートが配布されており,内容だけに集中してフォーマット調整をする場合に便利です。今回は,既存のRMarkdownテンプレートで飽きたらなくなった方に向けた記事になります。

今回は,WordやHTML出力はスルーして,PDF出力に限定した内容です。PDFに限定する理由は,HTMLで厳密にフォーマット調整することはあまりなさそうですし,Wordの場合は,最終的にはWordで調整すれば良い気がするからです。投稿できる形式に整えられた論文をPDF出力するような状況を想定しています。

R Markdownテンプレートパッケージの例

作り方の解説の前に,私が作ったR Markdownテンプレートパッケージを紹介します。どちらも日本語を使用した論文PDFテンプレートになります(なので,日本語を処理するための工夫を色々しています)。どちらもインストールするとR Markdownの新規作成時のフォーマットとして選択できるようになります。

まず,勤務先の専修大学人間科学部心理学科の卒論用R Markdownテンプレートです。GitHubも一緒に活用すると卒論指導の手間が半分になり,楽しさが2倍になりました*1。中身を埋めていって,Knitすると学科で指定しているフォーマットで卒論のPDFが出力されます。卒論用なので教育目的の内容がテンプレート内のコメントとして入っています。

github.com

次に,日本心理学会の発行する『心理学研究』用R Markdownテンプレートです。海外の雑誌のR Markdownテンプレートは充実してきたのですが,日本語を使うような国内誌のR Markdownテンプレートはほとんどないので作成しました。こっちはプロ用なので,あまり教育目的のコメントは入っていません。

github.com

RMarkdownテンプレート作成に有用なサイト

では,R Markdownテンプレート開発をはじめましょう。最初にテンプレート開発に使えるサイトを紹介します。

まず,本家の「R Markdown Cookbook」です。これが全てといえます。

bookdown.org

次に,Kazutanが以前にまとめた,「R Markdownの内部とテンプレート開発」です。ただ読むだけだと分からないのですが,実際にテンプレートを作り始めると,かゆいところに手が届く情報がまとまっています。

kz-md.net

この2つの資料を軸にしつつ,あとはグーグル検索でR Markdown, LaTeXあたりの情報を得ていく感じになります(私はライトユーザーなのでPandocについてはほとんど調べないです。この程度でも,雰囲気でなんとかなります)。

R Markdownテンプレート用Rパッケージの作成方法

それでは,R Markdownテンプレート用Rパッケージを作ってみましょう!基本的にはRのパッケージと同じなのですが,テンプレートファイルを配置したり,出力時の設定用R関数を書くあたりが特殊かもしれません。

(1)R Markdownの設定を変更して出力を調整する

R Markdownでは,一番上のYAMLを変更することで,LaTeXパッケージを追加したりできます。ただ設定が増えていくと大変ですし,細かい調整は難しくなるので,texのテンプレートファイルを作って,以下のように指定することもできます。

output:
  pdf_document:
    template: my-template.tex

一般的には,以下のdefault.latexというテンプレートに変更を加えてTeXテンプレートを作ります。以下のdefault.latexをみると分かりますが,$$でくくられた記法を使っています。細かい話をするとR Markdownでは,knitでMarkdown形式に変換して,それをPandocなるものを使ってLaTeX経由でPDF出力をします。そのPandocでLaTeX形式にする際に,TeXテンプレートを使います(よく分かんなけど,たくさんの人の支えによってR MarkdownからPDFが出力されているのだけは分かります)。

pandoc/default.latex at master · jgm/pandoc · GitHub

default.latexテンプレートを修正したものでもいいですし,何か理想とする出力に近いTeXテンプレートを元にして,それに修正を加えるのも良いかと思います。まあ,出力したい形式で出力できるTeXテンプレートを作るのが一番大変なところです。ただ,私はいつも試行錯誤をして,ほぼ雰囲気で書いたり修正しているので,まだ上手に言語化できません。なので,今回は省略します(とりあえず,やりたい内容×TeXもしくは内容×R Markdownで検索して,出てきた方法をTeXテンプレートに落とし込んでいる感じです)。以降は,TeXテンプレートとR Markdownテンプレートができた状態として進めます。

(2)Rパッケージ作成の下準備をする

以下の記事の「(5) 一旦コミットして,GitHubにプッシュする」まで作成します。

cpp-laboratory.hatenablog.com

(3)R Markdownテンプレートの作成

ここからがR Markdownテンプレート用の設定です。通常のRパッケージでは,Rフォルダ内に関数を定義したファイルを配置します。R Markdownテンプレートでは,inst > rmarkdown > templates > テンプレート名のフォルダを作り(つまり,inst/rmarkdown/templates/テンプレート名のフォルダ/),その中にファイルを配置します。inst/rmarkdown/templates/テンプレート名のフォルダ/を作りましょう。

次に,テンプレート名のフォルダ内にtemplete.yamlを作ります(つまり,inst/rmarkdown/templetes/テンプレート名のフォルダ/templete.yamlを作る)。senshuRmdの場合は,以下のような感じです。

f:id:cpp-laboratory:20201213143708p:plain

YAML内にR Markdownテンプレートの説明などを書きます。以下は,senshuRmdの内容です。nameに書かれた内容が,R Markdownファイルをテンプレートから作ろうとするときの名前になります。Rmdファイル以外のファイルも配布する場合は,create_dir: trueにしておきます。

name: Thesis format for Senshu
description: Thesis format for Department of Psychology, Senshu University
create_dir: true

そして,テンプレート名のフォルダ内にskeletonフォルダを作って,skeleton.Rmdを含む配布するファイルを配置します(つまり,inst/rmarkdown/templates/テンプレート名のフォルダ/skeleton/skeleton.Rmdを作る)。skeleton.Rmdは,R markdownのテンプレートです。senshuRmdの場合は,以下のように,参考になるように,fig1.pngやbibファイルなども配置しています。

f:id:cpp-laboratory:20201213143915p:plain

なお,senshuRmdのskeleton.RmdのYAMLは以下のようになっています。重要なのは一番最後の行で,output:でPDF形式や特定のテンプレートを指定するのではなく,senshuRmd内のsenshu_thesis関数を使っています(後述しますが,この関数で出力などの設定をしています)。

title: 'タイトル:'
author: '学籍番号: 氏名:'

bibliography:  reference.bib
suppress-bibliography: yes
output: senshuRmd::senshu_thesis

最後に,テンプレート名のフォルダ内にresourcesフォルダを作って,TeXテンプレートファイルを配置します(つまり,inst/rmarkdown/templetes/テンプレート名/resources/texテンプレート.tex)。senshuRmdの場合は,以下のようになります。

f:id:cpp-laboratory:20201213143920p:plain

(4)R Markdownテンプレート用R関数の作成

続いて,skeleton.RmdのYAMLにおいて,outputに指定した関数を設定します。関数の設定は以下の通りになります。ご自身のテンプレートに合わせて,関数名,テンプレート名,パッケージ名を変更ください。

#' 説明
#' @export
関数名 <- function(){
  template_tex_file <- system.file("rmarkdown/templates/テンプレート名/resources/テンプレート名.tex",
    package = 'パッケージ名')
  format_pdf <- rmarkdown::pdf_document(latex_engine = "xelatex",
    template = template_tex_file,
    keep_tex = TRUE,
    toc = TRUE,
    toc_depth = 3,
    highlight = 'tango')
  format_pdf$inherits <- "pdf_document"
  format_pdf
}

ちょっと説明をすると,system.file()でテンプレートを読み込んでいます。rmarkdown::pdf_documentでPDF出力の設定をしますが,日本語を使う場合は,xelatexを使います。

Rパッケージを完成させる

devtools::check()を使ってビルド&チェックしつつRパッケージとして完成させます(詳しくは, 初めてのRパッケージ作成:最初の一歩 - Computational Clinical Psychology Lab を参照ください)。

完成したら,GitHub経由でインストールして,File -> New File -> R Markdown...をクリックします。

f:id:cpp-laboratory:20201213154728p:plain

New R MarkdownでFrom Templateを選ぶと,自作したR Markdownテンプレートが出てくるので,選択して,OKをクリックします。

f:id:cpp-laboratory:20201213154732p:plain

後は,執筆・解析して,knitすれば理想のフォーマットのPDFが生成されます!

Enjoy!

*1:卒論執筆じゃなくて卒論指導です。とはいえ今後の社会人生活における共同作業の方法を身につけるという意味では教育効果も高いのではないかなと思います?

DockerでStanの実行環境を最速で用意しよう:Windows編

こちらは,Stan Advent Calendar 2020 - Qiita13日目の記事です。もう,StanのアドベントではDockerのこと以外を書かないという強い意志をもって,今年も書きます。

Dockerの概要については,以下の記事を参照ください。再現性高く解析環境を素早く用意できるようなサービスと思っておくと良いかと思います。こう書くと「お,Dockerいいじゃん」となりそうですが,あまり心理学で広まっている感じはしません。

ykunisato.github.io

Dockerの利用が少しでも増えるといいかなと思って,色々と普及活動を行ってきましたが,どうも響きません。なんとなく分かってきたのは,Macユーザーだと導入が簡単だけど,Windowsユーザーにとってはちょっと導入が面倒くさいようです(あとはDockerで10GBくらい使うので,ハードディスクに余裕がない場合に導入ができないというのもあるようです...)。そこで,Windowsユーザーのための導入方法を以下に紹介いたします(以下は,日本心理学会第84回大会のチュートリアルワークショップ「今日からできる再現可能な論文執筆」の内容とほぼ同じです)。

Windows10のエディションを確認する(ProかHomeか)

多くの方が,Windows10をお使いだとは思いますが,一般的に使われるWindowsにはProとHomeの2つのエディションがあります。エディションによってDockerの導入方法が異なります。以下の解説動画で,ご自身のパソコンのWindowsがProかHomeのどちらかをご確認ください。

Windows10がProエディションの場合の導入方法

Windows10 Proエディションの方は以下の動画を参考にDockerを導入なさってください。なお,コマンドプロンプトに打ち込むコードについて,動画内で紹介しているものでも動きますが,以下で書いているコードのほうが楽だし上手くいくと思います。

コマンドプロンプトに打ち込むDocker用のコードは以下になります。以下のコードは動画内で口頭で解説しているものとは異なりますが,こちらのほうが簡単かつ上手くいくと思います!(-e DISABLE_AUTH=trueは便利ですが,複数アカウントがある場合は挙動がつかめないのでおすすめしないです)ローカルで,ご自身が所有しているパソコンでの利用を想定しているのでパスワードはpaperに固定しています(気になる場合は改変ください)。

docker run -e PASSWORD=paper -p 8787:8787 -v "%cd%":/home/rstudio -d --name paper ykunisato/paper-r

終わったら,ブラウザのアドレスバーにlocalhost:8787と打ち込んで,出てきたログイン画面のUsernameにrstudio, Passwordにpaper(もしくはご自身で設定したパスワード)をいれてください。普段使っているホームディレクトリがマウントされていると思います。

Windows10がHomeエディションの場合の導入方法

Windows10 Homeエディションの方は以下の動画を参考にDockerを導入なさってください。なお,コマンドプロンプトに打ち込むコードについて,動画内で紹介しているものでも動きますが,以下で書いているコードのほうが楽だし上手くいくと思います。

コマンドプロンプトに打ち込むDocker用のコードは以下になります。以下のコードは動画内で口頭で解説しているものとは異なりますが,こちらのほうが簡単かつ上手くいくと思います!(-e DISABLE_AUTH=trueは便利ですが,複数アカウントがある場合は挙動がつかめないのでおすすめしないです)ローカルで,ご自身が所有しているパソコンでの利用を想定しているのでパスワードはpaperに固定しています(気になる場合は改変ください)。

docker run -e PASSWORD=paper -p 8787:8787 -v "%cd%":/home/rstudio -d --name paper ykunisato/paper-r

終わったら,ブラウザのアドレスバーにlocalhost:8787と打ち込んで,出てきたログイン画面のUsernameにrstudio, Passwordにpaper(もしくはご自身で設定したパスワード)をいれてください。普段使っているホームディレクトリがマウントされていると思います。

Dockerコマンド

コンテナの確認と開始

コンテナの動作確認するには,コマンドプロンプトに以下を打ち込みます。STATUSがUpになっているとコンテナが動いています(再起動後に止まったりしていることがある)。

docker ps -a

もしコンテナが停止している場合は(STATUSがExitedになっている),コマンドプロンプトに以下を打ち込んで,コンテナを開始します。

docker start コンテナ名(上記の場合はpaper)

コンテナの停止と削除,イメージの削除

もうコンテナが不要になったら,停止して削除します。コンテナの停止には,コマンドプロンプトに以下を打ち込みます。

docker stop コンテナ名(上記の場合はpaper)

コンテナの削除には,コマンドプロンプトに以下を打ち込みます。

docker rm コンテナ名(上記の場合はpaper)

rmしてもコンテナが削除されただけでダウンロードしたイメージは残っています。まず,以下をコマンドプロンプトに打ち込んで,イメージの状況を確認します。削除したいイメージのIMAGE IDをコピーします。

docker images

上記でコピーしたIMAGE IDを使って,以下をコマンドプロンプトに打ち込んで,イメージを削除します。

docker rmi IMAGE_ID

初めてのRパッケージ作成:最初の一歩

この記事は,ベイズ塾 Advent Calendar 2020 - AdventarOpen and Reproducible Science Advent Calendar 2020 - Adventarの12日目の記事です。

この数年,Rで解析をしていて,繰り返し使いそうなものは関数化したり,さらに他の人に使ってもらう場合は,パッケージ化するようにしています。といっても,CRANに登録するような気合の入ったものではなくて,GitHubで公開するようなライトなものです。まず,ベイズ塾の塾生はRスキルが高いので,どんどんオリジナルなパッケージを作っていくといいなあと思います。また,オープンサイエンスにおいては,オープンな解析ソフトの開発や公開が重要なので,日本からもこういうことに貢献できるような素地を作っていきたいなあと思います。ということで,今回は,そういうライトなパッケージ作成の最初の一歩の記事を書いてみようかと思います。

Rパッケージ作成に有用なサイト

私がRパッケージを作る時は以下のサイトを参照しています。全く覚えられないので毎回検索して,大体この2つを参照して作って,すぐに忘れることを繰り返しています。「Rパッケージの作成は,以下のサイトを参考にすると良いよ!終わり!!!」でもいいのですが,ちょっとは自分で覚えましょうかねということで,以下にまとめてみようかなと思います。

Practical R Package Development (Japanese)

こわくないRパッケージ開発!2016 - Qiita

今回作成するパッケージ

具体的な作業手順を説明したいと思うので,何か適当なRパッケージを作ることにします。簡単でかつ使いそうなものがなかなか浮かばず,今回は,Rで解析が終了したらslackに通知するというパッケージを作ります。ただ,slackとRの連携については,以下のslackrという便利なパッケージが既にあります。今回は,自分用にライト(あとでマニアックに調整できるくらいシンプル)なslack通知パッケージを作ることにします。

github.com

私は,時間のかかる解析をする時は,以下のようなコードを解析に関するコードの下にいれておいて,解析が終わったらslackに通知されるようにしています(slackのAPIトークンの取得は以下の記事を参照ください)。まあ,これでいいっちゃいいのですが,まあまあコードが長いですし,slackのトークンとチャンネル名などが入っているので,githubでコードをそのまま共有できないです。

httr::POST(url="https://slack.com/api/chat.postMessage",
             body = list(token = slackのトークン,
                         channel = slackのチャンネル,
                         username = slackのユーザーネーム,
                         text = paste(format(as.POSIXlt(Sys.time(), tz = "Asia/Tokyo"),"%Y/%m/%d %H:%M"),"なんかメッセージ")))

qiita.com

そこで,もう少し工夫をして,以下のような関数にしてみました。工夫点は以下のとおりです。

  • 関数の引数にslackのトークンの情報をそのままいれるとそのコードの共有がしにくくなりますし,GitHubにもあげにくいので,環境変数に書き込む関数set_slack_info()を追加しました。よくわかりませんが,Sys.setenv()で環境変数を設定できるようです。この設定はRを再起動しちゃうと消えちゃうので,そうしないためには,".Renviron"などに書き込む必要がありますが,今回は深入りを避けます。

  • 次に,上記のコードをsend_slack()関数にしました。トークンなどの情報は,set_slack()で設定するので,もしそれらの設定ができてなかったらエラーが出るようにしておきます。

set_slack <- function(slack_token, 
                           slack_channel = "#general", 
                           slack_username = "R"){
  if(missing(slack_token)){
    stop("Please set slack_token")
  }
  Sys.setenv(SLACK_TOKEN=slack_token)
  Sys.setenv(SLACK_CHANNEL=slack_channel)
  Sys.setenv(SLACK_USERNAME=slack_username)
}

send_slack <- function(message = "Analysis has been completed"){
  # check argument
  if (Sys.getenv("SLACK_TOKEN") == "") {
    stop("Please set slack_token with set_slack")
  }
  if (Sys.getenv("SLACK_CHANNEL") == "") {
    stop("Please set slack_channel with set_slack")
  }
  if (Sys.getenv("SLACK_USERNAME") == "") {
    stop("Please set slack_username with set_slack")
  }
  
  # send message to slack
  httr::POST(url="https://slack.com/api/chat.postMessage",
             body = list(token = Sys.getenv("SLACK_TOKEN"),
                         channel = Sys.getenv("SLACK_CHANNEL"),
                         username = Sys.getenv("SLACK_USERNAME"),
                         text = paste(format(as.POSIXlt(Sys.time(), tz = "Asia/Tokyo"),"%Y/%m/%d %H:%M"),message)))
}

使い方は,以下のようにset_slackでslackの情報を環境変数に追加します。

set_slack("slackのAPIトークン","#チャンネル名", "ユーザー名")

そのうえで,send_slack()内にメッセージをいれると,「2020/12/11 10:15 研究1の仮説1の推定終了!」みたいに,終わった時間(今回は,Asia/Tokyo時間に固定しています)とメッセージがslackの指定したチャンネルに届きます。まあ,それだけのチョット便利関数です。

send_slack("研究1の仮説1の推定終了!")

関数をRパッケージ化してみよう!

では,このシンプルな関数をRパッケージ化していくことにしましょう!まず,以下をご準備ください。

  • GitHubアカウント

  • Rstudio

  • Rパッケージ(devtools, usethis, remotes)

install.packages("devtools")
install.packages("usethis")
install.packages("remotes")

(1) Rパッケージ作成用プロジェクトを用意する

では,Rパッケージ作成用プロジェクトを用意しましょう。Rstudioで,File -> New Project...を選びます。

f:id:cpp-laboratory:20201211115811p:plain

出てきたウィンドウで,New Directoryを選びます。

f:id:cpp-laboratory:20201211120523p:plain

続いて,Project Typeは,R packageを選びます。

f:id:cpp-laboratory:20201211120527p:plain

出てきたウィンドウで,Package nameを記入します。なお,アンダーバー(_)は使えません。今回は,雑にeasySlackにします。Create a git reprositoryにチェックをいれておいてください。

f:id:cpp-laboratory:20201211120530p:plain

Filesをみると以下のようにファイルができています。

f:id:cpp-laboratory:20201211155209p:plain

(2) Rパッケージ作成用プロジェクトを設定する

第1章 新しくRパッケージを作る | Practical R Package Development (Japanese)を参考に,設定していきます。RstudioのBuild -> Configure Build Tools...をクリック。

f:id:cpp-laboratory:20201211155212p:plain

Build ToolsのGnerate documentation with Roxygenにチェックを入れる。

f:id:cpp-laboratory:20201211155215p:plain

なにかポップアップしてくるけど,これは,「OK」をクリックする。

f:id:cpp-laboratory:20201211155218p:plain

以下のファイルは不要なので,削除する。

  • NAMESPACE
  • Rフォルダ内のhello.R
  • manフォルダ内のhello.Rd

以下のように選択して,Deleteで削除する。

f:id:cpp-laboratory:20201211155734p:plain

(3) GitHubの設定をする

GitHubにアクセスして,ログインします。どこかに,Newっていう新たにリポジトリを作るボタンをあるので,クリックします。

f:id:cpp-laboratory:20201211160444p:plain

以下のように,Create a new repositoryが出てくるので,Repository nameを書き込んで,Create repogitoryをクリックします。Repository nameはパッケージ名です。

f:id:cpp-laboratory:20201211160448p:plain

レポジトリができると何か文字がでてくる画面になりますが,以下を確認します。

f:id:cpp-laboratory:20201211160451p:plain

上記の画面のうち,まずはgit remote ... の1行を使いますので,コピーします。コピーしたものを以下のように,RstudioのTerminalにペーストして実行します(Consoleじゃありません)。

f:id:cpp-laboratory:20201211161123p:plain

(4) パッケージに関する情報を設定をする

RstudioでFilesにあるDESCRIPTIONを開きます。以下のような感じです。

f:id:cpp-laboratory:20201211161710p:plain

細かいところは,後で直せるので,Version を0.0.1にして,AuthorとMaintainerだけ書き込みました。

f:id:cpp-laboratory:20201211161714p:plain

次は,ライセンスの情報を追加します。MITライセンスが多いかなと思います。usethisパッケージのuse_mit_license()関数が便利です。自分の名前を引数にいれましょう。次に,use_readme_md()でREADMEファイルを追加し,use_roxygen_md()でRのドキュメント作成を自動化してくれるroxygenの設定をします。以下をConsoleに打ち込みましょう。

usethis::use_mit_license("Yoshihiko Kunisato")
usethis::use_readme_md()
usethis::use_roxygen_md()

README.mdファイルが自動的に開く(開いてなければ,Filesから開く)。将来的にはここに説明を書き込むわけですが,後でもできるので,そのままにします。

f:id:cpp-laboratory:20201211163315p:plain

(5) 一旦コミットして,GitHubにプッシュする

さて,ここまでのところ,一旦Gitでコミットして,GitHubにプッシュしておきます。RstudioのGitタブで,Commitをクリックします。

f:id:cpp-laboratory:20201211164357p:plain

以下のような画面でてくるので,ファイルを全て選択して,Stageをクリックします。

f:id:cpp-laboratory:20201211164401p:plain

Commit messageにコメントを書きます。ここでは,適当にinit commitとかにしてみました。Commitをクリックして,終わったら,閉じます。

f:id:cpp-laboratory:20201211164405p:plain

さて,通常はこのcommitの画面でプッシュできますが,最初は以下のコードをRsutidoのTerminalに打ち込みます。これで,GitHub上にファイルや変更点がプッシュされます。

git branch -M main
git push -u origin main

(6) Rの関数を作成して,roxygenコメントを書き込む

これでパッケージ作成の下準備が整いました。ここから,パッケージのRフォルダ内にRの関数を書いていったり,それを文章化するためのroxygenコメントを書いていきます。まず,Rフォルダ内に,新規でRのファイルを作成し,先程のRの関数を貼り付けて,easy_slack.Rという名前で保存します。

次に,roxygenコメントを書きます。roxygenコメントとは, #' から始まるもので,@XXXによって,タイトル,説明,関数内で使用する他のパッケージ,出力,例などを書きます。これをやっておくと,あとで勝手にRで使われるマニュアルの形式にしてくれます(便利!)。おおよそ以下がR関数の記述の前にあればいいかなと思います。

#' @title タイトル(関数がすることを書くと良い)
#' @description \code{関数名} 説明(関数がすることを書くと良い)
#'
#' @importFrom パッケージ名 関数名
#' @param 引数 説明 
#' @return 出力の説明
#' @export
#' @examples
#' 関数の例

今回は,特に出力をだす関数じゃないので,@returnはないのですが,それ以外は,上記と同じように以下のように設定します。なお,@exportはユーザーが実行する関数につけます。今回,set_slack()もsend_slack()もユーザーが実行するので,@exportをつけます。

#' @title Setting the slack information to system
#' @description \code{set_slack} set the slack information to system
#'
#' @param slack_token slack acess token
#' @param slack_channel slack channel
#' @param slack_username slack username
#' @export
#' @examples
#' # set_slack("GitHub access token", "#r", "Mr.R")

set_slack <- function(slack_token,
                      slack_channel = "#general",
                      slack_username = "R"){
  if(missing(slack_token)){
    stop("Please set slack_token")
  }
  Sys.setenv(SLACK_TOKEN=slack_token)
  Sys.setenv(SLACK_CHANNEL=slack_channel)
  Sys.setenv(SLACK_USERNAME=slack_username)
}


#' @title Sending the message to slack channel
#' @description \code{send_slack} send the message to slack channel
#'
#' @importFrom httr POST
#' @param message message send to slack
#' @export
#' @examples
#' # send_slack("Hello!")

send_slack <- function(message = "Analysis has been completed"){
  # check argument
  if (Sys.getenv("SLACK_TOKEN") == "") {
    stop("Please set slack_token with set_slack")
  }
  if (Sys.getenv("SLACK_CHANNEL") == "") {
    stop("Please set slack_channel with set_slack")
  }
  if (Sys.getenv("SLACK_USERNAME") == "") {
    stop("Please set slack_username with set_slack")
  }

  # send message to slack
  httr::POST(url="https://slack.com/api/chat.postMessage",
             body = list(token = Sys.getenv("SLACK_TOKEN"),
                         channel = Sys.getenv("SLACK_CHANNEL"),
                         username = Sys.getenv("SLACK_USERNAME"),
                         text = paste(format(as.POSIXlt(Sys.time(), tz = "Asia/Tokyo"),"%Y/%m/%d %H:%M"),message)))
}

roxygenが書けたら,以下を実行します。すると,manフォルダ内に関数ごとにマニュアルが作成されます。これは,後でパッケージとしてインストールしたら,help()で見ることができます。

devtools::document()

send_slack()関数では,roxygenで@importFrom httr POSTと書いています。つまり,httrパッケージのPOST関数を使います。これをDESCRIPTIONに書き込む必要がありますが,以下のusethis::use_package()を使えば書き込んでくれます。以下をConsoleで実行します。

usethis::use_package("httr")

DESCRIPTIONをみると,Imports: httrが追加されています。

f:id:cpp-laboratory:20201211175256p:plain

動作確認をしてみましょう。devtools::load_all()を使うとインストールせずに,パッケージの関数などを確認できます。devtools::load_all()した上で,set_slack()とsend_slack()を確認します。slackのトークンとチャンネルを適切に設定した上で(XXXXと#r),以下をConsoleで実行します。

devtools::load_all()

set_slack("XXXXXXXXXXX","#r", "R博士")
send_slack()

動作してそうです。

f:id:cpp-laboratory:20201212042711p:plain

slackにも無事に通知がきました。

f:id:cpp-laboratory:20201211175300p:plain

さて,ここまできたら,devtools::check()でビルドとチェックをします。

devtools::check()

実行すると何かごにょごにょやって,もし問題があればエラーなどが出ます(以下は全て問題ない場合です)。なお,実行途中で止まることがありますが,その場合は,このRパッケージ作成用プロジェクトを開き直すと良いかもしれません(理由は分からないけどうまくいくことが多い謎Tipsです)。

f:id:cpp-laboratory:20201212041035p:plain

Rパッケージの完成までは,以下を繰り返します。

  1. Rフォルダ内でR関数とroxygen書く
  2. 適宜devtools::document()やusethis::use_package()を実行する
  3. devtools::load_all()で動作確認する
  4. devtools::check()を実行する

(7) GitHub経由でインストールして,動作確認する

完成したら,GitHub経由でインストールしてみましょう。一旦,パッケージ作成用のプロジェクトを閉じます(FileのClose project)。Consoleに以下を打ち込んでインストールします。

remotes::install_github("ykunisato/easySlack")

インストールが無事にできたら,早速関数を使ってみてテストをしてみます。

library(easySlack)
set_slack("GitHubのアクセストークン", "#チャンネル名", "ユーザー名")
send_slack()

無事にslackに送れました!

f:id:cpp-laboratory:20201211175300p:plain

さらにConsoleに以下を打ち込むと,ヘルプが出てきます。

?set_slack

roxygenで書いた内容が反映されています。ただ,もう少しドキュメントをちゃんと作らないとですね(急いでやったので英語も適当です)。

f:id:cpp-laboratory:20201212044001p:plain

今回作ったパッケージのGitHubリポジトリは以下になります。練習用ではありますが,ちょっとずつ整備をしてみようかと思います。

github.com

Enjoy!

今日からできる再現可能な論文執筆

これは,Open and Reproducible Science Advent Calendar 2020 - Adventar9日目の記事です。竹林由武さんと一緒に,日本心理学会第84回大会において,チュートリアル・ワークショップ「今日からできる再現可能な論文執筆」を行ってきました。以下は,当日の配布資料になります。

ykunisato.github.io

今回も若干省エネ記事ですが,上記の配布資料にはかなり時間を費やしたので,楽しんでいただけたら嬉しいです。

Enjoy!

再現可能性入門と最近の動向

これは,Open and Reproducible Science Advent Calendar 2020 - Adventar7日目の記事です。

2020年1月24日に第25回計算論的精神医学コロキウム(CPSYコロキウム)にて「再現可能性入門と最近の動向」という発表を行いました。スライドは以下になります。結構前の発表になりますが,基本的な事項がまとまっているかと思います。

Enjoy!

コンセンサスに基づいた透明性チェックリスト

この記事は,Open and Reproducible Science Advent Calendar 2019の23日目の記事です。

Open and Reproducible Science Advent Calendar 2019では,オープンサイエンスにまつわる様々な話題を扱ってきました。オープンサイエンスに限らず,何か新しいことが始まると,「じゃあどうやればいいの?」と不安に感じる方も多いかと思います。私もそうです。私はいつも自分が行っている研究実践に懐疑的で強迫的に確認をしてしまいがちなので,何か指針があると安心します。特に複数の専門家が議論してコンセンサスの得られたガイドラインやチェックリストだとその安心感が増します。

オープンサイエンスに特化した内容ではありませんが,研究に関連したそのようなコンセンサスに基づいたガイドラインとしては,研究の報告ガイドラインがあります。研究報告ガイドラインについては,EQUATOR (Enhancing the QUAlity and Transparency Of health Research) Networkにリストがあるので,参照すると良いかと思います。EQUATOR Networkで紹介されている報告ガイドラインに従って研究報告をすれば,研究の透明性が高くなるかと思います。

www.equator-network.org

研究デザインごとの有名なガイドラインとしては,以下のようなものがあります。以下は医学で用いられる研究デザインですが,医学に限定される内容ではないかと思います。

研究デザイン ガイドライン
無作為化比較試験 CONSORT
観察研究 STROBE
系統的レビュー PRISMA
研究プロトコル SPIRIT, PRISMA-P
診断精度,予後予測研究 STARD, TRIPOD
事例報告 CARE
臨床実践ガイドライン AGREE, RIGHT
質的研究 SRQR, COREQ
動物対象前臨床研究 ARRIVE
質向上研究 SQUIRE
経済評価 CHEERS

これらの研究報告ガイドラインについては,奥村泰之さんが主催されている「臨床疫学研究における報告の質向上のための統計学の研究会」にて,取り上げられていますので,是非とも過去資料などをご確認ください。

それでは,オープンサイエンス系のガイドラインやチェックリストとしては,何があるでしょうか?

TOPガイドライン

まず,オープンサイエンス系のガイドラインとして,Science誌で発表されたTransparency and Openness Promotion (TOP)ガイドライン*1があります。これは,個人というよりは,学術誌のポリシーに関するもので,その雑誌がどの程度オープンサイエンスを志向したものか検討する際に使えるものです。オープンサイエンスを推進する上では,研究者のインセンティブを適切に設計する必要があります。オープンサイエンスに関するガイドラインを作成し,雑誌がそれを採用すると,投稿者にとってオープンサイエンスを行うインセンティブが上がります。こういうガイドラインの設定によって,研究業界におけるオープンサイエンスの普及が進むと期待されます。

TOPガイドラインでは,8つの基準(Citation Standards,Data Transparency,Analytic Methods (Code) Transparency,Research Materials Transparency,Design and Analysis Transparency,Study Preregistration,Analysis Plan Preregistration,Replication)が設定され,それぞれについて,Not Implemented,レベル1,レベル2,レベル3で評価します(詳しくは,以下のSummary Tableを確認ください)。研究者が雑誌のオープンサイエンス度を評価する際にも使えますし,雑誌の編集委員会などで,雑誌のオープンサイエンスに関するポリシーを決める上でも活用できるかと思います。以下のOSFのリポジトリには,TOPガイドラインを採用している雑誌のリストなどもありますので,ご確認いただくと良いかと思います。

cos.io

TOPガイドラインは雑誌向けのものなので,私達が自分自身の研究実践を評価するにはどういうものがあるでしょうか?

コンセンサスに基づいた透明性チェックリスト

個々の研究のオープンサイエンス度の評価には,Nature Human Behaviour誌に発表されたコンセンサスに基づいた透明性チェックリスト*2が使えます。この透明性チェックリストは,行動・社会科学の研究者用に作成されたもので,投稿時にこのチェックリストも提出するという取り組みを通して,オープンサイエンス実践が広がることを期待するものになります。また,読者としては,このチェックリストを使って評価したり,提出されたリストを確認することで,当該論文の透明性を評価できます。

このチェックリストの作成にあたり,45名の学術誌の主任エディターと18名のオープンサイエンスの推進者が参加しました。コンセンサスの形成には,デルファイ法を使っています。デルファイ法は,研究報告ガイドラインなどでも活用される,専門家を対象としたコンセンサス形成の手法になります。具体的には,専門家を対象に匿名のアンケート調査を行って,その結果を集計したものをフィードバックして,再度アンケート調査を行います。これを反復して,意見が収束してきたら終了します。匿名で意見を集めるという方法をとることで,声の大きい人や権威者の意見に流されるということがなくなるというのがデルファイ法のメリットです。このチェックリストでは,デルファイ法のプロセスを通して,インタラクティブに修正が加えられました(項目の追加,削除,言い換えなど)。そして,最終的に,事前登録,方法,結果と考察,データ・コード・マテリアル入手可能性の4領域にわたる36項目のチェックリストを作成しています。また,短縮版の12項目版も作成しています。

なお,このチェックリスト作成にあたって,著者達は作成プロセスについて,事前登録をしています(事前登録内容はこちら)。また,作成にあったって使用したマテリアルもOSFに公開されています(使用されたマテリアルはこちら)。

作成された32項目版は以下から見れます(Shinyアプリになっており,必要事項を記入したり,チェックをいれると最終的に文章化されて出力されます)。

www.shinyapps.org

短縮版(12項目版)は以下から見れます。

www.shinyapps.org

第一著者のBalazs Aczelがこのチェックリストの多言語対応をするべく翻訳ボランティアを募集しました。私も参加しましたので,またあとで日本語版も公開されることになると思います。

その日本語版のドラフト版として,短縮版を翻訳してみました。12項目のうち,項目2以外は,Yes, No, N/Aで回答します。翻訳に誤りなどを見つけられましたら,是非ともこちらまでご指摘ください。

コンセンサスに基づいた透明性チェックリスト(短縮版)

(1) 完全データセットを分析する前に,タイムスタンプ付きの事前登録が,データ分析計画のための独立した第3者レジストリに投稿された。

(2) 研究が次のタイミングで事前登録された。

  • データが収集される前
  • いくつかのデータが収集された後だが,データを調べる前
  • すべてのデータが収集された後だが,データを調べる前
  • データを調べた後だが,統計分析を行う前
  • すべてではないがいくつかの統計分析が行われた後
  • 他の時点。説明(    )

(3) それぞれの研究疑問に対する意図された統計分析(例えば,検定の両側・片側,推論の規準,多重検定の補正,モデル選択規準,事前分布などに関する情報がこれに求められるかもしれない)

(4) 使用したサンプルサイズの理論的根拠(例,事前の検定力分析)

(5) 独立した追試を可能にする研究デザイン,手続き,および資料

(6) 関心のある測度(例,親しみやすさ)およびそれらの操作化(例,親しみやすさを測定する質問紙)

(7) 事前登録の変更(資格基準,グループに入れるカットオフ,または実験手順の変更など)

(8) 「確証的」(すなわち,事前に指定された)分析と「探索的」(すなわち,事前に指定されていない)分析とを明示的に区別している

(9) 原稿の分析の元となった(処理済み)データ

(10) すべてのコードとソフトウェア(著作権で保護されていないもの)

(11) すべての教示,刺激,および検査マテリアル(著作権で保護されていないもの)

(12) 原稿には,研究に関連するデータ,マテリアル,コードを含む,すべての研究項目の入手可能性と場所に関する記述が含まれている

透明性チェックリストは,専門家のコンセンサスの得られたものですし,使うのも簡単(大きな負担はない)です。透明性チェックリストの著者も述べていますが,ユーザーに過度な負担をかけないツールを作っていくこともとても大切な取り組みですね。

*1:Nosek, B. A., Alter, G., Banks, G. C., Borsboom, D., Bowman, S. D., Breckler, S. J., … Yarkoni, T. (2015). Promoting an open research culture. Science, 348(6242), 1422–1425.

*2:Aczel, B., Szaszi, B., Sarafoglou, A., Kekecs, Z., Kucharský, Š., Benjamin, D., … Wagenmakers, E.-J. (2019). A consensus-based transparency checklist. Nature Human Behaviour. https://doi.org/10.1038/s41562-019-0772-6

心理学における理論の危機について

この記事は,Open and Reproducible Science Advent Calendar 2019の8日目の記事です。

事前登録はよくても不必要?

2019年の11月初めに,Aba SzollosiらのPreregistration is redundant, at bestというタイトルのプレプリントが出ました*1。事前登録は良くても不必要という感じの少々過激なタイトルということもあって,Brian Nosekがそれを以下のツイートで紹介をしてから,Twitter上で議論がなされていました。

心理学の再現性の問題に対しては,データ収集前に研究仮説やデータ収集・解析プランなどを事前に登録して,研究者がデータ取得後に不適切な研究実践をしないように研究者の自由度を奪うことが重要とされています。しかし,"Preregistration is redundant, at best"論文では,科学が理論を作って磨くものであるなら,事前登録はそれには直接的には寄与しない(するとしてもあまり関係ないから無駄)と主張しています。心理学の場合,理論と統計モデルは密接に関与するので,理論がグズグズだと事前登録してもだめというのはそのように思えますし,事前登録していることだけで論文の価値が高いとするのは微妙ではないかという主張には納得できる部分もあります。

この議論が沸き起こった直後にDaniel Lakensが心理学評論の草稿を彼のブログ The 20% Statisticianにアップして(心理学評論のプレプリントは,こちら),事前登録の有用性はその研究がよってたつ科学哲学に依存する点を指摘しています(なお,議論の中で,MayoのSevere Testを参照しつつ論じており勉強になります)。さらに,Eric-Jan Wagenmakersが彼のブログBayesianSpectaclesで,"Preregistration is redundant, at best"論文の1パラグラフごとにコメントをした上で,タイトルの過激さはともかく,論文の内容にはほぼ同意するとしています。しかし,事前登録不要といえるほど強い理論が心理学にはないのではないので,事前登録を使うことには意味があるのではないかと指摘しています。事前登録について議論する上では,よってたつ科学哲学や理論についても考慮することが重要といえます。

心理学の理論の危機

SzollosiらのPreregistration is redundant, at best論文でも指摘されているように,心理学の再現性の議論の中では理論の強さが度々出てきます。心理学には再現性の危機がある点は多くの心理学者の知るところとなりましたが,理論の問題についてはまだ関心が薄いのではないかと思います。このような心理学における理論の弱さと再現性の問題を理解する上で,Klaus OberauerとStephan Lewandowskyの"Addressing the theory crisis in psychology"論文*2の枠組みは非常に有用です。そこで,本記事では,"Addressing the theory crisis in psychology"論文の概要についてRコードとともに紹介します。

link.springer.com

理論検証研究(Theory-testing research)と発見志向研究(Discovery-oriented research)

まず," Addressing the theory crisis in psychology"論文では,理論,仮説,データとの関係を以下の図(元論文のFig.1をもとに作成しました)のように整理しています*3。理論は仮説の設定をする上で示唆を与えるものになります。そして,仮説を設定した上でデータを収集し,そのデータによって仮説の補強(支持)・修正,さらに理論の補強(支持)・修正をします。データの結果から,直接理論について議論することがありますが,仮説を挟んでいることを意識するのは重要です。OberauerとLewandowskyは,理論と仮説とのやりとりは理論的レベル,仮説とデータのやりとりは実証レベルと呼びます。理論と仮説との関係は論理的に検証されるもので,仮説とデータとの関係は経験的に検証されるものになります。そして,理論の強さというのは,理論から仮説が導かれる際のリンクの強さになります。OberauerとLewandowskyは,その理論から仮説が導かれる際のリンクの強さによって,理論検証研究(Theory-testing research)と発見志向研究(Discovery-oriented research)に分けて検討を行っています。理論検証研究は,理論と仮説のリンクが強く,理論から導かれた仮説は事実に違いない(must be the case)というものです。一方,発見志向研究は,理論と仮説のリンクが弱く,理論から導かれた仮説は事実になり得る(can be the case)というものです。

f:id:cpp-laboratory:20191206084200p:plain

上記の図に" Addressing the theory crisis in psychology"論文にある数式を追加したのが以下の図です(元論文のFig.1とTable2と3をもとに作成しました)。まず,理論検証研究と発見志向研究の違いは理論から仮説を推測する際のリンクの強さでしたが,それは,以下の図のP(H|T)とP(H|¬T)になります。P(H|T)は理論Tが正しい場合の仮説Hの確率,P(H|¬T)は理論Tが正しくない場合の仮説Hの確率です。P(H|T)が高いほど,理論検証研究になります。そして,仮説HからデータDが得られる確率を推測する場合は,P(D|H)やP(D|¬H)を使いますが,P(D|H)は検定力,P(D|¬H)は有意確率になります。そして,これらが準備できたら,仮説を支持するデータDが得られた時の仮説の確率P(H|D)や仮説Hが正しい場合の理論Tの確率P(T|H)はベイズの定理から計算できます。最後に,P(H|D)とP(T|H)をまとめて,仮説を支持するデータが得られた時の理論Tの確率P(T|D)を求めることもできます。ちょっと図に書き込まれた数式に「うっ」となるかもしれないですが,結構単純ですし,統計的検定をまた違った観点から見ることができるので,新鮮かと思います。

f:id:cpp-laboratory:20191207174617p:plain

さて,図の左側のP(H|T),P(H|¬T),P(D|H),P(D|¬H)やP(T)を設定すれば,データDの下での仮説Hや理論Tの確率を計算できます。その計算をするR関数compute_prob_theory を以下のように作成してみました(tidyverseパッケージがRにインストールされていれば,以降のコードをRコンソールにコピペして実行することで,結果が再現できると思います)。

library(tidyverse)

compute_prob_theory <- function(pH_Ttrue, 
                          pH_Tfalse,
                          alpha = 0.05,
                          power = 0.8,
                          pT = 0.5){
  pT_Htrue = (pH_Ttrue*pT)/(pH_Ttrue*pT+pH_Tfalse*(1-pT))  
  pT_Hfalse = ((1-pH_Ttrue)*pT)/((1-pH_Ttrue)*pT+(1-pH_Tfalse)*(1-pT))
  pH = pH_Ttrue*pT + pH_Tfalse*(1-pT)
  pH_Dtrue =  (power*pH)/(power*pH + alpha*(1-pH))
  pT_Dtrue =  pT_Htrue*pH_Dtrue+pT_Hfalse*(1-pH_Dtrue)
  pH_Dfalse = ((1-power)*pH)/((1-power)*pH + (1-alpha)*(1-pH))
  pT_Dfalse = pT_Htrue*pH_Dfalse+pT_Hfalse*(1-pH_Dfalse)
  return( list(pH_Dtrue=pH_Dtrue, 
               pT_Dtrue=pT_Dtrue,
               pH_Dfalse=pH_Dfalse,
               pT_Dfalse=pT_Dfalse) )
}

理論検証研究の例

早速,関数を使ってみましょう。まず," Addressing the theory crisis in psychology"論文にある理論検証研究の例を計算してみます。P(H|T)を1.0(compute_prob_theory関数の引数のpH_Ttrue を 1に),p(H|¬T)を0.2(compute_prob_theory関数の引数のpH_Tfalseを0.2に)に設定して計算します。P(H|T)が1.0,つまり100%なので,理論から非常に高い確率で仮説を導ける場合です。なお,α=0.05, 1-β=0.8, P(T)=0.5(つまり,理論が正しい確率は50%で,正しいとも間違っているともいえない)に設定しています。

compute_prob_theory(pH_Ttrue = 1,pH_Tfalse = 0.2)

計算結果は以下のようになります。理論から非常に高い確率で仮説を導ける場合,仮説通りのデータDが得られた時の仮説Hが正しい確率は(pH_Dtrue)96%で,理論Tが正しい確率は(pT_Dtrue)80%になります。どちらも高い確率ですね。

$pH_Dtrue [1] 0.96

$pT_Dtrue [1] 0.8

$pH_Dfalse [1] 0.24

$pT_Dfalse [1] 0.2

発見志向研究の例

次に,論文にある発見志向研究の例を計算してみます。P(H|T)を0.1(引数のpH_Ttrue を 0.1),p(H|¬T)を0.02(引数のpH_Tfalseを0.02)に設定して計算します。P(H|T)が0.1,つまり10%なので,理論から仮説を導ける確率は低いです。

compute_prob_theory(pH_Ttrue = 0.1,pH_Tfalse = 0.02)

計算結果は以下のようになります。理論から仮説を導ける確率が低い場合,仮説通りのデータDが得られた時でも,仮説Hが正しい確率は(pH_Dtrue)51%で,理論Tが正しい確率は(pT_Dtrue)66%になります。最初に,P(T)=0.5にしているので,データが得られても,理論の確率は大きな変化をしていません。理論から仮説を導ける確率が低い場合,支持するデータが得られてもチャンスレベルの評価になるというのはなかなかびっくりな結果かもしれません。

$pH_Dtrue [1] 0.5052632

$pT_Dtrue [1] 0.6578947

$pH_Dfalse [1] 0.01325967

$pT_Dfalse [1] 0.4834254

この計算結果からも分かるように,同じ仮説Hを支持するようなデータDが得られたとしても,理論Tから仮説Hが導かれる確率が低いと(仮説と理論との推論リンクが弱いと),仮説や理論が正しいとする確率が低くなります。

なお,理論検証研究と発見志向研究と分けていますが,理論から仮説を導く確率は連続的なものなので,明確に分けられるものではありません。以下では,P(H|T)を0.1から1.0まで変化させた時の仮説を支持するデータDが得られた時の理論の確率(P(T|D))と仮説を支持しないデータDが得られた時の理論の確率(P(T|¬D))をプロットしています(論文のFig2の右の図に対応します)。

pH_Ttrue = seq(0.1,1,by = 0.1)
pH_Tfalse = seq(0.02,0.2,by = 0.02)
data <- compute_prob_theory(pH_Ttrue,pH_Tfalse)
plot_data <- data.frame(pH_Ttrue=c(pH_Ttrue,pH_Ttrue),
                        pT_D = c(data$pT_Dtrue,data$pT_Dfalse),
                        Data = rep(c("D_True","D_False"),each=10))

plot_data %>% 
  ggplot(aes(x = pH_Ttrue,y = pT_D, color = Data)) +
  geom_line() + geom_point() + 
  ylim(0,1) + labs(y="P(T|Data)", x = "P(H|T)")

f:id:cpp-laboratory:20191208044550p:plain

図を見ても明らかなように,理論と仮説とのリンクが強いほど,データから理論の正しさ(誤り)を主張することができます。理論と仮説とのリンクが強い研究を行うことが必要といえます。理論と仮説とのリンクが弱い発見志向研究が多いことが心理学の再現性の問題を引き起こしているのでないかとOberauerとLewandowskyは指摘しています。

追試か第2の仮説の検討か?

OberauerとLewandowskyは,再現性の危機に対する改善策(厳しい有意水準の採用,検定力の大きな直接的追試,オープンデータ,探索と確証分析を分ける,事前登録)のそれぞれについて,上記の枠組みから検討を加えています。その中から,以下では,理論検証研究と発見志向研究において,追試もしくは理論から導ける別の仮説(第2の仮説)の検討を行うことで理論の正しさに関する確率がどのように変わるのか検討した内容を紹介します。上で作成したR関数compute_prob_theoryに,論文のTable4の計算を追加したcompute_prob_theory_rep関数を以下のように作成しました。compute_prob_theory_rep関数では,データD1を収集した後で追試した場合の理論が正しい確率とデータD1を収集した後で別の仮説(第2の仮説)のデータD2を収集した場合の理論が正しい確率を計算します。

compute_prob_theory_rep <- function(pH_Ttrue, 
                                pH_Tfalse,
                                alpha = 0.05,
                                power = 0.8,
                                pT = 0.5){
  pT_Htrue = (pH_Ttrue*pT)/(pH_Ttrue*pT+pH_Tfalse*(1-pT))  
  pT_Hfalse = ((1-pH_Ttrue)*pT)/((1-pH_Ttrue)*pT+(1-pH_Tfalse)*(1-pT))
  pH = pH_Ttrue*pT + pH_Tfalse*(1-pT)
  pH_Dtrue =  (power*pH)/(power*pH + alpha*(1-pH))
  pT_Dtrue =  pT_Htrue*pH_Dtrue+pT_Hfalse*(1-pH_Dtrue)
  pH_Dfalse = ((1-power)*pH)/((1-power)*pH + (1-alpha)*(1-pH))
  pT_Dfalse = pT_Htrue*pH_Dfalse+pT_Hfalse*(1-pH_Dfalse)
  # replication
  pH_D_rep =  (power*pH_Dtrue)/(power*pH_Dtrue + alpha*(1-pH_Dtrue))
  pT_D_rep =  pT_Htrue*pH_D_rep+pT_Hfalse*(1-pH_D_rep)
  # 2nd Hypothesis(Y)
  pH2 = pH_Ttrue*pT_Dtrue+pH_Tfalse*(1-pT_Dtrue)
  pH2_D2true = (power*pH2)/(power*pH2 + alpha*(1-pH2))
  pT_D1true_H2true = (pH_Ttrue*pT_Dtrue)/(pH_Ttrue*pT_Dtrue+pH_Tfalse*(1-pT_Dtrue))
  pT_D1true_H2false = ((1-pH_Ttrue)*pT_Dtrue)/((1-pH_Ttrue)*pT_Dtrue+(1-pH_Tfalse)*(1-pT_Dtrue)) 
  pT_D1_2true =  pT_D1true_H2true*pH2_D2true + pT_D1true_H2false*(1-pH2_D2true)
  return( list(pT_Dtrue=pT_Dtrue,
               pT_D_rep=pT_D_rep,
               pT_D1_2true = pT_D1_2true) )
}

発見志向研究で追試,第2の仮説の検討をしたら?

上記と同じように,理論から仮説を導ける確率P(H|T)が0.1と低い場合において,追試と第2の仮説を検証した場合の理論の正しさの確率を計算します。今回は,理論の正しさの確率P(T)を0から0.9まで変化させてプロットしています。プロットをみると,オリジナルの研究だけよりも追試や第2の仮説の検証もした方が,支持するデータが得られた場合の理論の正しさの確率が高くなります。この結果から,発見志向研究では追試や第2の仮説は重要であることがわかります。

pT = seq(0,0.9,by = 0.1)
data_rep1 <- compute_prob_theory_rep(pH_Ttrue=0.1,pH_Tfalse=0.02,pT=pT)

plot_data1 <- data.frame(pT=c(pT,pT,pT),
                        pT_D = c(data_rep1$pT_Dtrue,data_rep1$pT_D_rep,data_rep1$pT_D1_2true),
                        Data = rep(c("Original","Replication","2nd Hypothesis"),each=10))

plot_data1 %>% 
  ggplot(aes(x = pT,y = pT_D, color = Data)) +
  geom_line() + geom_point() + 
  ylim(0,1) + labs(y="P(H|Data)", x = "P(T)")

f:id:cpp-laboratory:20191208044609p:plain

理論検証研究で追試,第2の仮説の検討をしたら?

次に,理論から仮説を導ける確率P(H|T)が1.0と高い場合において,追試と第2の仮説を検証した場合の理論の正しさの確率を計算します。発見志向研究と同様に,理論の正しさの確率P(T)を0から0.9まで変化させてプロットします。結果をみると,追試を追加したとしても,オジリナルな研究だけよりも,支持するデータが得られた場合の理論の正しさの確率はあまり高くなりません。その一方,第2の仮説の検証を追加することは,支持するデータが得られた場合の理論の正しさの確率を高くする結果になりました。この結果から,理論検証研究では追試よりも第2の仮説の検証が重要であることがわかります。

pT = seq(0,0.9,by = 0.1)
data_rep2 <- compute_prob_theory_rep(pH_Ttrue=1,pH_Tfalse=0.2,pT=pT)

plot_data2 <- data.frame(pT=c(pT,pT,pT),
                         pT_D = c(data_rep2$pT_Dtrue,data_rep2$pT_D_rep,data_rep2$pT_D1_2true),
                         Data = rep(c("Original","Replication","2nd Hypothesis"),each=10))

plot_data2 %>% 
  ggplot(aes(x = pT,y = pT_D, color = Data)) +
  geom_line() + geom_point() + 
  ylim(0,1) + labs(y="P(H|Data)", x = "P(T)")

f:id:cpp-laboratory:20191208044632p:plain

まとめ

今回は紹介ができませんでしたが,OberauerとLewandowskyは,有意水準を下げる(必要なサンプルサイズを大きくする)ことは理論検証研究ではあまり有効ではないが,発見志向研究では有効であることも示しています。それらも踏まえると,以下のように整理できます。

  • 理論が弱く,理論から十分に仮説を導けない場合は,発見志向研究を行う。発見志向研究では,理論の正しさについて議論するには,サンプルサイズを大きくすることと直接的追試が必要になる。

  • 理論が強く,理論から十分に仮説が導ける場合は,理論検証研究を行う。理論検証研究では,理論の正しさについて議論するには,直接的追試よりは第2の仮説の検証が重要になる。

" Addressing the theory crisis in psychology"論文は,簡単な仮定から理論・仮説・データの関係,さらには追試や第2の仮説検証の意義まで検討することができて,非常に面白いです。なお,この論文の内容に関する,以下のStephan Lewandowskyのトークを聴きに行きましたが,非常に面白かったです。

ただ,理論と仮説とのリンクが重要なことは分かるのですが,そのような理論の構築の仕方や理論から仮説を導く方法とはどういうものがあるのか実はよくわからないなあと感じています(そういう教育を受けた記憶があまり無いような・・・)。少なくとも自分のこれまでの研究実践を振り返ると,かなり発見志向的で理論検証的には進められてなかったように思います。心理学の再現性の議論は,実証レベルで議論されることが多いとは思いますが,今後は理論レベルでの検討が進み,その方法論の整備も進むと良いのではないかなあと期待しています。

一筋縄ではいかない話題ですが,心理学の研究実践が徐々に良いものになっていけばと思います。

Enjoy!

*1:Szollosi, A., Kellen, D., Navarro, D., Shiffrin, R., van Rooij, I., Van Zandt, T., & Donkin, C. (2019, October 31). Is preregistration worthwhile?. https://doi.org/10.31234/osf.io/x36pz

*2:Oberauer, K., & Lewandowsky, S. (2019). Addressing the theory crisis in psychology. Psychonomic Bulletin & Review. https://doi.org/10.3758/s13423-019-01645-2

*3:元の論文では仮説はX,データは"x"という表記にしてありました。仮説が複数ある場合などは論文の元の表記の方が扱いやすいですが,ちょっと混乱するので,今回は仮説はH,データはDという表記にしています。