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

R 在mgcv gam模型中是否可能包含两个平滑项的乘积,r,regression,gam,mgcv,R,Regression,Gam,Mgcv,我使用gam对时间序列数据的季节性建模取得了巨大成功。我的最新模型清楚地显示了除了季节变化之外的每周模式。虽然周模式本身在一年中非常稳定,但其振幅也随季节而变化。因此,理想情况下,我希望将我的数据建模为: y ~ f(day in year) + g(day in year) * h(day in week) 其中f,g和h是mgcv gam( y ~ s(day_in_year, k=52, bs='cc') + s(day_in_year, k=52, bs='cc'):s(da

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

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

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参数
。我尝试使用
te(一年中的一天,一周中的一天,k=c(52,5),bs='cc')
来工作,但引入了太多的自由度,因为该模型超出了在可用年数不多的特定工作日的假期


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

哇,这是一个很老的问题

关于互动 虽然周模式本身在一年中非常稳定,但其振幅也随季节而变化

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

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

如果这不是你所希望的,那么你期望“产品”是什么?两个边际设计矩阵的哈达玛积?那是什么意思?顺便说一下,一个阿达玛积需要两个相同维数的矩阵。但是,两个页边距的列数不同

如果你不明白我为什么一直在谈论矩阵,那么你需要阅读西蒙2006年的书。尽管GAM估算说明现在已经相当过时,但第4章中解释的GAM(如设计矩阵和惩罚矩阵)的构造/设置即使十年后也没有任何变化

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

平滑项
s(x)
非常类似于因子变量
g
,虽然它们看起来是一个单一变量,但它们被构造成一个具有许多列的设计矩阵。对于
g
它是一个伪矩阵,而对于
f(x)
它是一个基矩阵因此,两个平滑函数之间的交互作用的构造方式与两个因子之间的交互作用的构造方式相同。

如果您有一个5级的系数
g1
,另一个10级的系数
g2
,它们的边际设计矩阵(对比后)有4列和9列,那么交互
g1:g2
将有36列。这样的设计矩阵,只是
g1
g2
设计矩阵的行克罗内克积


关于过度装配 正如你所说,你只有几年的数据,也许2年或3年?在这种情况下,您的模型已经过参数化,使用了
k=52
表示一年中的
day
。尝试将其减少到例如
k=30

如果过度装配仍然很明显,这里有一些解决方法

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

方式2:保持GCV,手动增加平滑参数以加重处罚<这里,
gam
的参数code>gama很有用。例如,尝试
gamma=1.5


你的代码有误吗?
结的位置,应该是
day\u in\u year=c(0365)

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

  • 季节效应
  • 一周中的一天效应
  • 一种交互作用,使得一周中的某一天效果随一年中的某一天而变化
  • 这可以完全表示为张量积平滑。你在对另一个答案的评论中提到的模型

    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)
    
    您可以调整
    k
    的值,结合数据和
    gam.check()
    确定合适的值

    您还需要向模型中添加一个术语来处理假期。这将是一个参数术语,如果一天是假日,它将应用调整-因此,创建一个系数
    假日
    ,并将其添加到模型
    +假日
    。你可以想出更复杂的模型;如果一周有一个假期,那么可能需要一个系数索引,同时为
    周中的第二天
    组件提供一个按系数平滑,这样,如果一周是正常的一周,您可以估计一个每周模式,如果一周包含假期,则可以估计第二个每周模式

    如果你给我们看一个数据的例子/图,我可以展开或不那么笼统地评论

    你穿的光滑的
    te()
    不太适应假期,这并不奇怪;该模型假设
    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)
    
    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
    )
    
    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
    )