データ

ここでは、データを作成します。

censor = 1 とは、アウトカムのイベント発生を意味します。

dfSurvival <- data.frame(
  patientid = c(1,2,3,4,5,6,7,8,9,10,11,12,13),
  year = c(10,9,9,8,7,6,5,4,4,4,3,2,1),
  censor = c(1,1,1,1,0,1,0,1,1,0,1,0,1),
  group = c("exposure","control","exposure","control","exposure","control","exposure","control","exposure","control","exposure","control","exposure")
  )
dfSurvival
##    patientid year censor    group
## 1          1   10      1 exposure
## 2          2    9      1  control
## 3          3    9      1 exposure
## 4          4    8      1  control
## 5          5    7      0 exposure
## 6          6    6      1  control
## 7          7    5      0 exposure
## 8          8    4      1  control
## 9          9    4      1 exposure
## 10        10    4      0  control
## 11        11    3      1 exposure
## 12        12    2      0  control
## 13        13    1      1 exposure

変数

  • dfSurvival: データフレームであることを明示するために、dfを先頭につけた変数名としています。

関数

  • data.frame: base 関数。データフレームを作成する。他のプログラミング言語だと . は意味を持つことが多いが、R ではあまり意味はない。

実際には、File > Import Dataset などを使って、エクセルファイルまたはCSVファイルから読み込みます。 この時に、変数名を指定します。 変数名は、dataset や Dataset がデフォルトになっていることが多いようです。

生データからピボット(標準)

研究の生データは、通常は上の表のようなデータではありません。

実際には、毎年生存の確認をする場合、以下のような表を作成するでしょう。

## Warning in get_current_theme(): This functionality requires shiny v1.6 or higher

このようなデータ形式を、 long フォーマットといいます。 このデータを、表1のようなフォーマット(wide フォーマット)に成型します。

reshape2 を用いる場合

tidyr を用いる場合

library(tidyr)
dfTemp <- tidyr::pivot_wider(data = dfSurvivalEntry, names_from = "year", values_from = "censor")
#datatable(dfTemp)
dfTemp
## # A tibble: 13 x 12
##    patientid `2000` `2001` `2002` `2003` `2004` `2005` `2006` `2007` `2008`
##        <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>
##  1         1      0      0      0      0      0      0      0      0      0
##  2         2      0      0      0      0      0      0      0      0      0
##  3         3      0      0      0      0      0      0      0      0      0
##  4         4     NA     NA      0      0      0      0      0      0      0
##  5         5      0      0      0      0      0      0      0      0     NA
##  6         6     NA      0      0      0      0      0      0      1     NA
##  7         7     NA      0      0      0      0      0      0     NA     NA
##  8         8     NA      0      0      0      0      1     NA     NA     NA
##  9         9     NA      0      0      0      0      1     NA     NA     NA
## 10        10     NA      0      0      0      0      1     NA     NA     NA
## 11        11      0      0      0      1     NA     NA     NA     NA     NA
## 12        12     NA      0      0      0     NA     NA     NA     NA     NA
## 13        13     NA     NA      0      1     NA     NA     NA     NA     NA
## # … with 2 more variables: 2009 <int>, 2010 <int>

変数

  • dfSurvivalWider: データフレーム(tibble)形式

関数

  • tidyr::pivot_wider: ライブラリ tidyr が提供する関数

これは、確かに見やすいですが、表1の形式とは異なります。

そこで、

dfSurvivalWider <- tidyr::pivot_wider(data = dfSurvivalEntry, id_cols = "patientid", names_from = "censor", values_from = "year", values_fn = min)

names(dfSurvivalWider)[c(2,3)] <- c("alive","dead") # 列名を変えます。

dfSurvivalWider
## # A tibble: 13 x 3
##    patientid alive  dead
##        <int> <int> <int>
##  1         1  2000  2010
##  2         2  2000  2009
##  3         3  2000  2009
##  4         4  2002  2010
##  5         5  2000    NA
##  6         6  2001  2007
##  7         7  2001    NA
##  8         8  2001  2005
##  9         9  2001  2005
## 10        10  2001  2005
## 11        11  2000  2003
## 12        12  2001    NA
## 13        13  2002  2003

関数

  • c: base 関数。ベクトルを返す。combination の c。

  • names: base 関数。列名を表示するのが主な機能。ここでは列名変換に使用した。

このままですと、イベント発生しなかった人が NA のままになってしまいます。

dfSurvivalWider2 <- tidyr::pivot_wider(data = dfSurvivalEntry, id_cols = "patientid", names_from = "censor", values_from = "year", values_fn = max)

names(dfSurvivalWider2)[2] <- "alivelast" # 列名を変えます。

dfSurvivalWider2
## # A tibble: 13 x 3
##    patientid alivelast   `1`
##        <int>     <int> <int>
##  1         1      2009  2010
##  2         2      2008  2009
##  3         3      2008  2009
##  4         4      2009  2010
##  5         5      2007    NA
##  6         6      2006  2007
##  7         7      2006    NA
##  8         8      2004  2005
##  9         9      2004  2005
## 10        10      2004  2005
## 11        11      2002  2003
## 12        12      2003    NA
## 13        13      2002  2003
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
dfSurvivalWider <- inner_join(dfSurvivalWider, dfSurvivalWider2, by = "patientid")

