繁体   English   中英

是否可以在 mgcv gam 模型中包含两个平滑项的乘积

[英]Is it possible to include the product of two smooth terms in a mgcv gam model

我使用 gam 对时间序列数据的季节性建模取得了巨大成功。 除了季节性变化之外,我的最新模型清楚地显示了每周模式。 虽然每周模式本身在一年中非常稳定,但其幅度也随季节变化。 所以理想情况下,我想将我的数据建模为:

y ~ f(day in year) + g(day in year) * h(day in week)

其中f , ghmgcv中的循环平滑函数

gam(
  y ~ s(day_in_year, k=52, bs='cc') 
  + s(day_in_year, k=52, bs='cc'):s(day_in_week, k=5, bs='cc')
  , knots=list(
    day_in_year=c(0, 356)
    , day_in_week=c(0,7)
  )
  , data = data
)

不幸的是,这不起作用并抛出错误NA/NaN argument 我尝试使用te(day_in_year, day_in_week, k=c(52, 5), bs='cc') ,它有效,但引入了太多的自由度,因为该模型过度拟合了假期,这些假期落在有限的可用工作日内年。

是否可以按照我尝试的方式指定模型?

哇,一个很老的问题!

关于互动

虽然每周模式本身在一年中非常稳定,但其幅度也随季节变化。

使用张量积样条基te是交互的正确方式,尽管更合适的构造函数是ti 你说te返回很多参数。 当然。 第一个边距为k = 52 ,第二个边距为k = 5 ,那么该张量项的系数为52 * 5 - 1 但这只是创建交互的方式。

请注意,在mgcv GAM 公式中, :*仅对参数项之间的交互有效。 平滑之间的交互由teti处理。

如果这不是您所希望的,那么您期望“产品”是什么? 两个边际设计矩阵的 Hadamard 乘积? 那么这有什么意义呢? 顺便说一下,Hadamard 乘积需要两个相同维度的矩阵。 但是,您的两个边距的列数不同。

如果你不明白为什么我一直在谈论矩阵,那么你需要阅读 Simon 在 2006 年的书。虽然 GAM 估计解释现在已经过时了,GAM 的构造/设置(如设计矩阵和惩罚矩阵)在章节中解释4 即使在十年之后也根本没有改变。

好的,让我再给你一个提示。 用于构建te / ti设计矩阵的行式 Kronecker 产品并不是一项新发明。

平滑项s(x)很像因子变量g ,就好像它们看起来是单个变量一样,它们被构造为具有许多列的设计矩阵。 对于g它是一个虚拟矩阵,而对于f(x)它是一个基矩阵。 因此,两个平滑函数之间的交互作用的构建方式与构建两个因素之间的交互作用的方式相同。

如果您的因子g1为 5 个水平,另一个因子g2为 10 个水平,它们的边际设计矩阵(对比后)有 4 列和 9 列,那么交互作用g1:g2将有 36 列。 这样的设计矩阵,就是g1g2的设计矩阵的行式 Kronecker 乘积。


关于过拟合

正如你所说,你只有几年的数据,也许是 2 或 3 年? 在这种情况下,您的模型已通过对day_in_year使用k = 52过度参数化。 尝试将其减少到例如k = 30

如果过度拟合仍然很明显,这里有一些方法可以解决它。

方式 1:您使用 GCV 进行平滑度选择。 尝试method = "REML" GCV 总是倾向于过度拟合数据。

方式 2:继续使用 GCV,手动增加平滑参数以获得更重的惩罚。 gam gamma参数在这里很有用。 例如,尝试gamma = 1.5


你的代码有错别字?

结的位置,应该是day_in_year = c(0, 365)吗?

您的模型没有多大意义,因为您声明有:

  1. 季节性影响,
  2. 一周的一天效果,
  3. 一种相互作用,使得一周中的某一天效应随着一年中的某一天而变化

这可以完全表示为平滑的张量积。 您在此处其他答案的评论中提到的模型

y ~ f(一年中的一天) + g(一年中的一天) * h(一周中的一天)

