Allez vers la page précédente - étapes

Fusionner les bases de données

Une fois que l'on a pris connaissances des données que l'on souhaite obtenir des différentes bases de données, il est nécessaire de fusionner les différentes bases de données et dédoublonner les données qui apparaissent dans plusieurs bases de données.

Dédoublonner

La première étape est d'enlever les doublons au sein de chaque base de données afin de ne pas grossir artificiellement le nombre de ligne. Pour cela, il suffit d'utiliser drop_duplicates disponible avec la bibliothèque pandas. Cela se construit comme ceci:

df_bnf.drop_duplicates(subset ="uri_bnf", keep = 'first', inplace=True)

Le première argument signifie que l'on dédoublonne avec la colonne URI (c'est celle qui a le moins d'ambiguïté), le second veut dire qu'on ne garde que le premier et le dernier permet d'écraser les données. Par exemple pour BnF Data, nous passons de 11132 à 11039 lignes. Donc ça enlève quelques lignes.

Création d'ID unique

Ensuite, il est nécessaire de créer des ID unique pour chaque personne dans chaque base de données afin de fusionner

Fusion

Ensuite, il est possible de réaliser la fusion à proprement parler. Pour cela, il faut utiliser une méthode de record linkage qui permet de calculer la proximité entre deux chaînes de caractères. La méthode est répétée entre chaque ligne pour les variables choisies. Nous avons choisis d'utiliser cette méthode sur le nom de la personne, sa date de naissance et sa date de décès. Les deux derniers ont l'avantage d'avoir un format strict (YYYY-MM-DD), donc améliore considérablement les scores.

Pour réaliser cela, plusieurs bibliothèques python existent. Deux serons présentées ici, et elles sont présentées dans ce très bon article recordlinking posté par Chris Moffitt.

fuzzymatcher

Tout d'abord, la bibliothèque fuzzymatcher ( la documentation est très succincte; télécharger avec conda ou pip ) permet de le faire. Mais elle a le gros désavantage de ne pas fonctionner avec des nombres ou des dates (ou plutôt elle est analyse comme des chaînes de caractère).

On commence par choisir les colonnes pour lesquels ont veut utiliser la méthode:

left_on=["name_bnf", "placeOfBirth_bnf","placeOfDeath_bnf"]
right_on=["name_dbp", "placeOfBirth_dbp","placeOfDeath_dbp"]

Ensuite, on applique la méthode à proprement parler:

matched_results = fuzzymatcher.fuzzy_left_join(BnF_Data,
DBpedia,
left_on,
right_on,
left_id_col='uri_bnf',
right_id_col='uri_dbp')

Après, il faut expliciter quels colonnes souhaite-on voir apparaître (même celles sur lesquelles, le calcul ne se fait pas):

cols_bnf_dbp= ["best_match_score","id_bnf","uri_bnf","viaf_bnf", "name_bnf", "dateBirth_bnf", "dateDeath_bnf","placeOfBirth_bnf","placeOfDeath_bnf", "bio_bnf", "id_dbp","uri_dbp", "viaf_dbp", "name_dbp","birthDate_dbp","deathDate_dbp", "placeOfBirth_dbp","placeOfDeath_dbp"]

Enfin on affiche les résultats:

best_match_bnf_dbp=matched_results[cols_bnf_dbp].sort_values(by=["best_match_score"], ascending=False).head(10)
best_match_bnf_dbp

recordlinkage

La seconde méthode semble beaucoup pertinente au vu des données que nous disposons. La bibliothèque recordlinkage (télécharger avec conda ou pip permet aussi de calculer la proximité entre des chaînes de caractères. Mais cette dernière à l'avantage de fonctionner avec tous types de données (cf. cette page pour voir les types).

La méthode de cette bibliothèque est assez semblable à la précédente. on commence par index les deux jeux de données:

import recordlinkage
indexer = recordlinkage.Index()
indexer.sortedneighbourhood(left_on='name_bnf', right_on='name_dbp')
candidates = indexer.index(BnF_Data, DBpedia)
print(len(candidates))

Il est possible de le faire sur l'ensemble des données, mais au regard volume et de la puissance de calcul nécessaire, nous le faisons que pour une seule variable. À nous choisissons celle qui donne le plus grand nombre candidat potentiel.

Ensuite, il faut réaliser les comparaisons: compare = recordlinkage.Compare()

compare.string('name_bnf',
'name_dbp',
threshold=0.85,
label='name_bnf_dbp')
compare.exact('dateBirth_bnf',
'birthDate_dbp',
label='birthDate_bnf_dbp')
compare.exact('dateDeath_bnf',
'deathDate_dbp',
label='deathDate_bnf_dbp')
features = compare.compute(candidates, BnF_Data, DBpedia)

Pour les dates de naissance et de mort, nous avons fait le choix de prendre les valeurs exacts afin de contrer des éventuels différences de formats (ex: dans BnF Data certaines dates sont écrites ainsi: “18..” la bibliothèque n'arrive pas à les interpréter et ne sort pas de résultats).

Il faut ensuite de fusionner les données prenant les comparaisons avec un haut score. Ce dernier indique sur combien de variable un score élevé à été trouvé et les additionnent:

potential_matches = features[features.sum(axis=1) > 1].reset_index()
potential_matches['Score'] = potential_matches.loc[:, 'name_bnf_dbp':'deathDate_bnf_dbp'].sum(axis=1)
potential_matches

L'ensemble de la méthode est disponible sur un carnet sur Github.