2  Méthodes par distance

Les méthodes par distance sont simples à comprendre et à implémenter car elles reposent en général sur un algorithme qui ne compare pas les arbres possibles mais construit un arbre unique.

Toutefois, elles ont plusieurs faiblesses qui font qu’elles sont d’un usage limité aujourd’hui:

Les méthodes par distance ne peuvent donc pas être recommandées pour l’analyse phylogénétique.

2.1 Calcul des distances

Commençons par importer de nouveau la matrice de traits à états multiples que nous avions sauvegardée précédemment. Calculer la distance sur les données binarisées pourrait biaiser les calculs en donnant plus de poids aux caractères ayant un plus grand nombre d’états possibles.

Il est trivial de calculer la distance observée, ou p-distance, sur une telle matrice. Il suffit de calculer pour chaque paire de langues le rapport entre nombre de caractères différents et le nombre de caractères total avec la fonction Hamming() qui prend en charge les données manquantes et les polymorphismes.

lx_dist <- Hamming(lx_phy)

La diagonale des distances de chaque langue avec elle-même est bien sûr 0, et la matrice de distance est symétrique, on peut donc se passer d’afficher l’un des deux triangles.

Code
lx_dist_m <- as.matrix(lx_dist)
lx_dist_m[upper.tri(lx_dist_m)] <- NA
options(knitr.kable.NA = "")
knitr::kable(lx_dist_m, digits = 2)
Bleu Cyan Indigo Jaune Magenta Orange Rouge Vert Violet
Bleu 0.00
Cyan 0.13 0.00
Indigo 0.13 0.08 0.00
Jaune 0.22 0.21 0.21 0.00
Magenta 0.17 0.17 0.18 0.25 0.00
Orange 0.14 0.20 0.21 0.16 0.19 0.00
Rouge 0.16 0.19 0.17 0.25 0.15 0.20 0.00
Vert 0.19 0.22 0.24 0.19 0.20 0.10 0.21 0.00
Violet 0.17 0.20 0.22 0.22 0.23 0.12 0.21 0.14 0

On peut alternativement afficher la matrice des similitudes en retranchant les distances de 1, voir des pourcentages en multipliant le résultat par 100. On obtient alors une matrice semblable à ce qu’on voit en lexicostatistique.

lx_sim_m <- (1 - as.matrix(lx_dist)) * 100
Code
lx_sim_m[upper.tri(lx_sim_m)] <- NA
options(knitr.kable.NA = "")
knitr::kable(lx_sim_m, digits = 2)
Bleu Cyan Indigo Jaune Magenta Orange Rouge Vert Violet
Bleu 100.00
Cyan 86.92 100.00
Indigo 87.16 91.67 100.00
Jaune 77.98 78.70 79.09 100.00
Magenta 83.49 83.18 81.65 75.23 100.00
Orange 86.24 79.63 79.09 83.64 80.73 100.00
Rouge 84.40 80.56 82.73 75.45 85.32 80.00 100.00
Vert 81.48 77.57 76.15 80.73 79.63 89.91 78.90 100.00
Violet 83.49 79.63 78.18 78.18 77.06 88.18 79.09 86.24 100

2.2 UPGMA

L’algorithme de classification UPGMA (Unweighted pair group method with arithmetic mean) est le plus basique et le moins bon pour les classifications génétiques. Cette méthode présuppose notamment une «horloge moléculaire», c’est-à-dire que la vitesse de changement était constante, ce qui est faux en biologie comme en linguistique. Le résultat est un arbre dit ultramétrique où toutes les langues sont alignées au lieu d’être placées en fonction du nombre de changements avec des branches de longueur variées.

Néanmoins cette méthode est simplissime: on groupe les taxons les plus proches ensemble, et la distance du groupe obtenu aux taxons restants est recalculée en faisant la moyenne des distances des éléments groupés, et on recommence jusqu’à n’avoir plus que deux groupes.

lx_upgma <- upgma(lx_dist)
lx_upgma

Phylogenetic tree with 9 tips and 8 internal nodes.

Tip labels:
  Bleu, Cyan, Indigo, Jaune, Magenta, Orange, ...

Rooted; includes branch lengths.

On peut alors sauvegarder les résultats dans un fichier au format Newick.

write.tree(lx_upgma, "lx_upgma.tree")

On obtient un arbre unique enraciné qu’on peut facilement visualiser.

plot(lx_upgma)

2.3 Neighbour joining

La méthode de neighbour joining est plus sophistiquée que celle de UPGMA mais reste néanmoins simple. Elle s’en distingue par la prise en compte dans l’algorithme de la distance entre toutes les paires de taxons, et non seulement entre les paires les plus proches. Elle produit un arbre non enraciné et non ultramétrique.

lx_nj <- NJ(lx_dist)
lx_nj

Phylogenetic tree with 9 tips and 7 internal nodes.

Tip labels:
  Bleu, Cyan, Indigo, Jaune, Magenta, Orange, ...

Unrooted; includes branch lengths.
plot(lx_nj, "unrooted")

On peut bien sûr artificiellement enraciner l’arbre, mais c’est rarement une bonne idée. C’est néanmoins parfois nécessaire pour visualiser un grand nombre de langues.

plot(lx_nj, "tidy")

2.4 NeighborNet

L’algorithme NeighborNet permet d’obtenir non pas un arbre mais un réseau qui montre notamment les conflits dans les données.

lx_nn <- neighborNet(lx_dist)
lx_nn

Phylogenetic tree with 9 tips and 45 internal nodes.

Tip labels:
  Orange, Jaune, Bleu, Indigo, Cyan, Magenta, ...

Unrooted; includes branch lengths.
plot(lx_nn)

Ce réseau peut être sauvegardé au format nexus avec la fonction write.nexus.networx().

write.nexus.networx(lx_nn, "lx_nn.nex")