在 POSIXt 数据上拟合正弦波模型并使用 Ggplot2 绘图
Fitting a sine wave model on POSIXt data and plotting using Ggplot2
长期reader,第一次提问:)
我有一些在特定时间和日期收集的数据,有理由假设这些数据大致遵循 24 小时周期。我想在我的数据上拟合一个正弦波模型作为时间的函数,这样就可以测试未来的数据点是否落在预测模式上。
我已阅读 , this and this 回复,但他们没有解决我的问题,因为在我的情况下,我希望将 x 轴数据保留为 POSIXct 日期时间格式。这就是数据的收集方式,使用这种格式可以轻松解释图表。
这是一些与我的真实数据相同的可重现数据:
time <- c("2022-01-01 09:20:00", "2022-01-02 11:10:00",
"2022-01-02 18:37:00", "2022-01-03 14:01:00",
"2022-01-05 06:50:00", "2022-01-06 17:03:00")
time <- as.POSIXct(time)
value <- c(3, 6, 2, 8, 4, 1)
这些在 base R 中绘制得很好:
plot(time, value)
但是,现在我 运行 在尝试构建适合时间序列的正弦回归模型时遇到了麻烦。我也在努力完全理解 nls 函数所需的参数。基于前面的示例,我尝试了这种方法(并评论了我对它的工作方式的理解):
res <- nls(value ~ A * sin(omega * time + phi) + C, # This is the basic sine-function format
data = data.frame(time, value), # This defines the data used
start = list(A = 1, omega = 1, phi = 1, C = 1)) # This gives nls the starting values?
在这里,我收到一条错误消息:“Ops.POSIXt(omega, time) 中的错误:‘*’未为“POSIXt”对象定义”,我将其解释为我想要的特定日期格式使用这种方法是不可接受的。我知道这一点,因为如果我简单地用整数的虚拟向量替换时间变量,模型就可以正常工作,我可以按如下方式绘制它:
time2 <- c(1, 2, 3, 4, 5, 6)
res <- nls(value ~ A * sin(omega * time2 + phi) + C,
data = data.frame(time, value),
start=list(A=1, omega=1, phi=1, C=1))
coefs <- coef(res)
fit <- function(x, a, b, c, d) {a * sin(b * x + c) + d}
plot(time2, value)
curve(fit(x, a = coefs["A"], b = coefs["omega"],
c = coefs["phi"], d = coefs["C"]), add=TRUE,
lwd=2, col="red")
我知道我在正确的轨道上,但我的主要问题是,我如何在保持 POSIXct 格式的时间变量的同时执行上述过程?
如前所述,我的主要任务是使用 Ggplot2 绘制数据,但在解决最初的问题之前我什至无法开始尝试。但是,非常感谢任何关于如何开始的指示! :)
我可能只是从任意原始时间生成一个数字天数并使用它。然后,您可以修改 fit
函数,以便将 date-times 转换为预测值。然后,您可以轻松地根据模型制作预测数据框并绘制它。
df <- data.frame(time = time, value = value)
origin <- as.POSIXct("2022-01-01 00:00:00")
df$days <- as.numeric(difftime(time, origin, unit = "day"))
res <- nls(value ~ A * sin(omega * days + phi) + C,
data = df,
start = list(A = 1, omega = 1, phi = 1, C = 1))
fit <- function(res, newdata) {
x <- as.numeric(difftime(origin, newdata$time, units = "days"))
C <- as.list(coef(res))
C$A * sin(C$omega * x + C$phi) + C$C
}
new_df <- data.frame(time = origin + as.difftime(new_times, units = "days"))
new_df$value <- fit(res, new_df)
ggplot(df, aes(time, value)) +
geom_point() +
geom_line(data = new_df, colour = "gray") +
theme_bw()
长期reader,第一次提问:)
我有一些在特定时间和日期收集的数据,有理由假设这些数据大致遵循 24 小时周期。我想在我的数据上拟合一个正弦波模型作为时间的函数,这样就可以测试未来的数据点是否落在预测模式上。
我已阅读
这是一些与我的真实数据相同的可重现数据:
time <- c("2022-01-01 09:20:00", "2022-01-02 11:10:00",
"2022-01-02 18:37:00", "2022-01-03 14:01:00",
"2022-01-05 06:50:00", "2022-01-06 17:03:00")
time <- as.POSIXct(time)
value <- c(3, 6, 2, 8, 4, 1)
这些在 base R 中绘制得很好:
plot(time, value)
但是,现在我 运行 在尝试构建适合时间序列的正弦回归模型时遇到了麻烦。我也在努力完全理解 nls 函数所需的参数。基于前面的示例,我尝试了这种方法(并评论了我对它的工作方式的理解):
res <- nls(value ~ A * sin(omega * time + phi) + C, # This is the basic sine-function format
data = data.frame(time, value), # This defines the data used
start = list(A = 1, omega = 1, phi = 1, C = 1)) # This gives nls the starting values?
在这里,我收到一条错误消息:“Ops.POSIXt(omega, time) 中的错误:‘*’未为“POSIXt”对象定义”,我将其解释为我想要的特定日期格式使用这种方法是不可接受的。我知道这一点,因为如果我简单地用整数的虚拟向量替换时间变量,模型就可以正常工作,我可以按如下方式绘制它:
time2 <- c(1, 2, 3, 4, 5, 6)
res <- nls(value ~ A * sin(omega * time2 + phi) + C,
data = data.frame(time, value),
start=list(A=1, omega=1, phi=1, C=1))
coefs <- coef(res)
fit <- function(x, a, b, c, d) {a * sin(b * x + c) + d}
plot(time2, value)
curve(fit(x, a = coefs["A"], b = coefs["omega"],
c = coefs["phi"], d = coefs["C"]), add=TRUE,
lwd=2, col="red")
我知道我在正确的轨道上,但我的主要问题是,我如何在保持 POSIXct 格式的时间变量的同时执行上述过程?
如前所述,我的主要任务是使用 Ggplot2 绘制数据,但在解决最初的问题之前我什至无法开始尝试。但是,非常感谢任何关于如何开始的指示! :)
我可能只是从任意原始时间生成一个数字天数并使用它。然后,您可以修改 fit
函数,以便将 date-times 转换为预测值。然后,您可以轻松地根据模型制作预测数据框并绘制它。
df <- data.frame(time = time, value = value)
origin <- as.POSIXct("2022-01-01 00:00:00")
df$days <- as.numeric(difftime(time, origin, unit = "day"))
res <- nls(value ~ A * sin(omega * days + phi) + C,
data = df,
start = list(A = 1, omega = 1, phi = 1, C = 1))
fit <- function(res, newdata) {
x <- as.numeric(difftime(origin, newdata$time, units = "days"))
C <- as.list(coef(res))
C$A * sin(C$omega * x + C$phi) + C$C
}
new_df <- data.frame(time = origin + as.difftime(new_times, units = "days"))
new_df$value <- fit(res, new_df)
ggplot(df, aes(time, value)) +
geom_point() +
geom_line(data = new_df, colour = "gray") +
theme_bw()