library(ape)
library(phytools)
library(geomorph)
library(mvMORPH)Roteiro prático — Atributos multivariados
Aula 8 · Métodos Filogenéticos Comparativos
0. Pacotes e dados
Duas fontes do geomorph: 40 exemplares de duas espécies de Plethodon (12 marcos na cabeça) e as médias de 9 espécies, com a árvore.
data(plethodon, plethspecies)
dim(plethodon$land) # marcos × coordenadas × exemplares[1] 12 2 40
plethspecies$phy
Phylogenetic tree with 9 tips and 8 internal nodes.
Tip labels:
P_serratus, P_cinereus, P_shenandoah, P_hoffmani, P_virginia, P_nettingi, ...
Rooted; includes branch length(s).
1. Superposição de Procrustes, passo a passo
Translação, escala e rotação, à mão, para dois exemplares:
A <- plethodon$land[, , 1]; B <- plethodon$land[, , 30]
centrar <- function(M) sweep(M, 2, colMeans(M))
tamanho <- function(M) sqrt(sum(centrar(M)^2)) # tamanho do centroide
A1 <- centrar(A) / tamanho(A); B1 <- centrar(B) / tamanho(B)
s <- svd(t(A1) %*% B1); R <- s$v %*% t(s$u) # rotação de mínimos quadrados
B2 <- B1 %*% R
c(tamanho_A = tamanho(A), tamanho_B = tamanho(B), distancia_procrustes = sqrt(sum((A1 - B2)^2))) tamanho_A tamanho_B distancia_procrustes
15.2269199 14.6630464 0.1025589
par(mfrow = c(1, 2))
plot(rbind(A, B), type = "n", asp = 1, main = "brutos", xlab = "", ylab = "")
points(A, pch = 19, col = "steelblue"); points(B, pch = 19, col = "firebrick")
plot(rbind(A1, B2), type = "n", asp = 1, main = "superpostos", xlab = "", ylab = "")
points(A1, pch = 19, col = "steelblue"); points(B2, pch = 19, col = "firebrick")
O gpagen() faz a superposição generalizada (GPA) de todos os exemplares de uma vez, em relação ao consenso:
gpa <- gpagen(plethodon$land, print.progress = FALSE)
plotAllSpecimens(gpa$coords, links = plethodon$links)
2. O morfoespaço
pca <- gm.prcomp(gpa$coords)
round(pca$d / sum(pca$d), 3)[1:4] # proporção da variância nos 4 primeiros eixosComp1 Comp2 Comp3 Comp4
0.367 0.310 0.082 0.045
grupo <- interaction(plethodon$species, plethodon$site)
plot(pca$x[, 1:2], pch = 19, col = as.integer(grupo), asp = 1)
legend("topright", legend = levels(grupo), pch = 19, col = seq_along(levels(grupo)), bty = "n")
3. Sinal e PGLS multivariados
Agora as 9 espécies, com a árvore. O K multivariado (Adams 2014) e o PGLS da forma contra o tamanho (alometria), ambos com permutação:
gpa_sp <- gpagen(plethspecies$land, print.progress = FALSE)
arv <- plethspecies$phy
set.seed(801)
k <- physignal(gpa_sp$coords, arv, iter = 999, print.progress = FALSE)
c(K_mult = k$phy.signal, p = k$pvalue) K_mult p
0.9572991 0.0080000
gdf <- geomorph.data.frame(gpa_sp, phy = arv)
set.seed(804)
alo <- procD.pgls(coords ~ log(Csize), phy = phy, data = gdf, iter = 999, print.progress = FALSE)
summary(alo)$table Df SS MS Rsq F Z Pr(>F)
log(Csize) 1 0.00006868 6.8679e-05 0.15096 1.2446 0.55145 0.277
Residuals 7 0.00038627 5.5182e-05 0.84904
Total 8 0.00045495
Com 9 espécies, nenhuma relação detectável entre forma e tamanho.
O filomorfoespaço da forma, e a PCA filogenética (os eixos estimados com a matriz C, opção GLS = TRUE):
pca_comum <- gm.prcomp(gpa_sp$coords, phy = arv)
pca_filo <- gm.prcomp(gpa_sp$coords, phy = arv, GLS = TRUE)
par(mfrow = c(1, 2))
plot(pca_comum, phylo = TRUE, main = "PCA comum + árvore")
plot(pca_filo, phylo = TRUE, main = "PCA filogenética")
4. Modelos multivariados com verossimilhança penalizada
São 22 coordenadas para 9 espécies: mais variáveis que espécies. A verossimilhança comum não funciona; a penalizada (mvgls) sim, e os modelos se comparam pelo GIC.
Y <- two.d.array(gpa_sp$coords)[arv$tip.label, ]
dim(Y)[1] 9 22
ajustes <- lapply(c(BM = "BM", OU = "OU", EB = "EB"), \(m)
mvgls(Y ~ 1, tree = arv, model = m, method = "PL-LOOCV"))
sapply(ajustes, \(f) GIC(f)$GIC) BM OU EB
-1479.052 -1477.052 -1478.616
Os três ficam praticamente empatados: com 9 espécies, não há base para ir além do BM.
5. Uma matriz de taxas por regime
Com poucos atributos, o mvBM() compara uma matriz de taxas com uma por regime mapeado na árvore. Nos Anolis, SVL e cauda (já em log natural), com os ecomorfos:
data(anoletree, anole.data)
X <- as.matrix(anole.data[anoletree$tip.label, c("SVL", "TL")])
um <- mvBM(anoletree, X, model = "BM1", echo = FALSE, diagnostic = FALSE)
cada <- mvBM(anoletree, X, model = "BMM", echo = FALSE, diagnostic = FALSE)
c(BM1 = um$AICc, BMM = cada$AICc) BM1 BMM
-55.51964 -142.28052
round(cada$sigma[, , "TG"], 4) # a matriz de taxas dos trunk-ground SVL TL
SVL 0.0066 0.0083
TL 0.0083 0.0127
As restrições do slide (proporcional, autovetores compartilhados…) entram pelo argumento param:
prop <- mvBM(anoletree, X, model = "BMM", param = list(constraint = "proportional"),
echo = FALSE, diagnostic = FALSE)
c(livre = cada$AICc, proporcional = prop$AICc) livre proporcional
-142.28052 -93.03756
6. Modularidade e integração
Uma hipótese de dois módulos na cabeça das salamandras (marcos 1–5 × 6–12, a partição de exemplo do geomorph):
modulos <- rep(c("A", "B"), c(5, 7))
set.seed(802)
mt <- modularity.test(gpa$coords, modulos, CI = FALSE, iter = 999, print.progress = FALSE)
c(CR = mt$CR, p = mt$P.value) CR p
1.187625 0.709000
set.seed(805)
it <- integration.test(gpa$coords, partition.gp = modulos, iter = 999, print.progress = FALSE)
c(r_PLS = it$r.pls, p = it$P.value) r_PLS p
0.9108698 0.0010000
CR perto de 1 e p alto: sem sinal de modularidade; o PLS mostra integração forte entre as duas partes. As taxas de evolução de cada módulo, nas 9 espécies (11 marcos):
set.seed(803)
taxas <- compare.multi.evol.rates(gpa_sp$coords, gp = rep(c("A", "B"), c(5, 6)),
phy = arv, iter = 999, print.progress = FALSE)
c(razao = taxas$sigma.d.ratio, p = taxas$P.value) razao p
1.299746 0.470000
Resumo
gpagen()separa forma de tamanho;gm.prcomp()faz o morfoespaço (comum ou filogenético).physignal()eprocD.pgls()são o K e o PGLS para dados de alta dimensão.- Com mais variáveis que espécies,
mvgls()com verossimilhança penalizada; com poucos atributos,mvBM()com uma matriz de taxas por regime. modularity.test(),integration.test()ecompare.multi.evol.rates()para módulos.