RCT
BABA, Yoshihiko
2021/8/16
Holthoff VA, Marschner K, Scharf M, Steding J, Meyer S, Koch R, & Donix M (2015) Effects of physical activity training in patients with Alzheimer’s dementia: Reslts of a pilot RCT study. PloS one, 10(4), e0121478.
library(haven)
strUrl <- "https://doi.org/10.1371/journal.pone.0121478.s003"
strDestfile <- "pone.0121478.s003.sav"
curl::curl_download(strUrl, strDestfile)
df3 <- data.frame(read_sav(strDestfile))
strUrl <- "https://doi.org/10.1371/journal.pone.0121478.s004"
strDestfile <- "pone.0121478.s004.sav"
curl::curl_download(strUrl, strDestfile)
df4 <- read_sav(strDestfile)
では、pone.0121478.s004.sav から Table 1 を再現してみましょう。
library(tableone)
df4$BMI <- df4$Gewicht_kg / ( df4$Größe_cm/100 ) ^2
CreateTableOne(data = df4,
strata="group",
vars=c("Alter_in_Jahren_Studienbeginn","Geschlecht", "Ausbildungsjahre", "BMI"),
factorVars=c("Geschlecht"))
## Stratified by group
## 1 2 p
## n 15 15
## Alter_in_Jahren_Studienbeginn (mean (SD)) 72.40 (4.34) 70.67 (5.41) 0.341
## Geschlecht = 1 (%) 8 (53.3) 7 (46.7) 1.000
## Ausbildungsjahre (mean (SD)) 12.33 (2.13) 14.13 (2.70) 0.052
## BMI (mean (SD)) 23.43 (2.75) 24.12 (4.06) 0.589
## Stratified by group
## test
## n
## Alter_in_Jahren_Studienbeginn (mean (SD))
## Geschlecht = 1 (%)
## Ausbildungsjahre (mean (SD))
## BMI (mean (SD))
Number of steps のデータは見つかりませんでした。その他の値について、平均値と標準偏差は一致しました。 ただし、p値については多少異なっています。
df3 は、基本的には Long 形式ですが、横にも長いので、関心のある列のみ表示します。
datatable(df3[c("Patientennummer", "Gruppe", "Messzeitpunkt_Nummer", "ADCS_ges", "NPI_ges")])
ADCS
まず、df3 が巨大なデータフレームなので、ADCSとその他必要なデータだけの小さなデータフレームを作成します。
最初に、行数をそろえるために、インデックス列をコピーします。最初に使う列をすべて指定してもよいのですが、ここではインデックス列のみとしました。なお、最初にすべてコピーする場合は、
df3ADCS <- df3[c("Patientennummer", "Gruppe", "Messzeitpunkt_Nummer", "ADCS_ges")]
とします。列数が一つの時は文字列“A”ですが、複数の場合は文字列リストc(“A”, “B”, “C”) になります。
Time (Messzeitpunkt_Nummer) は、因子型にもとれますが、geom_smooth() を使うためには x軸も数値型である必要があるので、数値型とします。
library(ggplot2)
df3ADCS <- df3["Patientennummer"]
df3ADCS$Group <- factor(df3$Gruppe, level=c(1,2))
df3ADCS$Time <- as.numeric(df3$Messzeitpunkt_Nummer)
df3ADCS$ADCS <- as.numeric(df3$ADCS_ges)
平均値と標準誤差を手動で計算する方法です。
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
df3Plot <- df3ADCS %>%
group_by(Group, Time) %>%
summarise(ADCS_means = mean(ADCS, na.rm=T),
ADCS_SEs = sd(ADCS, na.rm=T)/sqrt(length(ADCS)))
## `summarise()` has grouped output by 'Group'. You can override using the `.groups` argument.
ggplot(data = df3Plot, aes(x = Time, y = ADCS_means, group = Group, colour = Group)) +
geom_point(position = position_dodge(width=0.2)) +
geom_line(position = position_dodge(width=0.2)) +
geom_errorbar(aes(ymin=ADCS_means-ADCS_SEs, ymax=ADCS_means+ADCS_SEs), width=.1, position = position_dodge(width=0.2))+
theme_bw()
平均値と標準誤差を自動的にプロットする方法です。
library(ggpubr)
ggline(df3ADCS, x = "Time", y = "ADCS", add = "mean_se",
color = "Group")+
stat_compare_means(aes(group = Group), label = "p.signif")
## Warning: Removed 4 rows containing non-finite values (stat_summary).
## Warning: Removed 4 rows containing non-finite values (stat_compare_means).
ggplot(data = df3ADCS, aes(x = Time, y = ADCS, colour = Group)) +
geom_smooth(method="lm")
## `geom_smooth()` using formula 'y ~ x'
## Warning: Removed 4 rows containing non-finite values (stat_smooth).
two way repeated measures ANOVA
データのない行を削除し、 外れ値を確認します。
library(rstatix)
##
## Attaching package: 'rstatix'
## The following object is masked from 'package:stats':
##
## filter
df3ADCSnoNA <- na.omit(df3ADCS)
identify_outliers(group_by(df3ADCSnoNA, "Group", "Time"), "ADCS")
df3ADCSnoNA <- na.omit(df3ADCS)
shapiro_test(group_by(df3ADCSnoNA, "Group", "Time"), "ADCS")
残念ながら、これは以下のエラーが出ます。
Error: Problem with mutate()
column data
. i data = map(.data$data, .f, ...)
. x Can’t subset columns that don’t exist. x Column "ADCS"
doesn’t exist. Run rlang::last_error()
to see where the error occurred.
library(rstatix)
aovDf3ADCS <- anova_test(
data = df3ADCSnoNA,
dv = "ADCS",
wid = "Patientennummer",
within = c("Group","Time"))
get_anova_table(aovDf3ADCS)
残念ながら、これは以下のエラーが出ます。
Error in lm.fit(x, y, offset = offset, singular.ok = singular.ok, …) : 0 (non-NA) cases
repeated measures ANOVA は、計測されていないデータがあると実行することができません。 例えば、Patientennummber = 11 の T3 におけるデータがありません(他にも何か所か欠測があります)。 このため、Patientennumber = 11 全体を削除するか、代入 (imputation) を必要があります。
介入後のフォローアップを伴う解析を予定している場合は、特に欠測が発生しやすいので注意が必要です。
削除するか、代入するかは、研究計画段階で決める必要があります。
Mixed model
一方、欠測値があっても実行できるのが Mixed Model の強みです。
library(lme4)
library(sjPlot)
lmeModeldf3ADCS = lmer(ADCS ~ Group*Time + (1|Patientennummer), data=df3ADCS)
anova(lmeModeldf3ADCS)
tab_model(lmeModeldf3ADCS)
ADCS | |||
---|---|---|---|
Predictors | Estimates | CI | p |
(Intercept) | 61.11 | 55.35 – 66.88 | <0.001 |
Group: Group 2 | 2.08 | -6.06 – 10.22 | 0.617 |
Time | 0.46 | -0.65 – 1.58 | 0.413 |
Group2:Time | -3.98 | -5.51 – -2.44 | <0.001 |
Random Effects | |||
σ2 | 8.23 | ||
τ00 Patientennummer | 109.44 | ||
ICC | 0.93 | ||
N Patientennummer | 30 | ||
Observations | 86 | ||
Marginal R2 / Conditional R2 | 0.097 / 0.937 |
library(emmeans)
emmeans(lmeModeldf3ADCS, list(pairwise ~ Group), adjust = "tukey")
## $`emmeans of Group`
## Group emmean SE df lower.CL upper.CL
## 1 62.0 2.74 28.1 56.4 67.6
## 2 56.3 2.74 27.9 50.7 61.9
##
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
##
## $`pairwise differences of Group`
## 1 estimate SE df t.ratio p.value
## 1 - 2 5.69 3.87 28 1.469 0.1529
##
## Degrees-of-freedom method: kenward-roger
ここでは、 p = 0.1529 より、交互作用があったとは言えないと解釈します。
NPI
library(ggplot2)
df3NPI <- df3["Patientennummer"]
df3NPI$Group <- factor(df3$Gruppe, level=c(1,2))
df3NPI$Time <- as.numeric(df3$Messzeitpunkt_Nummer)
df3NPI$NPI <- as.numeric(df3$NPI_ges)
#df3NPI <- subset(df3, !is.na(df3$NPI))
ggplot(data = df3NPI, aes(x = Time, y = NPI, colour = Group)) +
geom_point() +
geom_smooth(method = "lm")
library(lme4)
library(sjPlot)
lmeModeldf3NPI = lmer(NPI ~ Group*Time + (1|Patientennummer), data=df3NPI)
anova(lmeModeldf3NPI)
tab_model(lmeModeldf3NPI)
NPI | |||
---|---|---|---|
Predictors | Estimates | CI | p |
(Intercept) | 9.32 | 4.60 – 14.04 | <0.001 |
Group: Group 2 | 2.99 | -3.65 – 9.64 | 0.377 |
Time | -0.49 | -1.99 – 1.01 | 0.521 |
Group2:Time | 2.69 | 0.62 – 4.76 | 0.011 |
Random Effects | |||
σ2 | 15.05 | ||
τ00 Patientennummer | 49.65 | ||
ICC | 0.77 | ||
N Patientennummer | 30 | ||
Observations | 86 | ||
Marginal R2 / Conditional R2 | 0.228 / 0.820 |
library(emmeans)
emmeans(lmeModeldf3NPI, list(pairwise ~ Group), adjust = "tukey")
## $`emmeans of Group`
## Group emmean SE df lower.CL upper.CL
## 1 8.36 1.92 28.2 4.43 12.3
## 2 16.61 1.91 27.8 12.69 20.5
##
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
##
## $`pairwise differences of Group`
## 1 estimate SE df t.ratio p.value
## 1 - 2 -8.24 2.71 28 -3.044 0.0050
##
## Degrees-of-freedom method: kenward-roger
p = 0.0050 なので、交互作用があったと解釈します。
サンプルサイズ
library(WebPower)
## Loading required package: MASS
##
## Attaching package: 'MASS'
## The following object is masked from 'package:rstatix':
##
## select
## The following object is masked from 'package:dplyr':
##
## select
## Loading required package: lavaan
## This is lavaan 0.6-9
## lavaan is FREE software! Please report any bugs.
## Loading required package: parallel
## Loading required package: PearsonDS
wp.rmanova(ng = 2,
nm = 3,
power = 0.80,
alpha = 0.05,
f = 0.32,
type = "2")
## Repeated-measures ANOVA analysis
##
## n f ng nm nscor alpha power
## 95.61069 0.32 2 3 1 0.05 0.8
##
## NOTE: Power analysis for interaction-effect test
## URL: http://psychstat.org/rmanova