タグ:factor

医療統計に限らず、データを分析する時に集計表を出す場面は多くあります。

特に医療統計ではtable1として図表の最初に提示することが多いです。

スクリーンショット 2020-09-12 9.37.17

ポスター発表だとPower Pointでしょうか。
スクリーンショット 2020-09-12 9.38.30

論文であればWordを使うかもしれません。
スクリーンショット 2020-09-12 9.40.28

このtable1を作る時は基本次のような作業が必要になります。
・Excelで集計
・コピー
・WordやPower Pointに張り付け、もしくは手打ち
・体裁を整える

これが意外とめんどくさい作業なのですがRを使えば一度に行えます。
・Excelでデータを集める
・Rで集計→体裁を整える→Word, Power Point, 図として出力する

今回はgtsummaryパッケージを紹介します!


そしてこの記事を書いている最中にgtsumarryパッケージの作者であるDaniel Sjobergさん(@statistishdan)より直接アドバイスを頂きました。この場を借りてお礼申し上げます。



改善点やリクエストがあれば連絡が欲しいとのことでした。自分もいくつかリクエストさせていただきましたが、疑問点や改善点あればご指摘いただければ連絡してみるのはいかがでしょうか。




1.データの準備
今回は【1-11】Rで医療統計で必要なtable1を作るtableoneパッケージについて紹介しますで使用したデータと同じものを使います。


set.seed(1)
年齢 <- floor(rnorm(100,60,10))
性別 <- sample(c("男性","女性"),100,replace = TRUE)
体重 <- floor(rnorm(100,60,7))
MMT <- as.numeric(sample(c(1:5), 100, prob = c(0.1,0.1,0.2,0.3,0.3), replace = TRUE))
術側 <- sample(c("右","左"),100,replace = TRUE)
治療 <- sample(c(0,1),100,replace = TRUE)
data <- data.frame(年齢,性別,体重,MMT,術側,治療)
data
今回は治療(0:対照群、1:治療群)として分けていきます。


もしご自身のExcelデータで取り込み方がわからない場合は【4-0】第4章を進めていく上での準備をご参照ください。プロジェクトの使い方やExcelデータの読み込みについて紹介しています。


2.ライブラリの読み込み

一言でいうとライブラリとはRの機能を拡張してくれる機能の事です。

今回は4つのライブラリを使います
gtsummary(table1や結果の表をいい感じにまとめてくれる)
tidyverse(データの集計などに使用。今回はサブ的に使う)
gt(gtsummaryのデータをもっと細かく修正することができる。gtsummaryだけで完結するので必要ないが、表のタイトルやサブタイトルを付け加えたかったら必要)
flextable(できた表をWordやPower Point形式に貼り付ける際、gtsummaryよりも細かいく修正することができる。gtsummaryだけで完結するので必要ないが、表のタイトルやサブタイトルを付け加えたかったら必要)

rstudioのPackagesをみて自分のパソコンにインストールされているか確認してみてください。
このリストに入っていなかったり、最新のパッケージにしたい場合は以下のコードをコピペして実行してください。この操作は毎回する必要はありません。

install.packages("gtsummary")
install.packages("tidyverse")
install.packages("gt")
install.packages("flextable")

ライブラリがインストールできていれば今度はパッケージを読み込みます。
基本Rstudioを起動すると基本のパッケージしか使えない状態です。
パッケージは毎回呼び出す必要がありlibrary関数を使います。
まずは今回の記事で必要なgtsummaryとtidyverseを読み込みます。

library(gtsummary)
library(tidyverse)

これで準備は完了です。


3.表を作る前に確認しておくこと


table1はそもそも各群のベースラインを比較します。

スクリーンショット 2020-09-12 9.38.30


そのためには各変数(評価)がどんなデータか理解している必要があります


数値かカテゴリーか?

集計を行うにはその変数が数値なのか?カテゴリー変数なのか?の理解が必要です。

数値:年齢・体重

カテゴリー:性別、MMT、術側

MMTは「1が7人、2が5人・・・」と集計を行いたいとすると、値は数値ですがカテゴリー変数として集計を行う必要があります。


数値の場合は正規分布なのか?そうでないのか?

同じ数値でも正規分布かそうでないのか?を決めておくことが必要です。

正規分布であれば平均±標準偏差ですが、正規分布でない場合は中央値(四分位範囲 or 最大値〜最小値)で表現したりします。


4.基本的な使い方

今から実際にgtsummaryを使っていきます。

まずは作ってみる

集計表を作るのはtbl_summary()関数を使います。

dataのデータをtbl_summary関数に入れ込みます。
これを表現するとdata %>% tbl_summary()と表記します。
%>%はパイプ演算子といい、最近Rでデータを扱う時の主流となっています。

data %>% 
  tbl_summary()
スクリーンショット 2020-09-12 13.43.17

とりあえず集計表ができました!ただ群別に表示がされていないので群を分けます。
tbl_summary(by = 群分けする列名)のようにby=○○を付け加えるだけです。

data %>% 
  tbl_summary(by = 治療)
スクリーンショット 2020-09-12 14.01.16
たった2行でそれらしい表ができてきました!


