广义线性混合模型(GLMM)

知识背景

广义线性混合模型可以看做是广义线性模型(GLM)以及线性混合模型(LMM)的扩展,为了更好地理解GLMM,肯定要对普通线性模型、广义线性模型以及线性混合模型有个理解。

  • 普通线性模型长大概这个样子(以只有一个因变量举例):
    y = \beta_0 +\beta_1 * x + ε
    Y=\mathbf X\beta + ε
    也就是固定效应+随机误差,且因变量必须要满足正态性、独立性以及方差齐性

  • 广义线性模型(GLM)可以长这个样子:
    log(\frac{P(y=1)}{1-P(y=1)})=\beta_0 + \beta_1 * x_1+ ε
    也可以长这个样子:log(y) = \beta_0 + \beta_1 * x_1+ ε...
    也就是对因变量y进行了变换,使得变换后的值适用普通线性回归。而GLM之所以称为“广义”,关键就在于这种变换——连接函数(就是上边两个等式左边那一堆),使得模型的应用范围变得更宽,只要因变量服从指数分布就行

  • 而线性混合模型(LMM)则形如(以矩阵形式表示):
    Y = \mathbf X\beta + \mathbf Z \gamma + ε

相较普通线性模型,LMM其实就是多了随机效应\mathbf Z \gamma而已。

如何划分固定效应和随机效应?
(1)固定效应的因子水平明确,在抽样数据集中包含其所有类别,通常是在实验中加以控制的因素,例如组别。
(2)随机效应的因子水平不清晰,在抽样数据集中并不包含该自变量的所有情况,通常是实验中无法控制的因素,例如个体。

换句话说,以固定方式对因变量产生影响的因素为固定效应,相反,则为随机效应。

  • 广义线性混合模型

至此,GLMM应该就好理解了,其实就是在等式左侧对因变量进行变换,在等式右侧将固定效应与随机效应进行结合。但公式写起来蛮复杂,我就不列出来了。

示例

光说不练假把式,下面我们以纵向研究的宏基因组数据(分实验组和对照组,且每一个个体在3个时间点采样)为例来说明GLMM的具体应用:

假设你已经获得了物种丰度结果taxa.raw,形如:

WX20201110-151431.png

以及样本的各种信息sample.info,形如:

WX20201110-151645.png
  • 步骤1:多滤掉低丰度数据
#过滤掉物种丰度为0的样本数过多的行
> filter.index <- apply(taxa.raw, 1, function(X){sum(X>0)>0.1*length(X)})
> taxa.filter <- taxa.raw[filter.index, ]
#确保样本丰度和相加为100
> taxa.filter <- 100*sweep(taxa.filter, 2, colSums(taxa.filter), FUN="/")
> taxa.data <- as.data.frame(t(taxa.filter))
  • 步骤2:创建协变量矩阵

我们可以用如下代码为grouptime以及grouptime的交互项创建协变量矩阵:

> reg.cov <- tibble::rownames_to_column(sample.info, var = 'Sample') %>% 
           dplyr::select(Sample, group, indID, time) %>% 
           dplyr::mutate(time = ifelse(time == 'w0', 0, ifelse(time == 'w2', 1, ifelse(time == 'w4', 2,NA)))) %>%  #创建时间变量代码:w0是0,w2是1,w4是2;
           dplyr::mutate(group = ifelse(group == 'ck', 0, 1)) %>%  #创建分组变量代码:ck组为0,A组为1
           dplyr::mutate(timeXgroup = time*group) %>%   #创建时间与分组交互代码
           dplyr::mutate(indID = as.character(indID)) %>% 
           as.data.frame
#过滤掉采样不全的个体数据
> ind.count <- table(reg.cov$indID)
> reg.cov <- subset(reg.cov, indID %in% names(ind.count)[ind.count == 3])

> head(reg.cov)
  Sample group indID time timeXgroup
1   FN3T     1  A2-1    1          1
2   FN40     0  D2-4    0          0
3   FN42     1  A1-4    1          1
4   FN44     1  A1-5    0          0
5   FN45     1  A2-3    1          1
7   FN49     0  D2-2    1          0

  • 步骤3:拟合模型

先将w0和w1+w2的数据分别取出备用:

