用样条插值并保持精确的打结值

Interpolate with spline and keep exact knotted values

问题

我正在研究样条曲线并尝试连接月中以插入从 1 月 15 日开始的全年;但是,我想确保全年的中点月份设置正确。也就是说,我希望每个月的中点(第 15 个)与原始月度数据相同。目前,我的代码没有这样做,一些值与原始代码有很大不同。如果可能的话,我想确保这些精确值符合每个月中点(15 日)的数据。

有没有办法确保原始数据中的那些点在插值数据中设置正确,使它们位于每个月的中点(15 日)的准确位置?

示例:

# Monthly data
df <- data.frame(x <- seq(1,12), 
                 y <- c(45, 54, 50 ,63, 70, 75, 80, 88, 76, 81, 63, 54))

# Interpolate with spline to daily data starting with 15th of January (351 days)
values <- spline(df$x, df$y, n = 351)$y

# Check values
# Original values
df$y

# New values at 15th of each month
values[c(1,31, 60,91,121,152,182,213,244,274,305,335)]

输出(有些圆好,但大部分都关闭):

> df$y
 [1] 45 54 50 63 70 75 80 88 76 81 63 54

> values[c(1,31, 60,91,121,152,182,213,244,274,305,335)]
 [1] 45.00000 54.21321 49.65891 60.61385 68.91151 73.89644 77.62606 87.33305 79.66860 79.27115 73.10543 54.71480

期望的输出:

    > df$y
     [1] 45 54 50 63 70 75 80 88 76 81 63 54

    > values[c(1,31, 60,91,121,152,182,213,244,274,305,335)]
     [1] 45 54 50 63 70 75 80 88 76 81 63 54

图片:

红色:原月积分

黑线:来自样条插值的点

如果您试图使事情与日历日保持一致,您可以让 R 完成跟踪日期的工作。这种方法也可以处理闰年。最后,您可以从 1 月 15 日开始按天索引。以今年为例,代码可能如下所示:

  df <- data.frame(x=seq.Date(as.Date("2015-01-15"), by="month", length.out=12), 
                   y = c(45, 54, 50 ,63, 70, 75, 80, 88, 76, 81, 63, 54))
   values_by_date <- splinefun(df$x, df$y)
#
# To get a value at every day between Jan 15 and Dec 15
#
 values <- values_by_date(seq.Date(df$x[1], tail(df$x,1), by="day"))
#
#  Check dates at mid month
#  Note that second index should be 32, not 31
#
 values[c(1,32, 60,91,121,152,182,213,244,274,305,335)]

[1] 45 54 50 63 70 75 80 88 76 81 63 54

也许它比 WaltS 提供的答案更复杂,但它有效:

# Input data:
df <- data.frame(x <- seq(1,12),
                 y <- c(45, 54, 50 ,63, 70, 75, 80, 88, 76, 81, 63, 54))
# I use this dataframe to get the right position for the ticks
# The "offset_days" column is left 'empty' at start:
days_of_month <- data.frame(months=c('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'),
                            days = c(31,28,31,30,31,30,31,31,30,31,30,31),
                            offset_days = 0)
# Offset: The day of month you want your ticks to be placed (should be between 1 and 28):
offset <- 15

# Fill the "offset_days" column with the appropriate day
for(i in 1:nrow(days_of_month)) {
  if(i == 1)
    days_of_month$offset_days[i] <- offset
  else
    days_of_month$offset_days[i] <- days_of_month$offset_days[i-1] + days_of_month$days[i-1]
}

# Calculate the spline with the offset days as x value:
sp <- spline(days_of_month$offset_days, df$y, 351)

plot(sp$x, sp$y, type='l', xlim=c(0,365), xaxt='n')
lines(days_of_month$offset_days, df$y, type='o', col='red')
axis(side=1, at=cumsum(days_of_month$days), lab=rep('',12))
axis(side=1, at=days_of_month$offset_days, lab=days_of_month$months, tck=0)

输出:

红线是你的原始数据,黑线是平滑后的数据。

希望对您有所帮助