如果您的意思是*作为主要效应 + 交互作用,那么它只是完整张量积的分解。 在这种情况下,您拥有的模型无法识别-您两次获得一年中的某一天的函数。 如果您的意思是:的等价物,那么您的模型就没有星期几的主要影响,这似乎是不可取的。

我一直适合这种形式的模型(仅适用于一年中的每一天)。 我会通过以下方式解决这个问题:

gam(y ~ te(day_of_year, day_of_week, k = c(20, 6), bs = c("cc", "cc")),
    data = foo, method = "REML", knots = knots)

您还可以调整结定义。 我倾向于使用以下内容:

knots <- list(day_of_year = c(0.5, 366.5),
              day_of_week = c(0.5, 7.5)

这不会有太大区别,但您只是将边界结点放置在离数据更近一点的地方。

如果要分解效果,可以使用ti()平滑拟合模型

gam(y ~ ti(day_of_year, bs = "cc", k = 12) + ti(day_of_week, bs = "cc", k = 6) + 
      te(day_of_year, day_of_week, k = c(12, 6), bs = c("cc", "cc")),
    data = foo, method = "REML", knots = knots)

您可以结合数据和gam.check()调整k的值以确定合适的值。

您还需要向模型添加一个术语来处理假期。 这将是参数项,如果这一天是假日,则应用调整 - 因此,创建一个因子holiday并将其添加到模型+ holiday 你可以想到更复杂的模型; 如果一周有假期,则可能是一个因子索引,再加上day_of_week组件的因子平滑,这样您就可以在一周是正常周的情况下估计一个每周模式,如果该周包含假期,则估计第二个每周模式。

如果您向我们展示数据的示例/图,我可以不那么普遍地展开或评论。

您安装的te()平滑不能很好地适应假期也就不足为奇了; 该模型假设周效应是平滑的,并且随着一年中的一天效应的平滑变化。 假期不是从前一周或后一周的每周模式平稳偏离的。 假日效应并没有通过平滑的关系很好地建模,需要其他一些东西来解释这种效应。

我的问题现在已经有几年了,我想添加最终对我最有效的解决方案。

首先,不可能使用 mgcv 拟合我的问题中描述的模型。

有一段时间我使用了一个两阶段的过程。

model1 = gam(
  y ~ s(day_in_year, k=52, bs='cc') 
  + s(day_in_year, k=52, bs='cc')
  + as.factor(day_in_week)
  , knots=list(
    day_in_year=c(0, 366)
    , day_in_week=c(0,7)
  )
  , data = data
)
# get_weekday_offset gets the coefficients for each weekday and normalizes them to have mean 0
data$weekday_offset = get_weekday_offset(model1)[data$day_in_week]

model2 = gam(
  y ~ s(day_in_year, k=52, bs='cc') 
  + s(day_in_year, k=52, bs='cc')
  + s(day_in_year, k=52, bs='cc', by=weekday_offset)
  + as.factor(day_in_week)
  , knots=list(
    day_in_year=c(0, 366)
    , day_in_week=c(0,7)
  )
  , data = data
)

第二个模型的形式为"y ~ f(年中的天)+g(年中的天)*h(周中的天)",但 h 是一个固定函数,不适合第二个模型中的数据,而是基于最适合model1 这样做的明显缺点是 mgcv 需要运行两次,并且几乎所有第一次运行的信息(工作日的系数除外)都被丢弃。

我最终放弃这个模型的原因是除了振幅的变化之外,在一年的过程中,形状确实发生了一些变化,所以我最终确定了这个样子。

gam(
  y ~ s(day_in_year, k=52, bs='cc') 
  + s(day_in_year, k=10, bs='cc', by=as.factor(day_in_week)
  + as.factor(day_in_week)
  , knots=list(
    day_in_year=c(0, 366)
    , day_in_week=c(0,7)
  )
  , data = data
)

我删除了工作日的s ,因为我使用每周模式的最大自由度来证明数据是合理的,并且我添加了工作日和一年中的某一天之间的交互效果( s(day_in_year, k=12, bs='cc', by=as.factor(day_in_week) ),这估计了每个工作日的单独季节性曲线,但是因为它包含的自由度数远低于季节性项s(day_in_year, k=52, bs='cc') ,我没有遇到尝试te条款时遇到的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM