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

如何用dplyr替代for循环按组计算数据框峰谷时间差?

问题描述

需要基于分组数据框,使用find_peaks()函数识别每个分组的峰值和谷值,计算对应时间差,并通过dplyr实现按组批量处理(替代循环);最终输出支持长表或符合需求的宽表格式。

示例数据集

sample_df <- as.data.frame(cbind( 
  'group'= c('ABC123','ABC123','ABC123','ABC123','ABC123',
             'ABC111','ABC111','ABC111','ABC111',
             'ABC222','ABC222','ABC222','ABC222'),  
  'value' = c(12345, 13334, 12350, 13320, 12344, 
              12222, 12322, 12244,12344, 
              12315, 12333, 12305, 12365), 
  datetime = c("2000-01-01 23:50:00",
               "2000-01-01 23:51:00","2000-01-01 23:52:00","2000-01-01 23:53:30","2000-01-01 23:54:00",
               "2000-01-01 21:00:00","2000-01-01 21:10:00","2000-01-01 21:30:00","2000-01-01 22:00:00",
               "2000-01-01 03:00:02","2000-01-01 03:01:00","2000-01-01 03:02:10","2000-01-01 03:03:00")))

sample_df$value    <- as.numeric(sample_df$value)
sample_df$datetime <- as.POSIXct(sample_df$datetime) # 修正原示例错误的时间转换逻辑

解决方案

1. 封装单组处理逻辑

先定义函数,将单个分组内的峰值/谷值识别、时间差计算逻辑封装:

library(dplyr)

calculate_peak_valley_diff <- function(group_df) {
  # 识别当前分组的峰值、谷值索引
  peak_indices <- find_peaks(group_df$value, m = 1)
  valley_indices <- find_peaks(-group_df$value, m = 1)
  
  # 处理空索引的边界情况
  min_len <- min(length(peak_indices), length(valley_indices))
  if (min_len == 0) {
    return(tibble(diff = NA_character_))
  }
  
  # 对齐峰值和谷值的索引长度
  aligned_peaks <- peak_indices[1:min_len]
  aligned_valleys <- valley_indices[1:min_len]
  
  # 计算时间差并格式化为易读的文本
  time_diff <- abs(group_df$datetime[aligned_peaks] - group_df$datetime[aligned_valleys])
  formatted_diff <- case_when(
    as.numeric(time_diff, units = "secs") < 60 ~ paste(round(as.numeric(time_diff, units = "secs"), 1), "secs"),
    TRUE ~ paste(round(as.numeric(time_diff, units = "mins"), 3), "mins")
  )
  
  return(tibble(diff = formatted_diff))
}

2. dplyr按组批量处理

使用group_modify自动遍历每个分组,调用上述函数,输出长表格式结果:

# 按组计算,得到长表结果
long_result <- sample_df %>%
  group_by(group) %>%
  group_modify(~ calculate_peak_valley_diff(.x)) %>%
  ungroup()

# 查看长表输出
print(long_result)

3. 转换为宽表格式(匹配示例输出)

如果需要转换为以分组为列的宽表,结合tidyr实现:

library(tidyr)

wide_result <- long_result %>%
  group_by(group) %>%
  mutate(row_id = row_number()) %>% # 添加行号用于对齐不同长度的分组数据
  ungroup() %>%
  pivot_wider(names_from = group, values_from = diff) %>%
  select(-row_id)

# 查看宽表输出
print(wide_result)

关键说明

  • group_modify会自动拆分分组数据并传入自定义函数,无需手动处理分组拆分与合并
  • 函数内处理了空索引的边界情况,避免运行报错
  • 长表格式更适合后续数据分析,宽表则匹配你给出的示例输出形式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:02:57