MMTはカテゴリーとして表にする予定で今回は必要ありませんでしたが、もしMMTがカテゴリーでなく数値として認識されるとこうなります。
スクリーンショット 2020-09-12 17.05.44
その場合はtbl_summary()内でtype = 変えたい変数名 ~ "○○"を加えます。
○○は3択で"continuous(数値)", "categorical(カテゴリー)", "dichotomous(2択)"の3種類です。 

data %>% 
  tbl_summary(by = 治療,
              type = MMT ~ "categorical")




テーマを決める

table1といっても投稿するジャーナルで投稿規定が違います。
gtsummaryではいくつかのテーマが用意されています。修正がいるかも知れませんが、最初からテーマが準備できているものは利用するのもありです。

公式では現在JAMAとLANCETのテーマがあります。
下の該当するコードを実行すれば、reset_gtsummary_tmeme()を実行するまではその設定が引き継がれます(Rstudioを再起動すればもとに戻る可能性が高いです)。

#JAMAの投稿規定に合わせる
theme_gtsummary_journal(journal = c("jama"), set_theme = TRUE)
#LANCETの投稿規定に合わせる
theme_gtsummary_journal(journal = c("lancet"), set_theme = TRUE)

#元の設定に戻す
reset_gtsummary_theme()

日本語にする

英語→日本語にする機能もあります。
(install.packagesで最新のバージョンをインストールしたらできました)
これもreset_gtsummary_tmeme()を実行するまではその設定が引き継がれます。
#日本語にする
theme_gtsummary_language("ja")
#元の設定に戻す
reset_gtsummary_theme()
スクリーンショット 2020-09-12 14.39.39

注釈などが日本語に変わりました。

幅を狭くする

できた表はゆとりがありますがコンパクトにまとめることもできます。
theme_gtsummary_compact()を実行するだけです。
これもreset_gtsummary_tmeme()を実行するまではその設定が引き継がれます。

#幅をコンパクトにまとめる
theme_gtsummary_compact()

#もとの設定に戻す
reset_gtsummary_theme()
スクリーンショット 2020-09-12 14.45.41

「中央値と四分位範囲じゃなくて平均と標準偏差にしたい」というツッコミは後で解説します。
まずはこのまま進めます。


p値の列を作る

次にp値の列を作ります。
作り方は%>%を使い、先程のコードにadd_p()を加えるだけです。

data %>% 
  tbl_summary(by = 治療) %>% 
  add_p()
スクリーンショット 2020-09-12 14.52.49
注釈までつけてくれました。
年齢と性別にはWilcoxonの順位和検定(マン・ホットニーのU検定)
性別と術側にはカイ二乗検定
MMTにFisherの正確確率検定が使われています。
「Wilcoxonの順位和検定じゃなくてt検定にして欲しい」という希望も後で紹介します。

*検定自体に関しては第4章に解説があります。サイトマップに一覧がありますので検定に関して知りたい場合は確認してください。



N数を加える
人数を加える場合はadd_n()を加えます。

data %>% 
  tbl_summary(by = 治療) %>% 
  add_p() %>% 
  add_n() 
スクリーンショット 2020-09-12 15.01.43
欠損値がないので全て100ですが、欠損値があるデータだと変わることはあります。


全体の集計の列を作る

もし全体の集計列を加えたければadd_overall()を加えます。
今回はadd_n()を外してadd_overall()を加えていますが、もちろんどちらも加えることも可能です。


data %>% 
  tbl_summary(by = 治療) %>% 
  add_p() %>% 
  add_overall() 
スクリーンショット 2020-09-12 15.05.19


変数名を太字にする
このままでもいいですが、変数名を太字にしてわかりやすくします。
bold_labels()を使います。

data %>% 
  tbl_summary(by = 治療) %>% 
  add_p() %>% 
  add_overall() %>%   
  bold_labels()
スクリーンショット 2020-09-12 16.04.08




5.出力する

まだまだ調整は必要ですが、とりあえずここで出力してみます。
スクリーンショット 2020-09-12 15.50.09

出力には出力のファイル形式(docやpdf,図など)にあわせてgtsummary内の型を変える必要があります。

スクリーンショット 2020-09-12 15.27.50
公式サイトより引用

出力の形式はgt,kable,flextableなどがあります。
デフォルトはgtとなっています。
gtとはRだけでいい感じの表を作るためのgtパッケージの形式です。
今まで見てきた表です。確かにとても綺麗です。




HTMLの場合

HTML形式の場合はこのまま出力できます。
右下のViwerからSave as Web Pageを選択します。
Save as ImageやCopy to Clipboardは日本語が入るとうまく機能しません。
画像として残したいならパソコンでスクリーンショットを撮ったほうが早いです。
スクリーンショット 2020-09-12 16.07.28


Office(Word, Power Point)の場合

Officeの場合はflextable形式に変換します。
先程のコードにas_table_frex()を加えます。
そしてtable1(他の名前でもいい)という変数を付けます。
今までずっとtheme_gtsummary_compact()を設定していたので小さなサイズの表になっています。
今回は一度リセットし再度日本語にした状態で行ってみます。

reset_gtsummary_theme()
theme_gtsummary_language("ja")
table1 <- data %>% tbl_summary(by = 治療) %>% add_p() %>% add_overall() %>% bold_labels() %>% as_flex_table() table1
スクリーンショット 2020-09-12 16.18.20
gt形式と雰囲気が変わりました。こちらのほうが論文で見た形に近いかもしれません。

