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

将R语言循环代码转为向量化列表时遇向量索引错误求助

问题:重构R代码时的索引错误解决思路

原始混乱代码

之前使用的代码结构不规范,具体如下:

library(dplyr); library(plyr)
library(magrittr); library(stringr) 
library(ExclusionTable)
library(lubridate)
library(tidyverse); library(tidyr)
library(janitor)
library(survival)
library(ggsurvfit); library(gtsummary)
library(zoo)
library(tidycmprsk)

# AA cohort (2 of 3)
## as

i=1
num_fu = c(1,2,3,4,5,6,7,8,9)
as <- data.frame()
df <- data.frame()
dfs <- data.frame()
data_dir <- 'C:/Users/thepr/Documents/data/as'

assign(paste0("flnames", i), list.files(path = paste0(data_dir, i), pattern = "\\.csv", full.names = TRUE))
assign(paste0("as", i, "_list"), lapply(get(paste0("flnames", i)),
                                        function(x){base::as.data.frame(read.csv(x))}))
nm <- gsub(".csv", "", basename(eval(parse(text = paste0("flnames", i))))) %>% str_sub(., 1,6)
assign(paste0("as", i, "_list"), setNames(get(paste0("as", i, "_list")), nm))
df <- Reduce(full_join, get(paste0("as", i, "_list")))
assign(paste0("as",i), df[!duplicated(base::as.list(df))])
dfs <- df

for (i in 2:length(num_fu)){
RID_common <- as1$RID %in% get(paste0("as", i))$RID

      assign(paste0("flnames", i), list.files(path = paste0(data_dir, i), pattern = "\\.csv", full.names = TRUE))
      assign(paste0("as", i, "_list"), lapply(get(paste0("flnames", i)),
                                              function(x){base::as.data.frame(read.csv(x))}))
      nm <- gsub(".csv", "", basename(eval(parse(text = paste0("flnames", i))))) %>% str_sub(., 1,6)
      assign(paste0("as", i, "_list"), setNames(get(paste0("as", i, "_list")), nm))
      df <- Reduce(full_join, get(paste0("as", i, "_list")))
      assign(paste0("as",i), df[!duplicated(base::as.list(df))])
      
      dfs <- merge(dfs, df, by = "RID", all.x = TRUE)
      dfs <- dfs[!duplicated(base::as.list(dfs))]
            if(paste0("AS", i, "_AREA") %in% colnames(get(paste0("as", i)))){
              assign(paste0("fu_",i-1), get(paste0("as", i))[RID_common, c("RID", paste0("AS", i, "_AREA"))])
              assign(paste0("fu_loss_",i-1), get(paste0("as", i))[!RID_common, c("RID", paste0("AS", i, "_AREA"))])
            # FU rate
              assign(paste0("fu_rate_", i-1), nrow(get(paste0("as", i)))/nrow(as1))
            }
            else if(paste0("AS", i, "_DATA_CLASS") %in% colnames(get(paste0("as", i)))){
              assign(paste0("fu_",i-1), get(paste0("as", i))[RID_common, c("RID", paste0("AS", i, "_DATA_CLASS"))])
              assign(paste0("fu_loss_",i-1), get(paste0("as", i))[!RID_common, c("RID", paste0("AS", i, "_DATA_CLASS"))])
            # FU rate
              assign(paste0("fu_rate_", i-1), nrow(get(paste0("as", i)))/nrow(as1))
            }
            else{}
}

重构尝试代码

根据建议改用列表和向量重构代码,尝试版本如下:

library(tidyverse) #Includes: dplyr, stringr, tidyr
library(magrittr)
library(lubridate)
library(ExclusionTable)
library(janitor)
library(survival)
library(ggsurvfit); library(gtsummary)
library(zoo)
library(tidycmprsk)

# AA cohort (2 of 3)
## as
i=1
data_dir = c("C:/Users/thepr/Documents/data/as")
num_fu = c(1,2,3,4,5,6,7,8,9)
dirs <- paste0(data_dir, num_fu) # character
as <- data.frame()
df <- data.frame()
dfs <- data.frame()

flnames <- list.files(path = dirs, pattern = "\\.csv", full.names = TRUE)
as_list[[num_fu]] <- lapply(flnames[[num_fu]],
       function(x){base::as.data.frame(read.csv(x))})
names(as_list) <- gsub(".csv", "", basename(flnames[[num_fu]])) %>% str_sub(., 1,6)
df <- Reduce(full_join, as_list)
df <- df[!duplicated(base::as.list(df))]

遇到的错误

Error in flnames[[num_fu]] :  attempt to select more than one element in vectorIndex

解决思路与建议

  1. 错误根源解析:flnames是list.files返回的字符向量,并非列表。用[[num_fu]](num_fu是长度为9的向量)索引向量会报错,因为向量索引只能是单个整数或字符,不能是多元素向量。

  2. 按文件夹分组读取文件:按dirs中的每个文件夹分别读取文件,用lapply遍历文件夹路径,生成对应文件列表和数据框列表:

    # 按文件夹生成文件路径列表
    flnames_list <- lapply(dirs, function(dir) {
      list.files(path = dir, pattern = "\\.csv", full.names = TRUE)
    })
    # 用随访次数命名列表
    names(flnames_list) <- num_fu
    
    # 读取每个文件夹下的csv为数据框列表,并按规则命名
    as_list <- lapply(flnames_list, function(files) {
      file_names <- str_sub(gsub("\\.csv", "", basename(files)), 1, 6)
      lapply(files, read.csv) %>% setNames(file_names)
    })
    
  3. 合并每个随访阶段的数据:对as_list中每个子列表(对应一个随访阶段的多个csv)进行合并,同时简化去重操作:

    # 合并每个随访阶段内的csv,自动去重
    merged_as_list <- lapply(as_list, function(dfs) {
      Reduce(full_join, dfs) %>% distinct()
    })
    
  4. 统一处理随访与失访数据:用列表存储所有随访相关结果,避免用assign创建零散对象:

    # 提取基线数据(第一个随访阶段)
    baseline_df <- merged_as_list[[1]]
    # 遍历后续随访阶段,整理随访、失访数据及随访率
    followup_results <- lapply(2:length(merged_as_list), function(idx) {
      current_df <- merged_as_list[[idx]]
      rid_common <- baseline_df$RID %in% current_df$RID
      # 确定目标列
      target_col <- case_when(
        paste0("AS", idx, "_AREA") %in% colnames(current_df) ~ paste0("AS", idx, "_AREA"),
        paste0("AS", idx, "_DATA_CLASS") %in% colnames(current_df) ~ paste0("AS", idx, "_DATA_CLASS"),
        TRUE ~ NULL
      )
      list(
        fu = current_df[rid_common, c("RID", target_col)],
        fu_loss = current_df[!rid_common, c("RID", target_col)],
        fu_rate = nrow(current_df)/nrow(baseline_df)
      )
    })
    # 命名结果列表
    names(followup_results) <- paste0("fu_", 1:(length(merged_as_list)-1))
    
  5. 合并所有随访数据:如果需要合并全阶段数据,用Reduce逐步合并:

    full_dfs <- Reduce(function(x, y) merge(x, y, by = "RID", all.x = TRUE), merged_as_list) %>% distinct()
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 16:07:01