基于mgcv的多维分类响应变量GAM模型构建问询
我尝试用mgcv包拟合一个包含多维分类响应变量的GAM模型,该响应变量由三个二项维度(如A-B、a-b、α-β)组合而成,且部分组合缺失,模型依赖经度和纬度的平滑项。想请教:是否存在合适的分布族或语法,能在单个模型中预测预测变量对响应变量各维度的影响?还是必须对每个维度单独建模?
样本数据
library(dplyr) df <- data.frame(response.dim1 = sample(c("A", "B"), 1000, replace=TRUE), response.dim2 = sample(c("a", "b"), 1000, replace=TRUE), response.dim3 = sample(c("", "α", "β"), 1000, replace=TRUE), longitude = runif(1000, min = 0, max = 100), latitude = runif(1000, min = 50, max = 150)) df$response.comb <- paste(df$response.dim1, df$response.dim2, df$response.dim3, sep = "") df <- df %>% filter(response.comb %in% c("Aa", "Abα", "Abβ", "Bbα", "Bbβ"))
我希望构建类似gam(response.dim1 * response.dim2+3 ~ s(longitude, latitude))的可用模型。或者,是否可通过gam(response.comb ~ s(longitude, latitude))计算响应维度1和2的交互效应?
1. 单个模型拟合多维响应的可行方案
不需要对每个维度单独建模,有两种主流方式在单个GAM中处理这类问题:
(1)多项分布族(multinom)
直接把response.comb作为多分类响应变量,用multinom分布族拟合,模型会估计每个类别相对于参考类的空间平滑效应:
library(mgcv) # 拟合多分类GAM model_comb <- gam(response.comb ~ s(longitude, latitude), data = df, family = multinom)
后续可以用predict(model_comb, type = "response")得到每个组合类别在空间上的预测概率,再通过类别间的对比推导各维度的效应:比如对比Abα和Abβ的概率差异,就能得到维度3(α-β)的空间效应;对比Abα和Bbα的差异,就能得到维度1(A-B)的效应。
(2)联合建模(多响应公式)
mgcv支持通过cbind()绑定多个响应维度,拟合联合GAM,可共享或独立设置平滑项:
# 先把响应维度转成二项式数值型(0/1),注意空值对应维度3的β df$dim1_num <- as.numeric(df$response.dim1 == "A") df$dim2_num <- as.numeric(df$response.dim2 == "a") df$dim3_num <- as.numeric(df$response.dim3 == "α") # 拟合联合二项GAM,共享空间平滑项 model_joint <- gam(cbind(dim1_num, dim2_num, dim3_num) ~ s(longitude, latitude), data = df, family = binomial)
这种方式能直接得到每个维度的空间平滑效应,模型会同时估计三个维度的参数,效率更高,还能捕捉维度间的潜在关联。
2. 关于交互效应的计算
- 仅用
response.comb ~ s(longitude, latitude)的多分类模型,无法直接得到维度1和2的交互效应,因为模型是针对每个组合类别建模的。要单独估计维度1×2的交互,需要在公式中显式加入交互项:
model_interaction <- gam(response.comb ~ response.dim1 * response.dim2 + s(longitude, latitude), data = df, family = multinom)
该模型会同时估计维度1、维度2的主效应、二者的交互效应,再加上空间平滑项。
- 用联合建模方式时,可针对不同维度指定包含交互的平滑项,或单独加入维度交互的参数项,灵活度更高。
3. 缺失组合的处理
mgcv的multinom分布族会自动忽略数据中不存在的响应类别,不需要额外处理——模型只会针对实际存在的5个组合类别进行估计,参考类默认是数据中第一个出现的类别(示例中为"Aa")。
内容的提问来源于stack exchange,提问作者David