次にこれをWordやPower Pointに変換しますが1行のコードでできてしまいます。
手っ取り早く変換するにはprint(今作った変数名, preview="○○")を使います。
preview="○○"はpreview="docx"preview="pptx"の2択です。

#Wordで開く場合
print(table1, preview = "docx")
スクリーンショット 2020-09-12 16.22.24


#Power Pointで開く場合
print(table1, preview = "pptx")
スクリーンショット 2020-09-12 16.26.25


どうでしょうか!!!
この後の文字サイズや修正もWordやPower Pointで直接できてしまいます!
これだけでもかなり時短になるかと思います。

ただ集計方法を平均(標準偏差)やt検定を使うためにはもう少しコードを変える必要があります。


6.様々な箇所を修正する
ここからは応用編になりますが、gtsummaryは色々な箇所を変更することができます。



・列名の順番:gtsummaryの前に修正しておく
・列内の文字の修正(0→対照群, 1→治療群など):gtsummaryの前に修正しておく

・集計:tbl_summary()
・p値:add_p()
・全体:overall()
・N:n()
・左上の変数名:modify_header()
・列名の上:modify_spanning_header()
・脚注:modify_footnote()

・タイトル、サブタイトル:gtsummaryで直接できない。(gtパッケージやflextableパッケージで編集する)

上記の()内にコードを追加することで細かい修正ができます。

7.変数を並べ替えたい

変数はdataの変数の並んでいる順になっています。
そのため並べ替えるには事前にdataの並び順を変える必要があります。
dataを並べ替えるには【2-4】Rで指定した列や行だけを取り出すselect関数、slice関数、filter関数を紹介しますで紹介したselect関数を使います。
data %>% select関数で並べ替える %>% tbl_summary() %>% ・・・とtbl_summary()の前に入れます。

data %>% 
  select(治療,年齢,体重,性別,術側,MMT) %>% 
  tbl_summary(by = 治療) %>% 
  add_p() %>% 
  add_overall() %>%   
  bold_labels()
スクリーンショット 2020-09-12 16.38.50


8.列内の文字の修正(0→対照群など)

今は治療が0,1となっています。
修正するにはgtsummaryの前にdataのデータ自体を修正します。
列を修正するには【2-2】Rのmutate関数を使って列の追加や修正を行うで紹介したmutate関数を使います。先ほどと同じでtbl_sumamry()の前に入れます。
mutate()の中はfactor関数を使います。factor(列名, labels=c(○○))に関しては【1-10】Rでよく使われる型について説明します。のfactor関数の箇所をご参照ください。

data %>% 
  select(治療,年齢,体重,性別,術側,MMT) %>% 
  mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% 
  tbl_summary(by = 治療) %>% 
  add_p() %>% 
  add_overall() %>%   
  bold_labels()
スクリーンショット 2020-09-12 17.46.55



9.集計を変更する

集計方法を指定するのはtbl_summary()です。
公式ドキュメントはこちら



既にby=type=は説明していますが、ここではlabel(一番左の変数名)、statistics(集計方法)、digits(小数点第何位まで示すか)を紹介します。

どれも○○ =変えたい変数名を選択 ~ 何に変えるかといった表記方法になります。


一番左の変数名を変更する


左の列は変数名が載っていますが、単位など付け加えたい場合もあります。
それらはlabel=""で編集します。
もし変えたい変数が2つ以上の場合はlist()を使う必要があります。
下の2つのコードはlabel=しか変わっていないので見比べてください。上のツイートも参考になります。

#変えたい列が1つだけのとき
data %>% mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% select(治療,年齢,体重,性別,術側,MMT) %>% tbl_summary(by = 治療, label = 年齢 ~ "**年齢**(歳)") %>% add_p() %>% add_overall() %>% bold_labels()

#変えたい列が2つ以上の時はlist()の()内に入れる
data %>% mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% select(治療,年齢,体重,性別,術側,MMT) %>% tbl_summary(by = 治療, label = list(年齢 ~ "年齢(歳)", 体重 ~ "体重(kg)")) %>% add_p() %>% add_overall() %>% bold_labels()
スクリーンショット 2020-09-12 18.06.04


集計方法を変える
集計方法のデフォルトが中央値(四分位範囲)となっています。
そのため平均(標準偏差)にするにはtbl_summary()内でstatistic=○○を指定します。
tbl_summary(statistic = 変えたい変数名 ~ "集計方法")という書き方をします。

data %>% 
  select(治療,年齢,体重,性別,術側,MMT) %>% 
  mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% 
  tbl_summary(by = 治療,
              statistic = c(年齢, 体重) ~ "{mean}({sd})") %>% 
  add_p() %>% 
  add_overall() %>%   
  bold_labels()
スクリーンショット 2020-09-12 18.11.46
脚注を見ると平均(標準偏差)に変わっています。


今回はc(年齢, 体重)と列名を指定しました。
もし全ての数値の列を選びたい時はall_continuous()を使うこともできます。
data %>% 
  select(治療,年齢,体重,性別,術側,MMT) %>% 
  mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% 
  tbl_summary(by = 治療,
              statistic = all_continuous() ~ "{mean}({sd})") %>% 
  add_p() %>% 
  add_overall() %>%   
  bold_labels()

もし年齢だけ指定すると、年齢は平均(標準偏差)、体重はデフォルトの中央値(四分位範囲)となります。

