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

时间:2014-05-12 22:46:00

标签: r regression gam mgcv

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

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

其中fghmgcv

中的循环平滑函数
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'),但引入了太多的自由度,因为模型会在短时间内在特定的工作日内过度假期。

是否可以按照我想要的方式指定模型?

3 个答案:

答案 0 :(得分:5)

哇,这是一个很老的问题!

关于互动

  

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

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

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

如果这不是你所希望的,那么你期望"产品"成为?两个边缘设计矩阵的Hadamard积?那是什么意思呢?顺便说一下,Hadamard产品需要两个相同尺寸的矩阵。但是,您的两个边距的列数不同。

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

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

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

如果你有5个级别的因子g1和10个级别的另一个因子g2,他们的边缘设计矩阵(在对比之后)有4列和9列,那么交互{{1将有36列。这样的设计矩阵,只是g1:g2g1设计矩阵的行式Kronecker积。

关于过度拟合

正如你所说,你只有几年的数据,可能是2或3?在这种情况下,使用g2 k = 52对您的模型进行了过度参数化。尝试将其缩小为例如day_in_year

如果过度拟合仍然明显,可以采用以下几种方法解决它。

方式1:您正在使用GCV进行平滑度选择。试试k = 30。 GCV总是倾向于过度填充数据。

方式2:坚持使用GCV,手动夸大平滑参数以获得更严重的惩罚。 method = "REML"的{​​{1}}参数在此处很有用。例如,尝试gamma

代码中的拼写错误?

结点位置,应该是gam吗?

答案 1 :(得分:5)

当你声明存在:

时,你的模型没有多大意义
  1. 季节性影响,
  2. 一周的影响,
  3. 一种互动,使得星期效应随着一年中的某一天而变化
  4. 这可以完全表现为张量积平滑的产品。你在其他答案的评论中提到的模型

      

    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)
    

    您可以调整k的值,以确定与您的数据和gam.check()一起使用的合适值。

    您还需要在模型中添加一个术语来处理假期。这将是参数术语,如果日期是假日,则应用调整 - 因此,创建因子holiday并将其添加到模型+ holiday。你可以想到更复杂的模型;也许是一个因素索引,如果一周假期加上day_of_week组件的平滑因子,那么如果周是正常周,则估计一周模式,如果一周包含假日,则估计第二周模式

    如果您向我们展示我可以扩展或评论较少的数据的示例/情节。

    令人惊讶的是,te()顺利安装并不能很好地适应假期;该模型假设周效应平稳且平滑,随着年复一年的平稳效应而变化。假期不是前一周或后一周的每周模式的顺利离开。 假期效果不能通过平滑的关系很好地建模,而其他东西需要考虑到这种效果。

答案 2 :(得分:0)

我的问题现在已经有两年了,我想添加一个对我来说最有效的解决方案。

首先,无法使用我的问题使用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个字词。