> reg.cov.w0 <- subset(reg.cov, time == 0)
> rownames(reg.cov.w0) <- reg.cov.w0$indID
> head(reg.cov.w0)
     Sample group indID time timeXgroup
D2-4   FN40     0  D2-4    0          0
A1-5   FN44     1  A1-5    0          0
D2-5   FN4D     0  D2-5    0          0
D1-2   FN54     0  D1-2    0          0
A1-4   FN5J     1  A1-4    0          0
A2-4   FN60     1  A2-4    0          0

> reg.cov.w12 <- subset(reg.cov, time != 0)
> reg.cov.w12 <- na.omit(data.frame(baseline.sample = reg.cov.w0[reg.cov.w12$indID, 'Sample'],
                 baseline.subject = reg.cov.w0[reg.cov.w12$indID, 'indID'],
                 reg.cov.w12,
                 stringsAsFactors = F))
> head(reg.cov.w12)
  baseline.sample baseline.subject Sample group indID time timeXgroup
1            FN70             A2-1   FN3T     1  A2-1    1          1
3            FN5J             A1-4   FN42     1  A1-4    1          1
5            FN68             A2-3   FN45     1  A2-3    1          1
7            FN71             D2-2   FN49     0  D2-2    1          0
8            FN54             D1-2   FN4A     0  D1-2    2          0
9            FN6T             D1-5   FN4B     0  D1-5    1          0

然后单独为每一个物种进行拟合(为了便于说明,此处我们仅以其中一个物种丰度举例:

library(dplyr)
library(nlme)

> taxa.all <- colnames(taxa.data)
> p.taxa.list.lme <- list()
> spe <- taxa.all[9]
> spe
[1] "s__Bacteroides_vulgatus"

> X <- data.frame(Baseline = taxa.data[reg.cov.w12$baseline.sample, spe]/100,
                  reg.cov.w12[, c('time', 'group')])
> rownames(X) <- reg.cov.w12$Sample
> head(X)
         Baseline time group
FN3T 0.0004122127    1     1
FN42 0.0001939168    1     1
FN45 0.0026208886    1     1
FN49 0.0003091166    1     0
FN4A 0.0007188949    2     0
FN4B 0.0005986076    1     0

> Z <- X
> subject.ind <- reg.cov.w12$indID
> time.ind <- reg.cov.w12$time
> Y <- taxa.data[reg.cov.w12$Sample, spe]/100
> cat('Zeros/All',sum(Y==0),'/',length(Y),'\n')
Zeros/All 0 / 30 

#对Y进行变换(先开方在反正弦?)
> tdata <- data.frame(Y.tran = asin(sqrt(Y)), X, SID = subject.ind)
> head(tdata)
         Y.tran     Baseline time group  SID
FN3T 0.04531814 0.0004122127    1     1 A2-1
FN42 0.05269246 0.0001939168    1     1 A1-4
FN45 0.01527299 0.0026208886    1     1 A2-3
FN49 0.02599619 0.0003091166    1     0 D2-2
FN4A 0.01817293 0.0007188949    2     0 D1-2
FN4B 0.03147346 0.0005986076    1     0 D1-5
#进行拟合(以Baseline、time以及group为固定效应,以SID为随机效应)
> lme.fit <- try(lme(Y.tran ~ Baseline + time + group, random = ~1|SID, data = tdata))

随机效应的表达方式:
(1)1|SIDSID是随机截距,Baselinetimegroup是固定斜率,也就是他们前面的参数是固定的;
(2)0 + time|SIDSID是固定截距,time是随机斜率,Baselinetime是固定斜率;
(3)1 + time|SIDSID是随机截距,time是随机斜率,Baselinetime是固定斜率;

> summary(lme.fit)
...
Random effects:
 Formula: ~1 | SID
        (Intercept)    Residual
StdDev: 0.007468231 0.009009141

Fixed effects: Y.tran ~ Baseline + time + group 
                 Value Std.Error DF   t-value p-value
(Intercept)  0.0236327 0.0060813 14  3.886108  0.0016
Baseline    -1.2738533 1.3537572 12 -0.940976  0.3653
time         0.0023881 0.0032897 14  0.725932  0.4798
group        0.0016992 0.0053765 12  0.316037  0.7574
...

这样我们就得到了每个自变量的参数,以及P值,后续我们再使用多重检验矫正就可以得到矫正后的P值了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容