data %>% 
  select(治療,年齢,体重,性別,術側,MMT) %>% 
  mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% 
  tbl_summary(by = 治療,
              statistic = 年齢 ~ "{mean}({sd})") %>% 
  add_p() %>% 
  add_overall() %>%   
  bold_labels()

スクリーンショット 2020-09-12 18.19.20


もし中央値[四分位範囲]など2箇所変更するならlabel=と同様にlist()を使います。
data %>% 
  select(治療,年齢,体重,性別,術側,MMT) %>% 
  mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% 
  tbl_summary(by = 治療,
              statistic = list(年齢 ~ "{mean}({sd})",
                                 体重 ~ "{median}[{p25},{p75}]")) %>% 
  add_p() %>% 
  add_overall() %>%   
  bold_labels()
スクリーンショット 2020-09-12 18.21.16

ここで右側の説明を行います。
{集計方法}とすることで集計ができます。{}に入っていない箇所はその文字がそのまま使われます(ここでは( )や[]やカンマ。%や人など文字を入れることも可能)。
スクリーンショット 2020-09-12 18.32.59

他にも集計方法はあります。
{n}:集計した人数
{p}:集計した人数の%
{N}:母数
{p○○}:○○%時の値(0から100の数値を指定。"{p10},{p90}"など)
{var}:分散
集計方法を変えると自動的に脚注が変わるのもありがたいところです。



小数点をあわせる
デフォルトでは整数になっていますが、小数点第何位まで指定することができます。
人数は整数(0)がいいですし、小数点第何位で指定したい場合もあります。

data %>% 
  select(治療,年齢,体重,性別,術側,MMT) %>% 
  mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% 
  tbl_summary(by = 治療,
              statistic = list(年齢 ~ "{mean}({sd})",
                                 体重 ~ "{median}[{p25},{p75}]"),
              digits = list(c(年齢,体重) ~ c(1,2), 
                            c(性別,術側,MMT)  ~ c(0,1))) %>% 
  add_p() %>% 
  add_overall() %>%   
  bold_labels()
スクリーンショット 2020-09-12 18.48.13


digits = list(c(年齢,体重) ~ c(1,2), 
                  c(性別,術側,MMT)  ~ c(0,1)))
~の左側は今までと同様に列の選択を行っています。
今回~の右側は2つ数値を指定しています。
これは{平均}({標準偏差})という2つの数値を使っているからです。
年齢と体重の1つめの1は平均の小数点は第1位、2つめの2は小数点第2位という意味になります。
ここで体重の75%を確認してみてください。小数点第1位になっています。これは体重は{中央値}、{25%}、{75%}の3つの数値があるのに3つ目を指定していないためです。
そのため正しくは以下になります。


data %>% 
  select(治療,年齢,体重,性別,術側,MMT) %>% 
  mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% 
  tbl_summary(by = 治療,
              statistic = list(年齢 ~ "{mean}({sd})",
                                 体重 ~ "{median}[{p25},{p75}]"),
              digits = list(年齢 ~ c(1,2), 
                            体重 ~ c(1,2,2),
                            c(性別,術側,MMT)  ~ c(0,1))) %>% 
  add_p() %>% 
  add_overall() %>%   
  bold_labels()


10.検定方法を変えたい

集計のデフォルトは中央値(四分位範囲)でした。
統計を見るとデフォルトはWilcoxonの順位和検定(マン・ホットニーのU検定)となっています。
これをt検定で行うには修正が必要です。
p値や検定を修正するのはadd_p()の()内に記載します。

data %>% 
  select(治療,年齢,体重,性別,術側,MMT) %>% 
  mutate(治療 = factor(治療, labels = c("対照群", "治療群"))) %>% 
  tbl_summary(by = 治療,
              statistic = list(年齢 ~ "{mean}({sd})",
                                 体重 ~ "{median}[{p25},{p75}]"),
              digits = list(年齢 ~ c(1,2), 
                              体重 ~ c(1,2,2),
                              c(性別,術側,MMT)  ~ c(0,1))) %>% 
  add_p(list(年齢 ~ "t.test",
                  体重 ~ "wilcox.test")) %>% 
  add_overall() %>%   
  bold_labels()

変更したのはadd_p()だけです。
列名 ~ "検定方法"で指定します。
"t.test" for a t-test,(t検定)
"aov" for a one-way ANOVA test,(1元配置分散分析)
"wilcox.test" for a Wilcoxon rank-sum test,(マン・ホットニーのU検定)
"kruskal.test" for a Kruskal-Wallis rank-sum test,(クラスカル・ウォリス検定)
"chisq.test" for a chi-squared test of independence,(χ二乗検定)
"chisq.test.no.correct" for a chi-squared test of independence without continuity correction,
"fisher.test" for a Fisher's exact test,(フィッシャーの正確確率検定)
"lme4" for a random intercept logistic regression model to account for clustered data, lme4::glmer(by ~ variable + (1 | group), family = binomial). The by argument must be binary for this option.(階層モデルのロジスティック回帰?)

Tests default to "kruskal.test" for continuous variables, "chisq.test" for categorical variables with all expected cell counts >=5, and "fisher.test" for categorical variables with any expected cell count <5. A custom test function can be added for all or some variables. See below for an example.
公式サイトより引用





まとめ

実は続きがあるのですが基本的な箇所はかけましたので、まずは一旦投稿させていただきます。

