knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
fibre
is a minimal package for modelling traits along phylogenies using the INLA
package. We will demonstrate how it works by fitting a model on some simulated data. Let's simulate a simple univariate continuous character that has two distinct rates of evolution on the tree. We first simulate a two-state discrete characater evolving on the tree, then evolve a continuous traits with rates determined by this character. The following code is taken directly from this chapter of Luk J. Harmon's online book (link).
library(fibre) library(phytools) library(RRphylo) library(dplyr) set.seed(230045) ## transition matrix for the discrete trait simulation Q <- matrix(c(-1, 1, 1, -1), 2, 2) ## simulated tree tree <- pbtree(n = 100, scale = 1, d = 0.2) rates <- setNames(c(1, 20), 1:2) x <- simulate_traits(tree, rate_model = "discrete", temp_trend_rates = 0, rate_change = Q, rates = rates, internal = TRUE) # test <- simulate_traits(tree, rate_model = "continuous", temp_trend = -0.5, # rate_change = 1, internal = TRUE, anc = c(0, 1), # nsim = 1, log_rates = TRUE) # contMap(tree, test[1:length(tree$tip.label)], anc.states = test[(length(tree$tip.label) + 1L):length(test)], method = "user")
Okay, let's fit the most basic model in fibre
and compare it to what we get with RRphylo
. As a first step, it is always a good idea to standardise the response variable to improve convergence and comparability.
x <- scale(x) %>% apply(1, function(x) x) ## that last bit converts scaled matrix back to vector aces_true <- x[(length(tree$tip.label) + 1L):length(x)] x <- x[1:length(tree$tip.label)] contMap(tree, x[1:length(tree$tip.label)], anc.states = aces_true, method = "user") inla_fit <- fibre(phy = tree, data = x, obs_error = 1, verbose = FALSE) summary(inla_fit)
Now for RRphylo
:
RR_fit <- RRphylo(tree, x) n_node <- length(tree$tip.label) + tree$Nnode plot(cbind(RR_fit$rates[-1], get_rates(inla_fit, "mode")))
Let's try fixing the lambda parameter to what RRphylo
chose.
inla_fit2 <- fibre(phy = tree, data = x, obs_error = "one", hyper = RR_fit$lambda, verbose = FALSE) summary(inla_fit2) plot(cbind(RR_fit$rates[-1], get_rates(inla_fit2, "mode"))) abline(0, 1) inla_fit2 <- fibre(phy = tree, data = x, obs_error = "est", hyper = RR_fit$lambda, verbose = FALSE) summary(inla_fit2) plot(cbind(RR_fit$rates[-1], get_rates(inla_fit2, "mode"))) abline(0, 1)
inla_fit3 <- fibre(phy = tree, data = x, obs_error = "est", verbose = FALSE) summary(inla_fit3) plot(cbind(RR_fit$rates[-1], get_rates(inla_fit3, "mode")))
aces_preds <- get_aces(inla_fit3, "mode") plot(aces_true, aces_preds) plot(aces_true, RR_fit$aces[ , 1])
tip_preds <- get_tips(inla_fit3, "mode") plot(x, tip_preds) plot(x, RR_fit$predicted.phenotype[ , 1]) names(tip_preds) <- names(x) names(aces_preds) <- names(aces_true) contMap(tree, x[1:length(tree$tip.label)], anc.states = aces_true, method = "user") contMap(tree, tip_preds, anc.states = aces_preds, method = "user") contMap(tree, RR_fit$predicted.phenotype %>% apply(1, function(x) x), anc.states = RR_fit$aces %>% apply(1, function(x) x), method = "user")
aces_sd <- get_aces(inla_fit3, "sd") tip_sd <- get_tips(inla_fit3, "sd") names(tip_sd) <- names(x) names(aces_sd) <- names(aces_true) contMap(tree, tip_sd, anc.states = aces_sd, method = "user")
get_rate_var <- function(RR_fit) { betas <- RR_fit$rates L <- RR_fit$tip.path t <- RR_fit$tree Rvar <- array() for (i in 1:Ntip(t)) { ace.tip <- betas[match(names(which(L[i, ] != 0)), rownames(betas)), ] mat = as.matrix(dist(ace.tip)) Rvar[i] <- sum(mat[row(mat) == col(mat) + 1]) } var(Rvar) } get_rate_var(RR_fit)
tree_long <- tree tree_long$edge.length <- tree_long$edge.length * 111 RR_fit_long <- RRphylo(tree_long, x) contMap(tree, x[1:length(tree$tip.label)], anc.states = aces_true, method = "user") contMap(tree, RR_fit_long$predicted.phenotype %>% apply(1, function(x) x), anc.states = RR_fit_long$aces %>% apply(1, function(x) x), method = "user") RR_fit_long$lambda get_rate_var(RR_fit_long)
Q <- matrix(c(-1, 1, 1, -1), 2, 2) ## simulated tree tree <- pbtree(n = 100, scale = 1) ## simulate discrete character history tree <- sim.history(tree, Q, anc = "1") ## plot discrete character history on the tree plotSimmap(tree, setNames(c("blue", "red"), 1:2), pts = F) x <- sim.rates(tree, setNames(c(20, 1), 1:2), internal = TRUE) tree$edge.length <- tree$edge.length * 200 x <- scale(x) %>% apply(1, function(x) x) ## that last bit converts scaled matrix back to vector aces_true <- x[(length(tree$tip.label) + 1L):length(x)] x <- x[1:length(tree$tip.label)] contMap(tree, x[1:length(tree$tip.label)], anc.states = aces_true, method = "user") inla_fit_o <- fibre(phy = tree, data = x, obs_error = "est", verbose = FALSE) summary(inla_fit_o) RR_fit_o <- RRphylo(tree, x) plot(cbind(RR_fit_o$rates[-1], inla_fit_o$summary.fitted.values$mode[200:397])) ace_ind <- INLA::inla.stack.index(attr(inla_fit_o, "stack"), "aces")$data ace_preds <- inla_fit_o$summary.fitted.values$mode[ace_ind] plot(aces_true, ace_preds) plot(aces_true, RR_fit_o$aces[ , 1]) tip_ind <- 1:length(tree$tip.label) tip_preds <- inla_fit_o$summary.fitted.values$mode[tip_ind] plot(x, tip_preds) plot(x, RR_fit_o$predicted.phenotype[ , 1]) names(tip_preds) <- names(x) names(ace_preds) <- names(aces_true) contMap(tree, x[1:length(tree$tip.label)], anc.states = aces_true, method = "user") contMap(tree, tip_preds, anc.states = ace_preds, method = "user") contMap(tree, RR_fit_o$predicted.phenotype %>% apply(1, function(x) x), anc.states = RR_fit_o$aces %>% apply(1, function(x) x), method = "user")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.