dfSurvivalWider
## # A tibble: 13 x 5
##    patientid alive  dead alivelast   `1`
##        <int> <int> <int>     <int> <int>
##  1         1  2000  2010      2009  2010
##  2         2  2000  2009      2008  2009
##  3         3  2000  2009      2008  2009
##  4         4  2002  2010      2009  2010
##  5         5  2000    NA      2007    NA
##  6         6  2001  2007      2006  2007
##  7         7  2001    NA      2006    NA
##  8         8  2001  2005      2004  2005
##  9         9  2001  2005      2004  2005
## 10        10  2001  2005      2004  2005
## 11        11  2000  2003      2002  2003
## 12        12  2001    NA      2003    NA
## 13        13  2002  2003      2002  2003

次に、alive 列dead 列 から、duration 列 を計算します。

dfSurvivalWider$Duration <- dfSurvivalWider$alivelast - dfSurvivalWider$alive 

dfSurvivalWider$Duration <- dfSurvivalWider$dead - dfSurvivalWider$alive 

dfSurvivalWider[dfSurvivalWider$patientid == 1, "Group"] <- "exposure"
dfSurvivalWider[dfSurvivalWider$patientid == 2, "Group"] <- "control"
dfSurvivalWider$Group <- as.factor(dfSurvivalWider$Group)

dfSurvivalWider
## # A tibble: 13 x 7
##    patientid alive  dead alivelast   `1` Duration Group   
##        <int> <int> <int>     <int> <int>    <int> <fct>   
##  1         1  2000  2010      2009  2010       10 exposure
##  2         2  2000  2009      2008  2009        9 control 
##  3         3  2000  2009      2008  2009        9 <NA>    
##  4         4  2002  2010      2009  2010        8 <NA>    
##  5         5  2000    NA      2007    NA       NA <NA>    
##  6         6  2001  2007      2006  2007        6 <NA>    
##  7         7  2001    NA      2006    NA       NA <NA>    
##  8         8  2001  2005      2004  2005        4 <NA>    
##  9         9  2001  2005      2004  2005        4 <NA>    
## 10        10  2001  2005      2004  2005        4 <NA>    
## 11        11  2000  2003      2002  2003        3 <NA>    
## 12        12  2001    NA      2003    NA       NA <NA>    
## 13        13  2002  2003      2002  2003        1 <NA>

dplyr を駆使する方法もありますが、これより簡単には思えません。

最後の Group 列に exposure または control を入力する方法は、美しい方法ではありません。 しかし、エクセルなどの票に格納して inner_join などをするよりは、わかりやすく、また情報漏洩やミスのリスクも減るような気がします。

検定

library(survival)
objSurv <- survival::survfit( survival::Surv(year,censor) ~ group, data = dfSurvival)
summary(objSurv)
## Call: survfit(formula = survival::Surv(year, censor) ~ group, data = dfSurvival)
## 
##                 group=control 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     4      5       1    0.800   0.179       0.5161            1
##     6      3       1    0.533   0.248       0.2142            1
##     8      2       1    0.267   0.226       0.0507            1
##     9      1       1    0.000     NaN           NA           NA
## 
##                 group=exposure 
##  time n.risk n.event survival std.err lower 95% CI upper 95% CI
##     1      7       1    0.857   0.132        0.633            1
##     3      6       1    0.714   0.171        0.447            1
##     4      5       1    0.571   0.187        0.301            1
##     9      2       1    0.286   0.223        0.062            1
##    10      1       1    0.000     NaN           NA           NA

変数

  • objSurv: survival パッケージのオブジェクト。

  • dfSurvival: 上で作ったデータフレーム。

関数

  • survfit: survival パッケージの関数。生存時間データのカプランマイヤー推定で用いる関数

  • Surv: survival パッケージの関数。生存時間データオブジェクトを作成する。

  • summary: base 関数。

2群の比較 log-rank 検定

ログ・ランク (log-rank)検定は、群ごとのイベントありとなしに集計したクロス表のカイ2乗検定。R の survival パッケージが自動的に計算する。

survdiff(Surv(year,censor)~group, data = dfSurvival) 
## Call:
## survdiff(formula = Surv(year, censor) ~ group, data = dfSurvival)
## 
##                N Observed Expected (O-E)^2/E (O-E)^2/V
## group=control  6        4     3.58    0.0486     0.105
## group=exposure 7        5     5.42    0.0321     0.105
## 
##  Chisq= 0.1  on 1 degrees of freedom, p= 0.7

プロット

下準備

plot

plot(objSurv)

いろいろなオプションを試してみましょう。

plot(objSurv, conf.int = T, col = c("red","blue"), xlab= "year", ylab = "event")

ggplot2

survminer

library(survminer, warn.conflicts=FALSE, quietly=TRUE)

ggsurvplot(objSurv, data = dfSurvival, risk.table = TRUE, pval = TRUE, conf.int = TRUE, risk.table.y.text.col = TRUE)

ggfortify

library(ggplot2)
library(ggfortify)

autoplot(objSurv, data = dfSurvival )

参考

  1. 東北大学 医学統計勉強会 : 東北大学病院 - 循環器内科 第7回 「生存時間解析 生存曲線 Cox比例ハザードモデル」 https://www.cardio.med.tohoku.ac.jp/2005/newmember/medical_statistics.html