You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用bind_rows合并for循环生成的列表时出错,求tidyverse解决方案

问题:合并生存分析ROC结果列表时的维度不匹配错误

数据背景

假设存在如下数据框a:

> head(a)
  Ki67 simpson  WHO event event.tid
1   25       1 WHO1     1        17
2   46       3 WHO3     2        48
3   99       2 WHO2     1       110
4   57       4 WHO1     2       148
5   66       1 WHO3     1         3
6   75       3 WHO2     2       173

数据生成代码:

a <- data.frame(
  Ki67 = sample(1:100, size = 6000, replace = TRUE),
  simpson = as.factor(sample(1:4)),
  WHO = sample(c("WHO1", "WHO2", "WHO3")),
  event = sample(1:2),
  event.tid = sample(1:200)
)

现有代码与报错

使用riskRegression计算不同分组下Ki67的生存ROC曲线,代码如下:

library(riskRegression)
library(tidyverse)

df_list <- list()

for(i in c("WHO1", "WHO2", "WHO3")){
  
  for(j in c("1", "2", "3", "4")){
    
    y <- filter(a, WHO == i, simpson == j) %>% droplevels()
    
    x <- Score(list("Ki67" =  y$Ki67),
               formula = Hist(event.tid, event) ~ 1,
               data = y,
               metrics = c("auc"),
               times = c(36, 60, 120),
               plots = "ROC")
    
    df_list[[length(df_list) + 1]] <- list(
      WHO = i,
      simpson = j,
      times = x$ROC$plotframe$times,
      tpr = x$ROC$plotframe$TPR,
      fpr = x$ROC$plotframe$FPR,
      ki67 = sort(unique(y$Ki67))
    )
      
  }
}

尝试用bind_rows(df_list)合并列表时,出现维度不匹配错误:

bind_rows(df_list)

Error in vctrs::data_frame(): ! Can't recycle WHO (size 300) to match ki67 (size 99). Run rlang::last_trace() to see where the error occurred.

尝试过ki67 = rep(sort(unique(y$Ki67)), length(i))但未解决问题,需要tidyverse框架下的解决方案。

解决方案

原因分析

报错核心是每个列表元素内的向量长度不一致:WHO/simpson是单值,times/tpr/fpr是等长向量(对应ROC曲线的每个点),而ki67是该分组下所有唯一Ki67值的向量,长度与前者不匹配,导致bind_rows无法自动对齐。


方案1:关联ROC点对应的Ki67截断值(推荐)

Score函数输出的x$ROC$plotframe中已经包含每个ROC点对应的Ki67截断值(cutoff列),无需手动提取唯一Ki67值。直接基于该数据框构造结果,确保所有字段长度一致:

library(riskRegression)
library(tidyverse)

# 生成所有分组组合
groups <- expand_grid(WHO = c("WHO1", "WHO2", "WHO3"), simpson = c("1", "2", "3", "4"))

# 用purrr替代for循环,tidy风格处理每个分组
result <- groups %>%
  mutate(roc_data = pmap(list(WHO, simpson), function(w, s) {
    y <- filter(a, WHO == w, simpson == s) %>% droplevels()
    if(nrow(y) == 0) return(tibble()) # 处理空分组
    
    x <- Score(list("Ki67" = y$Ki67),
               formula = Hist(event.tid, event) ~ 1,
               data = y,
               metrics = c("auc"),
               times = c(36, 60, 120),
               plots = "ROC")
    
    # 直接提取plotframe,添加分组信息
    x$ROC$plotframe %>%
      mutate(WHO = w, simpson = s, ki67 = cutoff) %>%
      select(WHO, simpson, times, tpr, fpr, ki67)
  })) %>%
  unnest(roc_data)

这样得到的result是标准的tidy数据框,每行对应一个分组、一个时间点、一个ROC点及其对应的Ki67截断值。


方案2:将唯一Ki67与所有ROC结果做笛卡尔积(若业务需要)

如果确实需要将分组内的每个唯一Ki67值与所有ROC曲线点组合(即每个Ki67对应所有时间点的TPR/FPR),可以通过笛卡尔积实现:

library(riskRegression)
library(tidyverse)

groups <- expand_grid(WHO = c("WHO1", "WHO2", "WHO3"), simpson = c("1", "2", "3", "4"))

result <- groups %>%
  mutate(roc_data = pmap(list(WHO, simpson), function(w, s) {
    y <- filter(a, WHO == w, simpson == s) %>% droplevels()
    if(nrow(y) == 0) return(tibble())
    
    x <- Score(list("Ki67" = y$Ki67),
               formula = Hist(event.tid, event) ~ 1,
               data = y,
               metrics = c("auc"),
               times = c(36, 60, 120),
               plots = "ROC")
    
    # 提取ROC基础数据和唯一Ki67,做笛卡尔积
    roc_df <- x$ROC$plotframe %>% select(times, tpr, fpr)
    ki67_df <- tibble(ki67 = sort(unique(y$Ki67)))
    
    crossing(roc_df, ki67_df) %>%
      mutate(WHO = w, simpson = s) %>%
      select(WHO, simpson, times, tpr, fpr, ki67)
  })) %>%
  unnest(roc_data)

此方案会生成大量行(每个Ki67 × 每个ROC点),需根据实际业务需求选择。

内容的提问来源于stack exchange,提问作者cmirian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 19:54:54