从0开始学习R语言--Day13--混合效应与生存分析

混合效应模型(Mixed Effects Model)

对于数据来说,我们通常把所有样本共有的影响因素(性别,实验处理,实验方法),这种可以推广到总体的叫做固有效应,而仅适用于特定分组的(个体差异),叫做随机效应,混合效应模型就是用于处理既有固有效应又有随机效应的方法。

举一些具体点的例子,像同一个患者在一周内的血压数据,不同班级的学生成绩,不同地区的空气质量和查看对照实验的结果等,我们可以看到这些数据都有一些共同的特点,数据基本都有分组,且每个分组内的数据都有自己的特点,像学生成绩的固有效应就来自于考试的卷子难度,而随机效应既有学生的个体差异,也有师资差异,这需要我们在使用的时候有自己的判断。

下面我们举一个学生成绩的例子来举例:

R 复制代码
set.seed(123)
n_students <- 100
n_classes <- 5

# 模拟数据(保持不变)
data <- data.frame(
  student_id = 1:n_students,
  class_id = sample(1:n_classes, n_students, replace = TRUE),
  teaching_method = sample(c("A", "B"), n_students, replace = TRUE),
  baseline_score = rnorm(n_students, mean = 70, sd = 10)
)

data$score <- with(data, 
                   baseline_score + 
                     ifelse(teaching_method == "A", 5, -2) +  # 固定效应
                     rnorm(n_classes, sd = 3)[class_id] +     # 随机效应(班级)
                     rnorm(n_students, sd = 2)                # 个体误差
)

# 拟合模型(添加错误处理)
tryCatch({
  model <- lmer(score ~ teaching_method + (1 | class_id), data = data)
  summary(model)
}, error = function(e) {
  message("lme4出错,改用nlme包:")
  library(nlme)
  model <- lme(score ~ teaching_method, random = ~ 1 | class_id, data = data)
  summary(model)
})

# 绘图(保持不变)
ggplot(data, aes(x = teaching_method, y = score, color = factor(class_id))) +
  geom_boxplot() +
  labs(title = "成绩按教学方法和班级分布", 
       x = "教学方法", 
       color = "班级") +
  theme_minimal()

输出:

R 复制代码
Random effects:
 Formula: ~1 | class_id
        (Intercept) Residual
StdDev:    1.056784 11.59231

Fixed effects:  score ~ teaching_method 
                    Value Std.Error DF  t-value p-value
(Intercept)      75.44703  1.692050 94 44.58913   0e+00
teaching_methodB -7.93749  2.323873 94 -3.41563   9e-04

从输出可以看得出来,班级间的差异只有1.06,说明班级的分类对成绩的影响较小,而同一班级内不同学生的差异来到了11.59,说明成绩的变化主要来自于学生自己(比如有课外补习,下课有的人会勤快的问老师问题,有的学生特别聪明等);而从教学方法的p值可以看出,A教学方法对成绩的提升是最明显的,如果是研究不同老师的教学能力,可以将其纳入指标中(前提是控制学生群体相同),注意如果班级的数量大于5,即使随机效应里的标准差较小,最好也采用混合模型,因为班级数量太多的话,班级数量会呈现一定的结构,采用不同的模型可能会忽略层级结构的影响。

生存分析(Survival Analysis)

生存分析,很容易联想到是预测病人死亡的案例,事实上,确实是这样,生存分析是用来预测某个事件发生前的时间,像病人从治疗到死亡的时间,机器从使用到故障的时间,用户从注册到流失的时间等,反映出的核心问题是,在某个时间点,事件发生的概率是多少。

生存分析的关键在于从开始观察到事件发生的时间段内,是否发生了我们想要看到的事件,像预测病人死亡时,我们就会用到生存分析,但不一样的是,我们需要对数据进行筛选,就像生存分析的核心所说的,要筛选出符合所要事件的数据,当然了,这就跟指标有关了,比如在医学中常见的课题:患某类病的病人,在患有另一种病后死亡的概率,这种就需要筛选病人的药物,两种病的合并症,拿取的数据是否是在两类病发生中间的等等。而且,生存分析还可以利用缺少"结局"的数据,即如果病人还活着的数据,而不需要人为地赋予一个结局。

总而言之,通过生存分析,我们可以关注到是哪些因素影响到了事件发生的概率。

依然是通过一个例子来说明:

R 复制代码
set.seed(123)
n <- 100
treatment <- sample(c("A", "B"), n, replace = TRUE)
data <- data.frame(
  patient_id = 1:n,
  treatment = treatment,
  age = rnorm(n, mean = 60, sd = 10),
  time_to_event = round(rexp(n, rate = ifelse(treatment == "A", 0.01, 0.02)) + 30),
  event = rbinom(n, 1, 0.8)
)

# 生存分析
surv_obj <- Surv(data$time_to_event, data$event)
fit <- survfit(surv_obj ~ treatment, data = data)

# 绘制生存曲线
ggsurvplot(fit, data = data, 
           pval = TRUE,          # 显示组间差异p值
           risk.table = TRUE,    # 显示风险表
           title = "生存曲线(治疗A vs B)")

# Cox模型(分析影响因素)
cox_model <- coxph(Surv(time_to_event, event) ~ treatment + age, data = data)
summary(cox_model)

输出:

R 复制代码
Call:
coxph(formula = Surv(time_to_event, event) ~ treatment + age, 
    data = data)

  n= 100, number of events= 75 

                coef exp(coef)  se(coef)      z Pr(>|z|)    
treatmentB  1.012157  2.751528  0.266035  3.805 0.000142 ***
age        -0.007869  0.992162  0.012148 -0.648 0.517146    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

           exp(coef) exp(-coef) lower .95 upper .95
treatmentB    2.7515     0.3634    1.6335     4.635
age           0.9922     1.0079    0.9688     1.016

Concordance= 0.626  (se = 0.036 )
Likelihood ratio test= 14.09  on 2 df,   p=9e-04
Wald test            = 14.57  on 2 df,   p=7e-04
Score (logrank) test = 15.58  on 2 df,   p=4e-04

从输出我们可以看到,在100个样本数据中,有缺失数据的有25个。而通过观察年龄和治疗方案的输出,首先从三个检验值Likelihood ratio test,Wald test和Score test能看出模型整体是存在差异的,说明至少有一个预测变量起到了显著影响,而通过观察coef和p值,我们可以判断年龄对病人的生存时间没有太大影响,相反治疗方案的选择,在死亡风险上展示出了较大的差异。不过模型的C-index为0.626,接近于0.5,说明模型的解释力一般,要谨慎对待结果。

相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习