左上の変数名や脚注、タイトルなどの修正を行っていく予定です。

ただdocxやpptxに変換すればgtsummaryでなくても修正できることも多くあります。

まずは触ってみながらどこまでをRでするか、どこからをOfficeでするかなど自分なりの方法を探してみるのもいかがでしょうか?





















(2019年11月24日修正:8の②のfactor関数を修正しています)

第4章は統計を扱います。


今回も「シロート統計学」のハルさんとコラボレーションすることとなりました。


シロート統計学はEZRを使った統計分析をわかりやすく解説されています。


 


第4章はシロート統計学で使われていたEZRをRで行うとどうなるのか?といった視点で進めていきます。


今回使うデータもハルさんのサイトと同じものを使わせでいただく事になりました。それぞれ見比べることで参考にしてみてください!


今回は繰り返しのある一元配置分散分析を紹介します



まず繰り返しのある一元配置分散分析(ANOVA)についてはハルさんのサイトをご参照ください。



また1.準備〜4.データの読み込みまでは【4-1】Rでt検定を行う方法と全く同じ流れになります。
もし1〜4まででわからない部分があれば確認してみてください。

 

1.準備

第4章は毎回ExcelデータをダウンロードしてRを使うのでプロジェクトで管理して行うことを勧めています。

 

ここではR練習というプロジェクトを作り、Excelファイルを入れるためのdataフォルダを作っています。
これを前提に次から進めていきます。
スクリーンショット 2019-10-20 7.54.14


2.スクリプトファイルの作成

次にRのコードを書くためのスクリプトファイルを作ります。

スクリーンショット 2019-11-23 22.05.34



3.データのダウンロード


【1-13】Rで読み込みやすいExcelファイルの作り方今回もハルさんのサイトのデータを使わせていただきます。
実は分散分析を行う上で覚えておくと便利なExcelデータの作り方(列の並べ方)があります。
詳細は【1-13】Rで読み込みやすいExcelファイルの作り方で紹介しています。

デモデータ(反復測定分散分析)

この章ではRを使ってダウンロードしています。


download.file(url = “ファイルのURL”,
        destfile = “保存したい場所/ファイル名”)
urlはデモデータで右クリック → リンクのアドレスをコピー
destfileは保存場所と保存のファイル名を指定します。


実際のコードは以下になります。
前回のコードのURL(" "の中)とdestfileのdata/以降を変更するだけでOKです。
#データのダウンロード
url <- "https://haru-reha.com/wp-content/uploads/2018/05/demo-repeated-measures-anova.xlsx"
destfile = "data/demo-repeated-measures-anova.xlsx"
download.file(url, destfile)
スクリーンショット 2019-11-23 22.14.17


dataフォルダにダウンロードできたことを確認します。


4.データの読み込み

データを読み込みます。
今回は【4-0】第4章を進めていく上での準備で行った方法で進めます。

View Fileでデータを確認します。

スクリーンショット 2019-11-23 22.15.57

データが入っているセルを確認します。
B2からC22までデータが入っています(B2:E32と表記)
スクリーンショット 2019-11-23 22.20.35


次にImport Datasetでデータを取り込みます。
スクリーンショット 2019-11-23 22.15.57


Import画面ではName, Sheet,Rangeを指定します。

Name:ハルさんのサイトではgripでしたがgrip_rep_anovaとします(大文字・小文字は別物とされます)
Sheet:このExcelは1つしかデータがないのでDefaultのままでOK
Range:先ほど確認したB2:E32(実は今回のように表以外に余計なものがなければ空欄でもOK)

スクリーンショット 2019-11-23 22.24.40

Importボタンを押す前に右にあるコードをコピーしスクリプトファイルに貼り付けることも忘れずに行います。
library(readxl)
grip_rep_anova <- read_excel("data/demo-repeated-measures-anova.xlsx", 
                             range = "B2:E32")
View(grip_rep_anova)

データが正しく入っていることを確認します。
スクリーンショット 2019-11-23 22.25.10


これでデータの取り込みは完成です。

5.被験者間要因と被験者内要因と分散分析のデザインについて
分散分析を行う上で大切なのが被験者間要因と被験者内要因についてです。
スクリーンショット 2019-11-24 6.33.40
被験者間要因はいわゆる対応のないデータのことで被験者全体をA法、B法の2つに割り振るといった方法です。なので同じ人がA法とB法を行うことはありません。
被験者内要因はいわゆる対応のあるデータのことで同じ人が繰り返し測定します

そして被験者間要因は列の左側に、被験者内要因は列の右側に並べると後々分析しやすくなります。
また被験者間要因は縦に、被験者内要因は横につなげるとEZRで分析を行うには都合がいいです。

仮に下のデータがあったとします。
スクリーンショット 2019-11-24 6.35.12
この並びが分散分析を行う上での基本的な形になります。
要因が3つ(sex, treatment, 繰り返し)あるのでABC
被験者間要因と被験者内要因の間にsを付ける
上記の場合はABsCデザインと言います。

今回はsexの列を使いませんので繰り返しの1要因のみで分散分析を実施します。
(sexの列を使った分析は次の記事で紹介します)

被験者間要因がありませんので、今回はsAデザインということになります。
繰り返しの群間に差があるかどうかを見たいということです。


