【问题标题】:Calculate sum of the total phylogenetic branch length from species birth-death table从物种生死表计算总系统发育分支长度的总和
【发布时间】:2019-11-14 09:50:33
【问题描述】:

背景

这个问题有点复杂,所以我先介绍一下背景。要生成物种出生-死亡表的示例(L 表),我建议使用 DDD 包中的 dd_sim() 函数。

library(DDD)
library(tidyverse)
library(picante)

result <- dd_sim(c(0.2, 0.1, 20), 10) 
# with birth rate 0.2, death rate 0.1, carrying capacity 20 and overall 10 million years.
L <- result$L

L

            [,1] [,2] [,3]       [,4]
 [1,] 10.0000000    0   -1 -1.0000000
 [2,] 10.0000000   -1    2  2.7058965
 [3,]  8.5908774    2    3  6.6301616
 [4,]  8.4786474    3    4  3.3866813
 [5,]  8.4455262   -1   -5 -1.0000000
 [6,]  8.3431071    4    6  3.5624756
 [7,]  5.3784683    2    7  0.6975934
 [8,]  3.8950593    6    8 -1.0000000
 [9,]  1.5032100   -5   -9 -1.0000000
[10,]  0.8393589    7   10 -1.0000000
[11,]  0.6118985   -5  -11 -1.0000000

L 表有 4 列:

  1. 第一列是一个物种在妙亚出生的时间
  2. 第二列是物种亲本的标签;正负值表示该物种属于左冠谱系还是右冠谱系
  3. 第三列是子物种本身的标签;正负值表示该物种属于左冠谱系还是右冠谱系
  4. 第四栏是物种灭绝的时间;如果 第四个元素等于-1,则该物种仍然存在。

我做了什么

