]> git.donarmstrong.com Git - ape.git/blob - R/yule.R
a few bug fixes especially in plot.phylo()
[ape.git] / R / yule.R
1 ## yule.R (2009-06-08)
2
3 ##     Fits Yule Model to a Phylogenetic Tree
4
5 ## yule: standard Yule model (constant birth rate)
6 ## yule.cov: Yule model with covariates
7
8 ## Copyright 2003-2009 Emmanuel Paradis
9
10 ## This file is part of the R-package `ape'.
11 ## See the file ../COPYING for licensing issues.
12
13 yule <- function(phy, use.root.edge = FALSE)
14 {
15     if (!is.binary.tree(phy))
16       stop("tree must be dichotomous to fit the Yule model.")
17     bt <- rev(sort(branching.times(phy))) # branching times from past to present
18     ni <- cumsum(rev(table(bt))) + 1
19     X <- sum(phy$edge.length)
20     nb.node <- phy$Nnode
21     if (!is.null(phy$root.edge) && use.root.edge) {
22         X <- X + phy$root.edge
23         ni <- c(1, ni)
24     } else nb.node <- nb.node - 1
25     lambda <- nb.node/X
26     se <- lambda/sqrt(nb.node)
27     loglik <- -lambda*X + lfactorial(phy$Nnode) + nb.node*log(lambda)
28     obj <- list(lambda = lambda, se = se, loglik = loglik)
29     class(obj) <- "yule"
30     obj
31 }
32
33 yule.cov <- function(phy, formula, data = NULL)
34 {
35     if (is.null(data)) data <- parent.frame()
36     n <- length(phy$tip.label)
37     nb.node <- phy$Nnode
38     if (!is.null(phy$node.label)) phy$node.label <- NULL
39     bt <- sort(branching.times(phy)) # branching times (from present to past)
40     bt <- rev(bt) # branching times from past to present
41     ni <- cumsum(rev(table(bt))) + 1
42     X <- model.matrix(formula, data)
43     Xi <- X[phy$edge[, 1], , drop = FALSE]
44     Xj <- X[phy$edge[, 2], , drop = FALSE]
45     dev <- function(b) {
46         2 * sum(((1/(1 + exp(-(Xi %*% b)))) +
47                  (1/(1 + exp(-(Xj %*% b)))))
48                 * phy$edge.length/2) -
49          2 * (sum(log(ni[-length(ni)])) +
50               sum(log((1/(1 + exp(-(X[-(1:(n + 1)), , drop = FALSE] %*% b)))))))
51     }
52     out <- nlm(function(p) dev(p), p = c(rep(0, ncol(X) - 1), -1),
53                hessian = TRUE)
54     Dev <- out$minimum
55     para <- matrix(NA, ncol(X), 2)
56     para[, 1] <- out$estimate
57     if (any(out$gradient == 0))
58       warning("The likelihood gradient seems flat in at least one dimension (null gradient):\ncannot compute the standard-errors of the parameters.\n")
59     else para[, 2] <- sqrt(diag(solve(out$hessian)))
60     rownames(para) <- colnames(X)
61     colnames(para) <- c("Estimate", "StdErr")
62     ## fit the intercept-only model:
63     X <- model.matrix(~ 1, data = data.frame(X))
64     Xi <- X[phy$edge[, 1], , drop = FALSE]
65     Xj <- X[phy$edge[, 2], , drop = FALSE]
66     Dev.null <- nlm(function(p) dev(p), p = -1)$minimum
67     cat("\n---- Yule Model with Covariates ----\n\n")
68     cat("    Phylogenetic tree:", deparse(substitute(phy)), "\n")
69     cat("       Number of tips:", n, "\n")
70     cat("      Number of nodes:", nb.node, "\n")
71     cat("             Deviance:", Dev, "\n")
72     cat("       Log-likelihood:", -Dev/2, "\n\n")
73     cat("  Parameter estimates:\n")
74     print(para)
75     cat("\n")
76     cat("Null Deviance:", Dev.null, "\n")
77     cat("  Test of the fitted model: ")
78     chi <- Dev.null - Dev
79     df <- nrow(para) - 1
80     cat("chi^2 =", round(chi, 3), "  df =", df,
81         "  P =", round(1 - pchisq(chi, df), 3), "\n")
82 }