6.正規分布かどうかを確認
分散分析を行うにはデータの分布が正規分布であることが必要です。
ハルさんのサイトに沿って正規分布の確認を行います。

正規分布の確認は【4-10】Rで分散分析(一元配置分散分析)を行う方法と基本的には同じですが、今回は繰り返しの部分がwideデータになっています。longデータであれば今までの記事で紹介した方法でまとめて出すことができますが、今回は1つずつ確認します。

今回ヒストグラムはgeom_histgram関数を使いますのでtidyverseパッケージを読み込みます。
EZRで正規性の確認をする時に併せて作成されるヒストグラムは棒が5本なのでbins = 5とすることにします。

library(tidyverse)
ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W0), bins = 5) 

ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W1), bins = 5) 

ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W2), bins = 5) 
スクリーンショット 2019-11-23 22.42.57


7.シャピロ・ウィルク検定
次にハルさんのサイトでは正規性の検定を行っています。
正規性の検討はshapriro.test関数3つのカテゴリーそれぞれに行う必要があります。
ここでもwideデータなので1つずつ行います。

shapiro.test((grip_rep_anova$W0))
shapiro.test((grip_rep_anova$W1))
shapiro.test((grip_rep_anova$W2))
スクリーンショット 2019-11-23 22.44.56


すべて正規分布であることが棄却されませんでした。


8.反復測定分散分析(repeated measures ANOVA)を行う

そして反復測定分散分析を行います。

反復測定分散分析を行うには主に2つの方法があります。

1.carパッケージのAnova関数を使う(EZRもcarパッケージを使ってる)
2.ANOVA君を使う

ANOVA君は井関龍太さんが作成した分散分析に特化したスクリプトです。
使い方に特徴がありますが使えるようになると慣れると簡単でどの方法よりも詳細に分析できます。

ここではまず1の方法を紹介します。

反復測定分散分析を行うには次の方法になります。




①carパッケージを読み込む

まずはcarパッケージを読み込みます。
carパッケージはEZRをインストールする時に一緒にインストールされています。
もしインストールしていなければ先にインストールします。

install.packages("car")

その後library関数で呼び出します。
library(car)

②被験者要因を指定するdata.frameを準備する

今回のデータではsexの列は「MとFの2つのデータがある」とパソコンは読み取れますがW0,W1,W2はwideデータとなっているため「この3列が繰り返しのデータである」ことがパソコンは読み取れません。それがわかるためのものを2つ作ります。

まず繰り返しの順番がわかるtimeというベクトルを作ります。
このデータはfactor型である必要があるためfactor関数を使います。
そしてtimeのデータをdata.frame型に変更したidataを作ります。

 スクリーンショット 2019-11-24 10.11.33
そして大事なのがlevels = です。levels = を指定しないとfacorは五十音順になります。
今回は問題ないのですがもしpre,mid,postのように列名を付けるとlevels = を使わないとmid→post→preの順番になってしまいます。
factor関数に関しては【1-10】Rでよく使われる型について説明します。
 

③lm関数でモデルを作る

次に分析するためのモデルを作ります。
モデルはlm関数を使います。model(名前は何でもいい)という変数名に結果を入れます。
被験者内要因は3列になっているのでcbind関数でつなげます。
被験者間要因は今回無いので1とします。もしあると別の設定も必要ですが次の記事で紹介します。

スクリーンショット 2019-11-24 11.55.22
④Anova関数で分散分析を実行する



反復測定分散分析を行う時はcarパッケージのAnova関数を使います。Aは必ず大文字です。
res(resultの略、何でも良い)という変数名に結果を入れます。

Anova(lm関数で作ったモデル, idata = ◯◯, idesign = ~ ◯◯, type = "Ⅲ")

lm関数で作ったモデル:先程作ったmodel
idata:先程つくったidata
idesign:先程作ったtime(timeの前に を付けます)
type:"Ⅲ"または3とする(反復測定分散分析の場合は必ずⅢ)
スクリーンショット 2019-11-24 12.08.02

⑤summary関数で結果を表示する

summary(Anova関数の結果, multivariate = FALSE)

multivariate = FALSEと入れるとEZRと同じ結果が表示されます。

①〜⑤をまとめると以下になります
library(car)
time<- factor(c("W0", "W1", "W2"), levels = c("W0","W1", "W2")) idata <- as.data.frame(time) model <- lm(cbind(W0,W1,W2) ~ 1, data = grip_rep_anova) res <- Anova(model, idata = idata, idesign = ~time, type = 3 ) summary(res, multivariate = FALSE)
スクリーンショット 2019-11-24 21.02.57
行が長くて大変ですが実は色の部分以外はコピペ可能です。
(被験者間要因があればまた変わります。次回記事で紹介します)

スクリーンショット 2019-11-24 12.51.33
このあたりはハルさんのサイトと同じです。
EZRと同じ結果になります。

9.多重比較を行う

EZRの多重比較はEZR独自の関数を使っています。
そのため今回はpairwise.t.test関数を使います。
(被験者間要因があると使えないので注意!)
ただpairwise.t.test関数はlongデータで行う必要があります。

wideデータをlongデータに変えるにはgather関数、またはpivot_longer関数を使います。
wideデータとlongデータの切り替えは【2-5】Rでデータを集計するのに便利なlongデータとgather関数で紹介しています。

pairwise.t.test(数値, グループ, p.adjust.method = "◯◯")
〇〇はここでは3つの方法を紹介します。

