1 Préparation des données
La plupart des analyses phylolinguistiques utilisent des données lexicales. Une étape préalable à l’analyse phylogénétique consiste à déterminer quels mots sont cognats (homologues) et à les annoter. Cette tâche peut être grandement facilitée grâce à Edictor, un éditeur libre et gratuit de bases de données lexicales comparatives créé par Mattis List. Il permet entre autres d’annoter facilement les classes de cognats (ensembles de mots apparentés) dans un navigateur internet en ligne ou hors ligne. Un tutoriel en ligne détaillé est disponible en ligne.
1.1 Import
Edictor permet de sauvegarder les données traitées sous forme d’un fichier tabulaire au format .tsv. Il est alors très simple de l’importer avec R, en prenant garde d’ignorer les lignes de commentaires à la fin marquées par #.
Téléchargeons et importons pour l’exemple des données sur les variétés bai fournies dans Edictor. Les seules colonnes qui vont nous intéresser ici sont CONCEPTID (identifiant unique du concept), DOCULECT (langue) et COGIDS (classe de cognats). En outre, certaines langues peuvent avoir plusieurs formes (variantes?) pour une même classe de cognats, mais l’information qui nous intéresse est simplement la présence ou non d’un cognat, on peut donc supprimer les lignes superflues correspondantes avec la fonction distinct().
L’information sur les classes de cognats se trouve dans la colonne COGIDS.
Comme il s’agit de faire un exemple et non une réelle analyse phylogénétique, je propose de renommer les langues de manière arbitraire afin de ne pas induire en erreur les personnes qui tomberaient par hasard sur les résultats de nos analyses et les diffuseraient sans le contexte de ce tutoriel.
lx <- lx %>%
mutate(DOCULECT = case_when(
DOCULECT == "Gongxing" ~ "Magenta",
DOCULECT == "Jinman" ~ "Cyan",
DOCULECT == "Mazhelong" ~ "Jaune",
DOCULECT == "Dashi" ~ "Vert",
DOCULECT == "Zhoucheng" ~ "Violet",
DOCULECT == "Jinxing" ~ "Orange",
DOCULECT == "Tuolo" ~ "Rouge",
DOCULECT == "Enqi" ~ "Bleu",
DOCULECT == "Ega" ~ "Indigo",
))1.2 Conversion
Le but est de construire une matrice indiquant quels mots sont cognats, mais plusieurs types de matrices sont possibles.
1.2.1 États multiples
Tout d’abord, on peut utiliser un codage à états multiples et encoder pour chaque concept quelle est la classe de cognat de la forme de chaque langue. Chaque caractère peut ainsi avoir dans une langue une valeur parmi un ensemble d’une longueur finie, typiquement représentée par un chiffre entre 0 et 9 dans les formats de fichier pour la phylogénétique. L’ensemble des états possibles est propre à chaque caractère: 1 pour un caractère ne représente pas la même valeur que 1 pour un autre caractère, et des caractères différents peuvent ne pas avoir le même nombre d’états possibles.
Au-delà de 10 états différents, il est nécessaire d’utiliser d’autres symboles comme des lettres car les chaque doit être représenté par un seul symbole.
Un problème qui se pose pour le codage à états multiples est celui du polymorphisme, par exemple quand une langue présente deux synonymes pour un même concept et que chacun appartient à une classe de cognat différente. La convention standard pour une langue présentant à la fois l’état 1 et l’état 2 sera ici de noter dans ce cas {12}.
On trouve aussi la convention d’utiliser des parenthèses.
Vérifier s’il est possible d’avoir un polymorphisme de plus de deux états.
Il donc nécessaire tout d’abord de transformer les valeurs de COGIDS en chiffres à l’intérieur de chaque groupe de CONCEPTID. On concatène ensuite les valeurs multiples de COGIDS pour un même DOCULECT et CONCEPTID, avant de les entourer de parenthèses. On peut ensuite pivoter (et non transposer) notre tableau: les valeurs de CONCEPTID vont devenir des colonnes remplies par les valeurs correspondantes de COGIDS. Si pour une valeur de CONCEPTID donnée il n’y a pas de COGIDS associé dans un DOCULECT, c’est-à-dire que la langue n’a aucun concept avec une forme appartenant à cette classe de cognat, on remplit la cellule avec un ? pour indiquer que les données sont manquantes
lx_multi <- lx %>%
group_by(CONCEPTID) %>%
mutate(COGIDS = as.factor(COGIDS) %>% as.numeric()) %>%
group_by(DOCULECT, CONCEPTID) %>%
summarise(COGIDS = paste0(COGIDS, collapse = "")) %>%
ungroup() %>%
mutate(COGIDS = ifelse(str_detect(COGIDS, "..+"), paste0("{", COGIDS, "}"), COGIDS)) %>%
pivot_wider(
names_from = CONCEPTID,
values_from = COGIDS,
values_fill = "?",
)Pour finir de convertir nos données en une matrice phylogénétique prête à l’analyse, il suffit de les convertir en objet matriciel puis enfin d’utiliser la fonction MatrixTophyDat() de TreeTools.
La fonction phyDat() de phangorn ne semble pas capable de convertir les cas de polymorphismes.
library(TreeTools)
lx_phy_multi <- lx_multi %>%
column_to_rownames("DOCULECT") %>%
as.matrix() %>%
MatrixToPhyDat()Le résultat s’affiche mal en HTML.
On peut alors sauvegarder la matrice obtenue avec la fonction write.phyDat(). Plusieurs formats courants comme Nexus ou Phylip sont possibles. Le format Nexus est ici recommandé pour bien prendre en compte les polymorphismes.
library(phangorn)
write.phyDat(lx_phy_multi, "lx_phy_multi.nex", format = "nexus")Cette conversion étant un peu fastidieuse, il est plus pratique de créer une fonction réutilisable pour tout le processus de conversion d’un fichier .tsvau format Edictor vers une matrice de traits binaires au format phyDat.
as_phyDatM_edictor <- function(dt) {
dt %>%
group_by(CONCEPTID) %>%
mutate(COGIDS = as.factor(COGIDS) %>% as.numeric()) %>%
group_by(DOCULECT, CONCEPTID) %>%
summarise(COGIDS = paste0(COGIDS, collapse = "")) %>%
ungroup() %>%
mutate(COGIDS = ifelse(str_detect(COGIDS, "..+"), paste0("{", COGIDS, "}"), COGIDS)) %>%
pivot_wider(
names_from = CONCEPTID,
values_from = COGIDS,
values_fill = "?",
) %>%
column_to_rownames("DOCULECT") %>%
as.matrix() %>%
MatrixToPhyDat()
}as_phyDatM_edictor(lx)9 sequences with 110 character and 43 different site patterns.
The states are 1 2 3 4 5 6 7
1.2.2 États binaires
Il est cependant courant en phylolinguistique d’utiliser une matrice avec des caractères binaires: la langue possède-t-elle (1) ou non (0) un cognat pour une classe de cognats et un concept donnés? Cela permet de traiter sans problème les cas de polymorphisme, comme on peut en trouver dans nos données d’exemple, et lève toute limite au nombre d’états possibles pour un caractère. Les méthodes bayésiennes utilisent en général des données binaires car elles modélisent la perte et l’apparition de traits.
La conversion est un peu plus complexe et nécessite de pivoter trois fois notre tableau en faisant attention aux éventuelles données manquantes (les cas où un concept n’apparaît pas dans dans la liste d’une langue). Dans un premier temps, on utilise les valeurs de DOCULECT comme noms de colonnes et on remplit de 0 si la langue n’a pas de forme pour une classe de cognat et un concept donnés, et avec 1 sinon. Il faut rajouter une colonne fantoche auparavant avec par exemple rowid_to_column afin de conserver les colonnes CONCEPT et COGIDS et utiliser cette colonne fantoche pour remplir les cellules. On repivote ensuite notre tableau dans l’autre sens en mettant l’information binaire (présence ou non d’une même association entre un concept et une classe de cognat) dans une colonne VALUE dont on convertit le type de numérique à caractère. Pour chaque langue et concept, s’il n’y aucune classe de cognat et donc uniquement des 0 dans VALUE, c’est que les données sont manquantes, et on remplace les 0 par ?, le symbole standard pour les données manquantes. Enfin on peut pivoter à nouveau le tableau, cette fois-ci en utilisant une nouvelle valeur concaténant CONCEPT et COGIDS comme noms de colonnes et en abandonnant ces deux colonnes d’origine. On obtient ainsi un tableau au format large avec les langues (taxons) en lignes et les combinaisons entre concepts et classes de cognats en colonnes, avec 1 pour «présence», 0 pour «absence», et ? pour «donnée manquante».
lx_bin <- lx %>%
rowid_to_column() %>%
pivot_wider(
names_from = DOCULECT,
values_from = rowid,
values_fill = 0,
values_fn = length
) %>%
pivot_longer(cols = !(CONCEPTID | COGIDS), names_to = "DOCULECT", values_to = "VALUE") %>%
mutate(VALUE = as.character(VALUE)) %>%
group_by(CONCEPTID, DOCULECT) %>%
mutate(allzero = sum(VALUE != "0") == 0) %>%
rowwise() %>%
mutate(VALUE = ifelse(allzero, "?", VALUE)) %>%
ungroup() %>%
mutate(id = paste0(CONCEPTID, "_", COGIDS)) %>%
select(DOCULECT, id, VALUE) %>%
pivot_wider(
names_from = id,
values_from = VALUE
)Comme précédemment, il suffit de convertir le résultat avec MatrixTophyDat() de TreeTools.
lx_phy_bin <- lx_bin %>%
column_to_rownames("DOCULECT") %>%
as.matrix() %>%
MatrixToPhyDat()
lx_phy_bin9 sequences with 205 character and 80 different site patterns.
The states are 0 1
On peut alors sauvegarder la matrice obtenue avec la fonction write.phyDat(). Plusieurs formats courants comme Nexus ou Phylip sont possibles. Pour une simple matrice comme la nôtre, l’option par défaut (Phylip) est suffisante (le réimport d’un fichier nexus à traits binaires pose en autre des problèmes non encore résolus).
write.phyDat(lx_phy_bin, "lx_phy_bin.nex", format = "nexus")Régler le problème de spécification des symboles dans les fichiers Nexus pour les données binaires.
Cette conversion étant un peu fastidieuse, il est plus pratique de créer une fonction réutilisable pour tout le processus de conversion d’un fichier .tsvau format Edictor vers une matrice de traits binaires au format phyDat.
as_phyDat2_edictor <- function(dt) {
dt %>%
rowid_to_column() %>%
pivot_wider(
names_from = DOCULECT,
values_from = rowid,
values_fill = 0,
values_fn = length
) %>%
pivot_longer(cols = !(CONCEPTID | COGIDS), names_to = "DOCULECT", values_to = "VALUE") %>%
mutate(VALUE = as.character(VALUE)) %>%
group_by(CONCEPTID, DOCULECT) %>%
mutate(allzero = sum(VALUE != "0") == 0) %>%
rowwise() %>%
mutate(VALUE = ifelse(allzero, "?", VALUE)) %>%
ungroup() %>%
mutate(id = paste0(CONCEPTID, "_", COGIDS)) %>%
select(DOCULECT, id, VALUE) %>%
pivot_wider(
names_from = id,
values_from = VALUE
) %>%
column_to_rownames("DOCULECT") %>%
as.matrix() %>%
MatrixToPhyDat()
}as_phyDat2_edictor(lx)9 sequences with 205 character and 80 different site patterns.
The states are 0 1
