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

如何计算R语言数据集中时间区间在各年份的持续时长

计算时间区间在各年份的持续时长(R语言实现)

我有一个包含id、startyr(起始日期,以年为单位的小数)、endyr(结束日期,以年为单位的小数)三个变量的R语言数据集df,需要计算每个时间区间在各整数年份的持续时长。例如区间2023.50-2024.50,需将0.5年分配给2023年,0.5年分配给2024年。

数据集生成代码

id <- rep(1:100, times = 1)
startyr <- rnorm(n = 100, mean = 2024, sd = 1)
endyr <- startyr + 0.325 
df <- data.frame(id, startyr, endyr)

# 查看前5行数据
head(df)
#      id  startyr    endyr
# 1     1 2023.067 2023.392
# 2     2 2024.936 2025.261
# 3     3 2025.173 2025.498
# 4     4 2024.615 2024.940
# 5     5 2023.747 2024.072

理想输出示例

#     id  startyr    endyr dur2023  dur2024  dur2025  dur2026 
#      X 2023.5     2024.5   0.5     0.5         0      0
#      Y 2024.15     2026.15   0     0.85        1      0.15

实现方案

可以使用tidyverse工具包完成需求,核心思路是拆分时间区间到对应年份、计算各年份有效时长,最后转成宽格式输出:

# 加载工具包
library(tidyverse)

# 计算各年份持续时长
df_dur <- df %>%
  # 按行处理每个数据点
  rowwise() %>%
  # 生成该区间覆盖的所有整数年份(比如2023.7-2024.2覆盖2023、2024)
  mutate(year = list(floor(startyr):floor(endyr))) %>%
  # 把年份列表展开为多行数据
  unnest(year) %>%
  # 计算每个年份内的有效时长
  mutate(
    year_start = year,
    year_end = year + 1,
    # 取区间与年份的重叠部分长度
    duration = pmin(endyr, year_end) - pmax(startyr, year_start)
  ) %>%
  # 转宽格式,每个年份对应一列,缺失年份填充0
  pivot_wider(
    names_from = year,
    values_from = duration,
    names_prefix = "dur",
    values_fill = 0
  )

# 查看处理后的前5行数据
head(df_dur)

如果需要限定输出的年份范围(比如只保留2023-2026),可以修改代码如下,确保指定年份全部显示,无重叠的年份时长为0:

df_dur_fixed <- df %>%
  rowwise() %>%
  # 指定要包含的年份范围
  mutate(year = list(2023:2026)) %>%
  unnest(year) %>%
  mutate(
    year_start = year,
    year_end = year + 1,
    # 确保无重叠时时长为0
    duration = pmax(0, pmin(endyr, year_end) - pmax(startyr, year_start))
  ) %>%
  pivot_wider(
    names_from = year,
    values_from = duration,
    names_prefix = "dur",
    values_fill = 0
  )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 06:12:49