library(survival)
rm(list = ls())
dim(lung)
## [1] 228 10
str(lung)
## 'data.frame': 228 obs. of 10 variables:
## $ inst : num 3 3 3 5 1 12 7 11 1 7 ...
## $ time : num 306 455 1010 210 883 ...
## $ status : num 2 2 1 2 2 1 2 2 2 2 ...
## $ age : num 74 68 56 57 60 74 68 71 53 61 ...
## $ sex : num 1 1 1 1 1 1 2 2 1 1 ...
## $ ph.ecog : num 1 0 0 1 0 1 2 2 1 2 ...
## $ ph.karno : num 90 90 90 90 100 50 70 60 70 70 ...
## $ pat.karno: num 100 90 90 60 90 80 60 80 80 70 ...
## $ meal.cal : num 1175 1225 NA 1150 NA ...
## $ wt.loss : num NA 15 15 11 0 0 10 1 16 34 ...
31 Cox回归校准曲线绘制
前面我们已经讲过逻辑回归模型的校准曲线的画法,这次我们学习cox回归的校准曲线画法。
31.1 准备数据
使用自带数据lung
数据集进行演示。
这个是关于肺癌的生存数据,一共有228行,10列,其中time
是生存时间,单位是天,status
是生存状态,1是删失,2是死亡。其余变量是自变量,意义如下:
inst
:机构代码,对于我们这次建模没啥用age
:年龄sex
:1是男性,2是女性ph.ecog
:ECOG评分。0=无症状,1=有症状但完全可以走动,2=每天<50%的时间在床上,3=在床上>50%的时间但没有卧床,4=卧床不起ph.karno
:医生评的KPS评分,范围是0-100,得分越高,健康状况越好,越能忍受治疗给身体带来的副作用。pat.karno
:患者自己评的KPS评分meal.cal
:用餐时消耗的卡路里wt.loss
:过去6个月的体重减少量,单位是磅
大多数情况下都是使用1代表死亡,0代表删失,这个数据集用2代表死亡,但有的R包会报错,需要注意!
我们这里给它改过来:
library(dplyr)
library(tidyr)
<- lung %>%
lung mutate(status=ifelse(status == 2,1,0))
str(lung)
## 'data.frame': 228 obs. of 10 variables:
## $ inst : num 3 3 3 5 1 12 7 11 1 7 ...
## $ time : num 306 455 1010 210 883 ...
## $ status : num 1 1 0 1 1 0 1 1 1 1 ...
## $ age : num 74 68 56 57 60 74 68 71 53 61 ...
## $ sex : num 1 1 1 1 1 1 2 2 1 1 ...
## $ ph.ecog : num 1 0 0 1 0 1 2 2 1 2 ...
## $ ph.karno : num 90 90 90 90 100 50 70 60 70 70 ...
## $ pat.karno: num 100 90 90 60 90 80 60 80 80 70 ...
## $ meal.cal : num 1175 1225 NA 1150 NA ...
## $ wt.loss : num NA 15 15 11 0 0 10 1 16 34 ...
然后把数据划分为训练集、测试集,下面这个划分方法是错的哈,这个示例数据样本量太少了,我想让训练集和测试集样本量都尽量多一点,所以用了一个错误的方法进行演示:
set.seed(123)
<- sample(1:nrow(lung),nrow(lung)*0.7)
ind1 <- lung[ind1,]
train_df
set.seed(563435)
<- sample(1:nrow(lung),nrow(lung)*0.7)
ind2 <- lung[ind2, ]
test_df
dim(train_df)
## [1] 159 10
dim(test_df)
## [1] 159 10
31.2 方法1:rms
library(rms)
# 必须先打包数据
<- datadist(train_df)
dd options(datadist = "dd")
units(train_df$time) <- "day" # 单位设置为:天
构建cox比例风险模型。rms
可以使用内部重抽样的方法绘制校准曲线,可以选择bootstrap法或者交叉验证法,下面我们选择500次bootstrap的内部验证方法,计算时间点为第1年的校准曲线(样本太少,给警告了):
# 建立cox回归模型,时间点选择1年
<- cph(Surv(time, status) ~ sex + ph.ecog + ph.karno + wt.loss,
coxfit1 data = train_df, x = T, y = T, surv = T,
time.inc = 100 # 100天
)
# m=40表示以40个样本为1组,一般取4-6组,我们这个数据样本量太少了
# u=100和上面的time.inc对应
<- calibrate(coxfit1, cmethod = "KM", method = "boot",
cal1 u = 100, m = 40, B = 500)
## Using Cox survival estimates at 100 days
31.2.1 训练集
接下来就是画图,可以直接使用plot()
函数:
plot(cal1)
也可以提取数据,自己画,以实现更多的细节控制:
plot(cal1,
lwd = 2, # 误差线粗细
lty = 1, # 误差线类型,可选0-6
errbar.col = c("#2166AC"), # 误差线颜色
xlim = c(0.7,1),ylim= c(0.7,1), # 坐标轴范围
xlab = "Prediced OS",ylab = "Observed OS",
cex.lab=1.2, cex.axis=1, cex.main=1.2, cex.sub=0.6) # 字体大小
lines(cal1[,c('mean.predicted',"KM")],
type = 'b', # 连线的类型,可以是"p","b","o"
lwd = 3, # 连线的粗细
pch = 16, # 点的形状,可以是0-20
col = "tomato") # 连线的颜色
box(lwd = 2) # 边框粗细
abline(0,1,lty = 3, # 对角线为虚线
lwd = 2, # 对角线的粗细
col = "grey70" # 对角线的颜色
)
31.2.2 测试集
然后是外部验证集的校准曲线:
# 获取测试集的预测的生存概率,这一步有没有都行
<- survest(coxfit1,newdata=test_df,times=100)$surv
estimates
<- val.surv(coxfit1, newdata = test_df,
vs S = Surv(test_df$time,test_df$status),
est.surv = estimates,# 这一步有没有都行
u = 100 # 时间点,也是选100天
)plot(vs)
31.3 方法2:riskRegression
这个R包也非常好用,但是这种方法不能有缺失值,所以我先把缺失值去掉,然后再划分训练集和测试集,但是由于样本量太少,这里的划分方法是不正确的哈。
# 删除缺失值
<- na.omit(lung)
df2
# 划分数据
set.seed(123)
<- sample(1:nrow(df2),nrow(df2)*0.9)
ind1 <- df2[ind1,]
train_df
set.seed(563435)
<- sample(1:nrow(df2),nrow(df2)*0.9)
ind2 <- df2[ind2, ]
test_df
dim(train_df)
## [1] 150 10
dim(test_df)
## [1] 150 10
# 构建模型
<- coxph(Surv(time, status) ~ sex + ph.ecog + ph.karno,
cox_fit1 data = train_df,x = T, y = T)
31.3.1 训练集
# 画图
library(riskRegression)
set.seed(1)
<- Score(list("fit1" = cox_fit1),
cox_fit_s formula = Surv(time, status) ~ 1,
data = train_df,
plots = "calibration",
conf.int = T,
B = 500,
M = 50, # 每组的人数
times=c(100) # 时间点选100天
)plotCalibration(cox_fit_s,cens.method="local",# 减少输出日志
xlab = "Predicted Risk",
ylab = "Observerd RISK")
当然也是可以用ggplot2
画图的。
# 获取数据
<- plotCalibration(cox_fit_s,plot = F,cens.method="local")
data_all
# 数据转换
<- data_all$plotFrames$fit1
plot_df
# 画图
library(ggplot2)
ggplot(plot_df, aes(Pred,Obs))+
geom_point()+
geom_line(linewidth=1.2)+
scale_x_continuous(limits = c(0,0.5),name = "Predicted Risk")+
scale_y_continuous(limits = c(0,0.5),name = "Observerd Risk")+
geom_abline(slope = 1,intercept = 0,lty=2)+
theme_bw()
31.3.2 测试集
使用起来完全一样,只需要提供测试集即可:
set.seed(1)
<- Score(list("fit1" = cox_fit1),
cox_fit_s formula = Surv(time, status) ~ 1,
data = test_df, # 测试集
plots = "calibration",
B = 500,
M = 50,
times=c(100) # 时间点
)plotCalibration(cox_fit_s,cens.method="local",# 减少输出日志
xlab = "Predicted Risk",
ylab = "Observerd Risk")
这个结果也是可以用ggplot2
绘制的,就不再重复了。