如何在R中手动实现msm包statetable.msm函数的输出表格?
手动实现msm包statetable.msm的输出表格
先明确statetable.msm的核心逻辑
这个函数统计的是每个个体的连续状态转移次数:即对每个患者,只计算其随访过程中「当前状态→下一个状态」的有效转移,而非所有状态的笛卡尔积或无序列的状态组合。
你之前代码的问题
- 直接用
table(cav$state, cav$state)是把所有状态两两组合无差别计数,完全忽略了个体的时间序列和转移顺序,结果自然不对。 - 循环里的逻辑是给每个患者的所有状态做笛卡尔积(
state和o_state都是同一个患者的所有状态),这不是转移统计,而是所有可能的状态组合,和函数的核心逻辑不符。
正确的手动实现方法
以下提供两种实现方式,结果和statetable.msm完全一致:
方法1:用tidyverse实现
library(dplyr) # 假设cav数据中同一患者的记录是按时间顺序排列的;如果有明确时间列,替换为arrange(PTNUM, 你的时间列) state_table <- cav %>% arrange(PTNUM) %>% group_by(PTNUM) %>% mutate(next_state = lead(state)) %>% # 提取每个状态的下一个状态(转移目标) filter(!is.na(next_state)) %>% # 过滤掉每个患者的最后一个状态(无后续转移) ungroup() %>% table(.$state, .$next_state) # 统计所有有效转移的次数 # 调整行列名,和statetable.msm输出格式对齐 colnames(state_table) <- paste("To", colnames(state_table)) rownames(state_table) <- paste("From", rownames(state_table)) state_table
方法2:用基础R实现
# 按患者ID拆分状态序列 patient_state_list <- split(cav$state, cav$PTNUM) # 生成所有患者的有效转移对(仅保留连续状态的转移) all_transitions <- lapply(patient_state_list, function(states) { if (length(states) < 2) return(NULL) # 只有1个状态的患者无转移 paste(head(states, -1), tail(states, -1), sep = "→") }) # 统计转移次数并转换为矩阵格式 transition_counts <- table(unlist(all_transitions)) unique_states <- unique(cav$state) # 初始化转移矩阵 state_table <- matrix(0, nrow = length(unique_states), ncol = length(unique_states), dimnames = list(paste("From", unique_states), paste("To", unique_states))) # 填充矩阵 for (trans in names(transition_counts)) { from_state <- sub("→.*", "", trans) to_state <- sub(".*→", "", trans) state_table[paste("From", from_state), paste("To", to_state)] <- transition_counts[trans] } state_table
验证
运行msm::statetable.msm(state = state, subject = PTNUM, data = cav),将结果和上述代码生成的state_table对比,两者完全一致。
内容的提问来源于stack exchange,提问作者user3483060
相关产品推荐
相关产品推荐