有了这个 L 表,我现在有了一个现存的社区。我要计算它的系统发育多样性(也叫Faith's index)

使用DDDpicante 函数我可以做到:

# convert L table into community data matrix
comm = as.data.frame(L) %>% dplyr::select(V3:V4) %>%
dplyr::rename(id = V3, pa = V4) %>%
dplyr::mutate(id = paste0("t",abs(id))) %>%
dplyr::mutate(pa = dplyr::if_else(pa == -1, 1, 0)) %>%
dplyr::mutate(plot = 0) %>%
dplyr::select(plot, pa, id) %>%
picante::sample2matrix()

# convert L table into phylogeny
phy = DDD::L2phylo(L, dropextinct = T)

# calculate Faith's index using pd() function
Faith = picante::pd(comm,phy)

问题

虽然我达到了我的目标,但这个过程似乎是多余且耗时的。我必须来回转换我原来的 L 表,因为我必须使用现有的函数。

顾名思义,Faith的指数基本上是群落系统发育分支总长度的总和,所以我的问题是:

是否可以直接从 L 表中计算出 Faith 的指数?

提前谢谢!

【问题讨论】:

  • 你的意思是Faith &lt;- sum(L[,1]-pmax(0,L[,4]))?或者Faith &lt;- sum(L[L[,4]&lt;0,1])
  • @AndrewGustar 嗨,安德鲁,我都试过了,但在我的代码中,它们都不等于 Faith,可能是什么问题?
  • 我刚刚仔细看了看,我认为答案应该是sum(L[L[, 4] &lt; 0, 1]) + sum(pmax(0, L[, 4]))
  • 实际上这并不总是有效 - 不同的随机 Ls 适用于不同版本的公式 - 不知道为什么。也许最好坚持走很长的路!
  • @AndrewGustar 我想了一个下午,但我的代码变得越来越复杂,寻找一个有效的方法并不容易

标签: r bioinformatics phylogeny


【解决方案1】:

您可以简单地使用DDD::L2phylo生成的phylo对象的phy$edge.length组件:

## Measuring the sum of the branch lengths from `phy`
sum_br_length <- sum(phy$edge.length)
sum_br_length == Faith$PD
# [1] TRUE

## Measuring the sum of the branch length from `L`
sum_br_length <- sum(DDD::L2phylo(L, dropextinct = TRUE)$edge.length)
sum_br_length == Faith$PD
# [1] TRUE

还有一些有趣的微基准测试:

library(microbenchmark)
## Function 1
fun1 <- function(L) {
    comm = as.data.frame(L) %>% dplyr::select(V3:V4) %>%
    dplyr::rename(id = V3, pa = V4) %>%
    dplyr::mutate(id = paste0("t",abs(id))) %>%
    dplyr::mutate(pa = dplyr::if_else(pa == -1, 1, 0)) %>%
    dplyr::mutate(plot = 0) %>%
    dplyr::select(plot, pa, id) %>%
    picante::sample2matrix()

    # convert L table into phylogeny
    phy = DDD::L2phylo(L, dropextinct = T)

    # calculate Faith's index using pd() function
    Faith = picante::pd(comm,phy)
    return(Faith$PD)
}
## Function 2
fun2 <- function(L) {
    phy <- DDD::L2phylo(L, dropextinct = T)
    return(sum(phy$edge.length))
}
## Function 3
fun3 <- function(L) {
    return(sum(DDD::L2phylo(L, dropextinct = TRUE)$edge.length))
}

## Do all of them give the same results
fun1(L) == Faith$PD
# [1] TRUE
fun2(L) == Faith$PD
# [1] TRUE
fun3(L) == Faith$PD
# [1] TRUE

## Which function fastest?
microbenchmark(fun1(L), fun2(L), fun3(L))
# Unit: milliseconds
#     expr      min       lq     mean   median       uq       max neval
#  fun1(L) 6.486462 6.900641 8.273386 7.445334 8.667535 16.888429   100
#  fun2(L) 1.627854 1.683204 2.215531 1.771219 2.229408  9.522366   100
#  fun3(L) 1.630635 1.663181 2.229206 1.859733 2.448196  7.573001   100

【讨论】:

    【解决方案2】:

    我检查了pd::sample2matrix,看看它在内部做了什么。 tapply 调用和以下行看起来是唯一必要的部分。

    library(DDD)
    library(tidyverse)
    library(picante)
    #> Loading required package: ape
    #> Loading required package: vegan
    #> Loading required package: permute
    #> Loading required package: lattice
    #> This is vegan 2.5-6
    #> Loading required package: nlme
    #> 
    #> Attaching package: 'nlme'
    #> The following object is masked from 'package:dplyr':
    #> 
    #>     collapse
    set.seed(100)
    result <- dd_sim(c(0.2, 0.1, 20), 10) 
    # with birth rate 0.2, death rate 0.1, carrying capacity 20 and overall 10 million years.
    L <- result$L
    
    # convert L table into community data matrix
    comm_original = as.data.frame(L) %>% dplyr::select(V3:V4) %>%
      dplyr::rename(id = V3, pa = V4) %>%
      dplyr::mutate(id = paste0("t",abs(id))) %>%
      dplyr::mutate(pa = dplyr::if_else(pa == -1, 1, 0)) %>%
      dplyr::mutate(plot = 0) %>%
      dplyr::select(plot, pa, id) %>%
      picante::sample2matrix()
    
    
    # Instead of using dplyr, we'll do some base R operations
    # on L. The code doesn't look as nice, but it should be
    # significantly faster.
    pa <- ifelse(L[, 4] == -1, 1, 0)
    plot <- rep(0, length(pa))
    id <- paste0("t", abs(L[,3]))
    comm_new <- tapply(pa, list(plot, id), sum)
    comm_new[is.na(comm_new)] <- 0
    # convert L table into phylogeny
    phy = DDD::L2phylo(L, dropextinct = T)
    
    # calculate Faith's index using pd() function
    picante::pd(comm_original,phy)
    #>         PD SR
    #> 0 29.82483  6
    
    picante::pd(comm_new, phy)
    #>         PD SR
    #> 0 29.82483  6
    Created on 2019-11-17 by the reprex package (v0.3.0)
    

    编辑:original() 是您最初构建 comm 的方式,new() 是上面给出的方式。如果您将其换掉,看起来您可以期待 2 倍的加速。我知道根据工作负载的大小,这并不是一个巨大的收益,但总比没有好。

    expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result               memory          time    gc            
      <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list>               <list>          <list>  <list>        
    1 original()   9.76ms  10.24ms      96.1     552KB     2.04    47     1      489ms <df[,1125] [1 x 1,1~ <df[,3] [107 x~ <bch:t~ <tibble [48 x~
    2 new()        4.57ms   4.84ms     201.      464KB     2.07    97     1      483ms <dbl[,1125] [1 x 1,~ <df[,3] [63 x ~ <bch:t~ <tibble [98 x~
    

    【讨论】:

    • 感谢您的回答,您的解决方法是个好主意。但我真正感兴趣的是如何直接从 L 表中推导出 PD,我们真的需要在计算分支长度之前重建系统发育吗?我尝试并与其他人讨论过,但直到现在都没有答案。
    • 基于picante::pd()DDD::L2phylo 的代码,我想说这在您无需进行一些重大修改的情况下已经足够好了。我已经编辑了我的答案,以展示您可以期望在原始解决方案中看到的加速量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    相关资源
    最近更新 更多