在GLMM中如何将循环日期作为二次固定效应纳入模型?
在GLMM中实现循环日期的非线性(二次/高阶)效应
核心问题分析
你的尝试存在两个关键错误:
- 建模公式错误:
poly((Date_sin + Date_cos), 2)将正弦和余弦值相加后做多项式变换,完全丢失了循环变量的二维极坐标结构,把环形数据压缩成一维,无法捕捉真实的循环非线性趋势。 - 预测逻辑错误:用
ggpredict同时遍历Date_sin和Date_cos的所有取值,会生成大量不可能存在的组合(比如sin=0.9同时cos=0.9,不符合sin²+cos²=1的约束),导致逆变换得到的JulianDay完全无效,最终绘图结果混乱。
正确实现方案
下面提供两种可靠的方法,均可在GLMM中实现循环日期的非线性效应:
方法1:使用循环B样条(最简洁推荐)
直接对JulianDay使用循环B样条(splines::bs(..., bs="cc")),它天生支持循环结构,能自动捕捉非线性循环趋势,无需手动处理sin/cos变换:
library(tidyverse) library(glmmTMB) library(ggeffects) library(splines) data(airquality) airquality$Date = as.Date(paste0("2018-", airquality$Day, "-", airquality$Month)) airquality$JulianDay = yday(airquality$Date) airquality = airquality %>% drop_na(Date, Ozone) # 同时删除Ozone缺失值,避免模型报错 # 使用循环B样条构建模型(df=4控制复杂度,可根据需求调整) Mod_cyclic_spline = glmmTMB(Ozone ~ bs(JulianDay, bs="cc", df=4), data = airquality, family = poisson) # 预测完整JulianDay序列的结果 pred_spline = ggpredict(Mod_cyclic_spline, terms = "JulianDay [all]") # 绘图 ggplot(pred_spline, aes(x, predicted)) + geom_line(color="blue") + labs(x="Julian Day", y="Predicted Ozone")
方法2:手动构建sin/cos的非线性项
如果坚持手动用sin/cos编码循环变量,需要同时纳入它们的一次、二次项以及交互项,来捕捉二维平面上的非线性趋势;且预测时必须基于真实存在的sin/cos组合(从完整JulianDay序列生成对应的值):
# 重新构建循环变量 airquality$Date_cos = cos(airquality$JulianDay*(2*pi/365)) airquality$Date_sin = sin(airquality$JulianDay*(2*pi/365)) # 构建包含非线性项的模型:一次项+二次项+交互项 Mod_cyclic_poly = glmmTMB(Ozone ~ Date_cos + Date_sin + I(Date_cos^2) + I(Date_sin^2) + Date_cos:Date_sin, data = airquality, family = poisson) # 生成完整的JulianDay序列(1-365),计算对应的sin/cos new_data = tibble(JulianDay = 1:365) %>% mutate(Date_cos = cos(JulianDay*(2*pi/365)), Date_sin = sin(JulianDay*(2*pi/365))) # 预测并整合结果 pred_poly = predict(Mod_cyclic_poly, newdata = new_data, type = "response") new_data$predicted = pred_poly # 绘图 ggplot(new_data, aes(JulianDay, predicted)) + geom_line(color="red") + labs(x="Julian Day", y="Predicted Ozone")
结果说明
- 循环样条方法(方法1):代码简洁,自动处理循环边界(1月1日和12月31日的效应连续),调整
df参数即可控制非线性复杂度。 - 手动sin/cos方法(方法2):更灵活,适合需要自定义非线性结构的场景,但需确保纳入足够的项(二次项+交互项)来捕捉趋势。
两种方法的预测结果都会呈现合理的循环非线性趋势,不会出现你之前的混乱情况。
内容的提问来源于stack exchange,提问作者Charlotte R
相关产品推荐
相关产品推荐