bonferroni
holm
hochberg


grip_rep_anova_long <- 
  grip_rep_anova %>% 
  gather(key = "key", value = "value", W0:W2)

pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "bonferroni")
pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "holm")
pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "hochberg")

スクリーンショット 2019-11-24 13.17.18


10.まとめ

今回は反復測定分散分析を紹介しました。
今までの手法に比べると手続きが必要ですが、慣れるとコピペでもできるようになります。
次回は被験者間要因も含めた混合計画反復測定分散分析を紹介します。


11.今回使ったコード

今回使ったコードは以下になります。
#データのダウンロード
url <- "https://haru-reha.com/wp-content/uploads/2018/05/demo-repeated-measures-anova.xlsx"
destfile <- "data/demo-repeated-measures-anova.xlsx"

download.file(url, destfile)

#データの読み込み
library(readxl)
grip_rep_anova <- read_excel("data/demo-repeated-measures-anova.xlsx", 
                             range = "B2:E32")
View(grip_rep_anova)

#正規分布の確認
library(tidyverse)
ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W0), bins = 5) 

ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W1), bins = 5) 

ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W2), bins = 5) 

shapiro.test((grip_rep_anova$W0))
shapiro.test((grip_rep_anova$W1))
shapiro.test((grip_rep_anova$W2))


#carパッケージのインストールしたことなければインストール
install.packages("car")

#反復測定分散分析を行う
library(car)
time<- factor(c("W0", "W1", "W2"), levels = c("W0","W1", "W2"))
idata <- as.data.frame(time)
model <- lm(cbind(W0,W1,W2) ~ 1, data = grip_rep_anova)
res <- Anova(model, idata = idata, idesign = ~time, type = 3)
summary(res, multivariate = FALSE)

#多重比較
grip_rep_anova_long <- 
  grip_rep_anova %>% 
  gather(key = "key", value = "value", W0:W2)

pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "bonferroni")
pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "holm")
pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "hochberg")



今までRでデータの変数名を変更したり条件でグループ化したりしました。







そして前回の記事では集計して平均や標準偏差などの要約を出したり、グラフを作るためにgather関数を使ってlongデータを作りました。

【2-5】Rでデータを集計するのに便利なtidyデータとgather関数



今回は棒グラフや折れ線グラフ作成に必要な平均や標準偏差などの統計量を求めます。



データは前回と同じデータを使います。

FIM.xlsx

スクリーンショット 2019-02-19 22.25.41


ダウンロードした後、プロジェクトの指定フォルダにファイルを移動させておけば、以下のコマンドで前回最後の場面まで進みます。

library(tidyverse)
library(readxl)
fim <- read_excel("FIM.xlsx", sheet = "入院時")
fim_long <- fim %>% 
  gather(食事:FIM合計, key = 項目, value = 点数, factor_key = TRUE) 
head(fim_long)


1,groop_by関数でグループ化したい項目を指定する

ますグループ化するためにはgroop_by関数を使います。

group_by(データ,列名)

%>%を使うとデータの部分は省略できます。

fim_long %>% 
  group_by(項目) 

スクリーンショット 2019-02-21 21.42.39



何も変わってないように見えますが、薄い文字のところに# Groups:項目 [21]とあります。


ちなみにグループの種類が複数でも可能です。

fim_long %>% 
  group_by(項目,性別) 

スクリーンショット 2019-02-21 21.45.43



2.列名の順番について

下の2つのコードはどういった違いがあるのでしょうか?

スクリーンショット 2019-02-22 0.15.27

表の並び順が違うだけでその後グラフを作るときには影響はないのですがイメージとしては上記のようになります。





3.統計量を出すsummarize関数


平均などの統計量などを出すにはsummarize関数を使います。

summarize(名前1 = 関数1, 名前2 = 関数2)

summarize関数の前にgroup_by関数を使っていると、グループごとの集計が出てきます。

fim_summarize <-  fim_long %>% 
  group_by(項目,性別) %>% 
  summarize(平均 = mean(点数), 
            標準偏差 = sd(点数), 
            最小値 = min(点数), 
            最大値 = max(点数))
fim_summarize

スクリーンショット 2019-02-22 0.49.09




もし保存したい場合はwrite.csv関数を使います。

wite.csv(保存する変数名, "ファイル名.csv")
ファイル名には" "と.csvを入れます

write.csv(fim_summarize,"FIM集計")
スクリーンショット 2019-02-22 0.57.54
右のfilesビューにFIM集計.csvができました。

csvファイルをExcelで読み込む時は【1-11】Rで医療統計で必要なtable1を作るtableoneパッケージについて紹介しますをご参照ください。

ポイントとしてはファイルの出力先を$A$1ではなく$B$1にしてください。
$A$1だとなぜかエラーが出ます。
スクリーンショット 2019-02-22 1.04.57

スクリーンショット 2019-02-22 1.07.22

Excelにするとわかるのですが、小数点10桁まで表示されます。
もし小数点第一位までの表示にしたい時はround関数を使います。

round(数値, x)
たとえばxが1だと小数点第二位を四捨五入して小数点第一位まで表示します。

fim_summarize <- fim_long %>%
group_by(項目,性別) %>%
summarize(平均 = round(mean(点数), 1),
   標準偏差 = round(sd(点数), 1),
   最小値 = min(点数),
   最大値 = max(点数))
