使用lapply()时为何会读取到不需要的Excel工作表?
问题分析与解决
问题场景
接手了别人写的R代码,用来批量提取多家医疗诊所Excel里的财务数据:
- 每家诊所的Excel里,每个工作表对应一个月份的数据
- 用
lapply()遍历指定季度的月份,只提取对应季度的数据 - 其中一家诊所的Excel只有2022年1月、2月的工作表,这次要做四季度(10-12月)更新,按道理不该出现这家诊所的1、2月数据
- 跑脚本时,这家诊所的Excel因为找不到
October工作表报错,在RStudio里跳过错误后脚本跑完了,但最终输出里居然还是有这家诊所的1、2月数据
问题根源
核心问题出在函数没初始化内部变量,而且全局环境里留着旧的dat数据:
- 这次要提取四季度的三个月份(10、11、12月),但这家诊所的Excel里只有1、2月的工作表,所以
read_excel找October工作表时直接报错 - 在RStudio里跳过错误后,函数接着往下跑,但这时候
dat变量根本没被read_excel创建出来 - R找不到函数内部的
dat,就会去全局环境里找——而之前测试代码时生成的1、2月数据正好存在全局的dat里 - 后续代码直接给这个旧的
dat加月份、年份、诊所名称,然后返回,结果旧数据就混进新输出里了
另外,代码完全没做错误处理,全靠手动跳过错误,这也让问题更容易发生。
解决方案
1. 给函数内部变量初始化,杜绝引用全局旧数据
在函数开头先把dat设为空数据框,就算read_excel报错,也不会去全局环境找旧数据:
MClist22 = lapply(quarter, function(x){ dat <- data.frame() # 先初始化空数据框 tryCatch({ # 只有工作表存在时,才执行提取逻辑 dat = read_excel(MCPath22, sheet = x, skip = 1)[c(1,2)] names(dat) = names dat$Month = x dat$Year = year dat$Location = "Medical Center" }, error = function(e){ # 捕获错误,打印提示,不中断后续迭代 message(paste("跳过不存在的工作表:", x)) }) return(dat) })
2. 用tryCatch自动处理不存在的工作表
用tryCatch捕获read_excel的错误,不用手动跳过:
- 工作表存在时,正常提取数据
- 工作表不存在时,自动打印提示,返回空数据框,不影响后面的月份遍历
3. 合并前过滤空数据框
把MClist22里的空数据框过滤掉,避免合并出无效行:
MC_newdata = do.call(rbind, Filter(NROW, MClist22)) %>% select(Medication, `Total WAC`, Month, Year, Location) %>% mutate(Date.Added = Sys.time())
Filter(NROW, MClist22)会只保留有数据的框,空的直接过滤掉。
4. 清理全局环境旧变量(可选)
在脚本开头加rm(list = ls())(注意:会清空全局环境所有变量,确保你没重要数据在里面再用),或者每次跑脚本前手动删掉dat这类临时变量,防止旧数据捣乱。
内容的提问来源于stack exchange,提问作者JKA99
相关产品推荐
相关产品推荐

