含条件中断的while循环计算时长:代码无法识别End_Focal问题排查
问题排查与解决方案
核心错误原因
连续Out_Sight区间被重复计算
你的代码中,外层for循环会遍历每一行j,只要该行是Out_Sight就会计算从j到停止点k的时长。但当存在连续多行Out_Sight时,每一行都会触发一次计算——比如Out_Sight从行2到行5,j=2时计算5-2,j=3时计算5-3,j=4时计算5-4,这些值会被重复累加到总和中,导致最终时长被严重高估。stop使用list类型不必要
虽然%in%可以处理list,但使用向量更符合R的常规用法,避免潜在的类型匹配歧义。
修正后的代码
# 保留你的"not in"函数 '%!in%' <- function(x,y)!('%in%'(x,y)) # 处理时间列 df$HMS <- lubridate::hms(df$Time, roll = F) # 初始化foc_summary(仅保留ObsID列) library(dplyr) foc_summary <- df %>% mutate(ObsID = factor(ObsID)) %>% group_by(ObsID) %>% slice(1) %>% select(ObsID) detach('package:dplyr') foc_summary <- as.data.frame(foc_summary) # 按ObsID和时间排序数据 df <- df[order(df$ObsID, df$HMS),] # 将stop改为向量类型 stop <- c("In_Sight", "End_Focal") # 初始化结果列 foc_summary$Time_OutSight <- 0 # 按ObsID计算视线外时长 for (i in 1:nrow(foc_summary)){ current_obs <- foc_summary$ObsID[i] print(current_obs) obs_data <- droplevels(subset(df, df$ObsID == current_obs)) total_out <- 0 j <- 1 while(j <= nrow(obs_data)){ if (obs_data$Setting[j] == "Out_Sight"){ # 找到当前Out_Sight区间的结束点 k <- j + 1 while(k <= nrow(obs_data) && obs_data$Setting[k] %!in% stop){ k <- k + 1 } # 处理边界:如果到观测末尾,取最后一行的时间 end_time <- ifelse(k > nrow(obs_data), obs_data$HMS[nrow(obs_data)], obs_data$HMS[k]) # 累加当前区间的时长 total_out <- total_out + as.numeric(end_time) - as.numeric(obs_data$HMS[j]) # 跳到区间结束点,避免重复处理 j <- k } else { j <- j + 1 } } foc_summary$Time_OutSight[i] <- total_out }
关键修改说明
- 改用
while循环遍历行,处理完一个Out_Sight区间后直接跳到结束点k,彻底避免重复计算同一区间的时长。 - 将
stop从list改为向量,消除类型歧义。 - 增加边界判断,处理
Out_Sight持续到观测最后一行的情况,防止索引越界。 - 简化累加逻辑,避免用
c()不断扩展向量,提升代码效率。
内容的提问来源于stack exchange,提问作者Vittoria Roatti
相关产品推荐
相关产品推荐

