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

如何解决周度转日度数据拆分中的负值与求和方向问题?

解决方案

1. 修正日期区间匹配问题

原数据的coll_wk是前7天累计值的结束日期,而tempdisagg默认将低频日期作为高频区间的起始日期(对应后续7天的和)。我们需要把每个周度值的锚点日期改为对应7天区间的起始日期,这样工具就能正确匹配“前7天”的总和逻辑:

library(dplyr)
library(tempdisagg)

# 为原数据添加区间起始日期:coll_wk往前推6天,得到7天区间的第一天
dat <- dat %>% mutate(coll_wk_start = coll_wk - 6)

2. 解决拆分后出现负值的问题

denton-cholette方法可能因趋势波动产生负值,我们可以换用线性/样条插值+非负截断+区间缩放的方式,既保证插值平滑,又确保非负和总和守恒:

方法A:基于线性插值的非负拆分

这种方法简单稳定,适合无明显周期的数据:

# 构造每个7天区间的中点日期,用周度值的1/7作为中点初始值
dat_mid <- dat %>%
  mutate(
    mid_date = coll_wk_start + 3,  # 7天区间的第4天(中点)
    mid_value = New_A / 7
  )

# 生成覆盖所有区间的日度日期序列
date_seq <- seq(min(dat$coll_wk_start), max(dat$coll_wk), by = "day")

# 线性插值得到初始日度值
interp_func <- approxfun(dat_mid$mid_date, dat_mid$mid_value, method = "linear", rule = 2)
initial_daily <- interp_func(date_seq)

# 截断负值(设为0)
initial_daily[initial_daily < 0] <- 0

# 按原7天区间分组,缩放日度值确保每组总和等于原周度值
daily_A <- tibble(date = date_seq, value = initial_daily) %>%
  mutate(week_group = findInterval(date, dat$coll_wk_start)) %>%
  left_join(dat %>% mutate(week_group = row_number(), original_sum = New_A), by = "week_group") %>%
  group_by(week_group) %>%
  mutate(New_A = value / sum(value) * original_sum) %>%
  ungroup() %>%
  select(date, New_A)

方法B:基于三次样条插值的平滑拆分

如果需要更平滑的日度曲线,可改用三次样条插值:

# 构造中点数据(同方法A)
dat_mid <- dat %>%
  mutate(
    mid_date = coll_wk_start + 3,
    mid_value = New_A / 7
  )

# 生成日度日期序列
date_seq <- seq(min(dat$coll_wk_start), max(dat$coll_wk), by = "day")

# 自然三次样条插值
spline_func <- splinefun(dat_mid$mid_date, dat_mid$mid_value, method = "natural")
initial_daily <- spline_func(date_seq)

# 截断负值并缩放(同方法A)
daily_A <- tibble(date = date_seq, value = initial_daily) %>%
  mutate(week_group = findInterval(date, dat$coll_wk_start)) %>%
  left_join(dat %>% mutate(week_group = row_number(), original_sum = New_A), by = "week_group") %>%
  mutate(value = ifelse(value < 0, 0, value)) %>%
  group_by(week_group) %>%
  mutate(New_A = value / sum(value) * original_sum) %>%
  ungroup() %>%
  select(date, New_A)

方法C:修正tempdisagg结果的负值问题

如果坚持使用tempdisagg,可以在拆分后对负值进行截断并重新缩放:

# 用调整后的起始日期进行拆分
dat_A <- dat %>% select(coll_wk_start, New_A) %>% rename(date = coll_wk_start, value = New_A)
disagg_result <- td(value ~ 1, data = dat_A, to = "daily", method = "denton-cholette", conversion = "sum")$values

# 生成日度日期序列
date_seq <- seq(min(dat$coll_wk_start), max(dat$coll_wk), by = "day")

# 截断负值并缩放
daily_A <- tibble(date = date_seq, value = disagg_result) %>%
  mutate(week_group = findInterval(date, dat$coll_wk_start)) %>%
  left_join(dat %>% mutate(week_group = row_number(), original_sum = New_A), by = "week_group") %>%
  mutate(value = ifelse(value < 0, 0, value)) %>%
  group_by(week_group) %>%
  mutate(New_A = value / sum(value) * original_sum) %>%
  ungroup() %>%
  select(date, New_A)

3. 批量处理New_B字段

以上方法均可直接复制用于New_B字段,只需将代码中的New_A替换为New_B即可。

验证结果

可以通过以下代码验证每个7天区间的总和是否等于原周度值:

# 验证New_A的拆分结果
daily_A %>%
  mutate(week_end = date + 6) %>%  # 每个日期对应的区间结束日期
  group_by(week_end) %>%
  summarise(daily_sum = sum(New_A)) %>%
  left_join(dat %>% select(coll_wk, original_sum = New_A), by = c("week_end" = "coll_wk")) %>%
  mutate(diff = daily_sum - original_sum)

所有diff值应接近0(浮点误差范围内),且所有New_A值均非负。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 14:47:02