fim_summarize
スクリーンショット 2019-02-22 1.18.28



4.summarize関数を使うときの注意点。

group_by関数の順番に影響する

2でも紹介しましたが、groop_by関数で指定したグループが複数の場合、summarize関数で表示される順番はgroop_by関数の影響を受けます。

スクリーンショット 2019-02-22 0.15.27

あとでExcelで並べ替えるのはただ面倒です。もしcsvで保存をする時は何を示したいかをあらかじめイメージしておくことが重要になります。



2.欠損地があるとNAとなる

平均を求めるmean関数などはどこか1つでも欠損値(空欄)があると結果はNAとなります。

氏名 <- c("A", "B", "C", "D")
年齢 <- c(55, 63, 67, 71)
test_1回目 <- c(1,2,3,NA)
test_2回目 <- c(5:8) test_3回目 <- c(9:12)
data <- data_frame(氏名, 年齢, test_1回目, test_2回目, test_3回目)
data data %>%
gather(3:5, key = 回数, value = 点数) %>%
group_by(回数) %>%
summarize(平均 = mean(点数))
スクリーンショット 2019-02-22 1.53.38


もし結果にNAが出た時はまずはそもそものデータの入れ損ねがないか確認をし対応します。

それでも欠損値がある時はNAを省いて計算する欠損値を統計の技術を使って代入するといった方法があります。

もし欠損値を省いて平均を出す場合はna.rm = TRUEを付け加えます。

data %>%
gather(3:5, key = 回数, value = 点数) %>%
group_by(回数) %>%
summarize(平均 = mean(点数, na.rm = TRUE))
スクリーンショット 2019-02-22 2.06.51


ただ実は欠損値を省いた方がいいのかどうかという問題があります。ただ業務で傾向を確認したいなどであれば欠損値を省いてもいいと思いますが、きちんと出さないと行けない場面ではこれはこれできちんと勉強する必要があります。欠測データに関しては医療統計の本では紹介されていない事が多く専門書が必要かもしれません。


欠測データ処理: Rによる単一代入法と多重代入法 (統計学One Point)



summarize関数に入れられる関数は単一の値が出るものに限る。

summarize関数で使える統計量はmean関数,sd関数,median関数など単一の値になります。

ただ、関数の中には最小値と最大値を一度に出してくれるrange関数など複数の値を出すものがあります。

test_2回目 <- c(5:8)
range(test_2回目)
スクリーンショット 2019-02-22 2.27.00


range関数をsummarize関数に入れようとするとエラーが出ます。

data %>% gather(3:5, key = 回数, value = 点数) %>% group_by(回数) %>% summarize(平均 = mean(点数, na.rm = TRUE), 範囲 = range(点数))

スクリーンショット 2019-02-22 2.36.38

「1つの値しか入れられないのに2つ入ってるよ!」と怒られています。

スクリーンショット 2019-02-22 2.41.49

特にあるのが四分位範囲です。
四分位範囲はquantile関数を使って以下のように一度に値を出すことができます。
quantile(fim$年齢, c(0.1, 0.25, 0.5, 0.75, 0.9))
スクリーンショット 2019-02-22 2.45.59


しかしsummarize関数ではまとめて入れられないので1つずつ入れる必要があります。
fim_summarize <- fim_long %>% group_by(項目,性別) %>% summarize(平均 = mean(点数), 標準偏差 = sd(点数), 最小値 = min(点数), percent_25 = quantile(点数, 0.25), 中央値 = median(点数), percent_75 = quantile(点数, 0.75), 最大値 = max(点数)) fim_summarize
スクリーンショット 2019-02-22 3.01.32



そもそもの列のfactorの順番があってるのか?

gather関数のkey列に関してはfactor_key=TRUEで五十音順ではなく、元の順番に戻すことができます。

しかし他の列でfactorの順番が合っていない可能性もあります。

もしほかの列でfactorの順番を合わせるにはmutate関数とfactor関数を組み合わせて使うことができます。

今回は女性と男性を入れ替えてみます。
fim_summarize <- fim_long %>%
mutate(性別 = factor(性別, levels = c("男性","女性"))) %>%
group_by(項目,性別) %>%
summarize(平均 = mean(点数),
     標準偏差 = sd(点数),
      最小値 = min(点数),
   percent_25 = quantile(点数, 0.25),
   中央値 = median(点数),
   percent_75 = quantile(点数, 0.75),
      最大値 = max(点数))
fim_summarize
スクリーンショット 2019-02-22 3.01.32


factor関数の使い方は【1-10】Rでよく使われる型について説明しますをご参照ください


まとめ

今回はgroup_by関数とsummarize関数と、実際に集計を出し保存するところまで紹介しました。

これでひとまず第2章で行う予定だった「データを集計しやすいように形を整え集計する」が終わりです。

スクリーンショット 2019-02-08 10.33.40


ただ今回は「できるだけExcelの時点でデータは編集しやすい形式で保存している」ことを前提に話を進めています。

もっと形が整っていないデータの扱いやここでは説明できなかった項目も多くあります。

もし「もっと知りたい」「ここの情報では足りない!」ということであれば下記のサイトなどもご参照ください。


データハンドリング入門
https://kazutan.github.io/kazutanR/hands_on_170730/index.html




↑このページのトップヘ