Ответ 1
data.frame для Newick
Я сделал свою кандидатскую диссертацию по вычислительной филогенетике и где-то по пути создания этого кода я использовал один или два раза, когда получил некоторые данные в этом нестандартном формате (в филогенетическом смысле). script пересекает структуру данных, как будто это дерево... и вставляет материал по пути в строку Newick, которая является стандартным форматом и может быть затем преобразована в любой тип древовидного объекта.
Я думаю, что script может быть оптимизирован (я использовал его так редко, что работа над ним снизила бы общую эффективность), но, по крайней мере, лучше делиться, чем позволять собирать пыль вокруг моего жесткого диска.
## recursion function
traverse <- function(a,i,innerl){
if(i < (ncol(df))){
alevelinner <- as.character(unique(df[which(as.character(df[,i])==a),i+1]))
desc <- NULL
if(length(alevelinner) == 1) (newickout <- traverse(alevelinner,i+1,innerl))
else {
for(b in alevelinner) desc <- c(desc,traverse(b,i+1,innerl))
il <- NULL; if(innerl==TRUE) il <- a
(newickout <- paste("(",paste(desc,collapse=","),")",il,sep=""))
}
}
else { (newickout <- a) }
}
## data.frame to newick function
df2newick <- function(df, innerlabel=FALSE){
alevel <- as.character(unique(df[,1]))
newick <- NULL
for(x in alevel) newick <- c(newick,traverse(x,1,innerlabel))
(newick <- paste("(",paste(newick,collapse=","),");",sep=""))
}
Основная функция df2newick()
принимает два аргумента:
-
df
, который является преобразователем данных (объект класса data.frame) -
innerlabel
, который сообщает функции писать метки для внутренних узлов (bulean)
Чтобы продемонстрировать это на вашем примере:
df <- data.frame(x=c('A','A','B','B','B'), y=c('Ab','Ac','Ba', 'Ba','Bd'), z=c('Abb','Acc','Bad', 'Bae','Bdd'))
myNewick <- df2newick(df)
#[1] "((Abb,Acc),((Bad,Bae),Bdd));"
Теперь вы можете прочитать его в объекте класса phylo
с read.tree()
от ape
library(ape)
mytree <- read.tree(text=myNewick)
plot(mytree)
Если вы хотите добавить внутренние метки node в строку Newick, вы можете использовать это:
myNewick <- df2newick(df, TRUE)
#[1] "((Abb,Acc)A,((Bad,Bae)Ba,Bdd)B);"
Надеюсь, что это полезно (и, может быть, мой доктор философии не был полной талией времени;)
Дополнительная заметка для формата данных:
Как вы можете заметить, функция df2newick игнорирует внутренние моды с одним ребенком (который в любом случае лучше всего подходит для большинства филогенетических методов... был применим только для меня). Объекты df
, которые я первоначально получил и использовали с этим script, были в этом формате:
df <- data.frame(x=c('A','A','B','B','B'), y=c('Abb','Acc','Ba', 'Ba','Bdd'), z=c('Abb','Acc','Bad', 'Bae','Bdd'))
Очень похож на ваш... но "внутренние дочерние узлы singe" просто имеют то же имя, что и их дети, но у вас есть и другие внутренние имена для этих узлов, а имена проигнорированы... возможно, не релевантны но вы можете просто игнорировать часть функции рекурсии, например:
traverse <- function(a,i,innerl){
if(i < (ncol(df))){
alevelinner <- as.character(unique(df[which(as.character(df[,i])==a),i+1]))
desc <- NULL
##if(length(alevelinner) == 1) (newickout <- traverse(alevelinner,i+1,innerl))
##else {
for(b in alevelinner) desc <- c(desc,traverse(b,i+1,innerl))
il <- NULL; if(innerl==TRUE) il <- a
(newickout <- paste("(",paste(desc,collapse=","),")",il,sep=""))
##}
}
else { (newickout <- a) }
}
и вы получите что-то вроде этого:
[1] "(((Abb)Ab,(Acc)Ac)A,((Bad,Bae)Ba,(Bdd)Bd)B);"
Это действительно странно для меня, но я добавляю его на всякий случай, потому что он действительно включает в себя всю информацию из вашего исходного фрейма.