Partager via


Tutoriel : Découvrir les relations dans le jeu de données Synthea à l’aide d’un lien sémantique

Ce tutoriel montre comment détecter les relations dans le jeu de données Synthea public à l’aide d’un lien sémantique.

Lorsque vous travaillez avec de nouvelles données ou que vous travaillez sans modèle de données existant, il peut être utile de découvrir automatiquement les relations. Cette détection de relation peut vous aider à :

  • comprendre le modèle à un niveau élevé,
  • obtenir plus d’informations lors de l’analyse exploratoire des données,
  • valider les données mises à jour ou nouvelles, les données entrantes et
  • nettoyer les données.

Même si les relations sont connues à l’avance, une recherche de relations peut vous aider à mieux comprendre le modèle de données ou l’identification des problèmes de qualité des données.

Dans ce tutoriel, vous commencez par un exemple de base simple où vous expérimentez seulement trois tables afin que les connexions entre elles soient faciles à suivre. Ensuite, vous affichez un exemple plus complexe avec un ensemble de tables plus volumineux.

Dans ce tutoriel, vous allez apprendre à :

  • Utilisez des composants de la bibliothèque Python du lien sémantique (SemPy) qui prennent en charge l’intégration à Power BI et aident à automatiser l’analyse des données. Ces composants sont les suivants :
    • FabricDataFrame : structure de type pandas améliorée avec des informations sémantiques supplémentaires.
    • Fonctions permettant d’extraire des modèles sémantiques d’un espace de travail Fabric dans votre bloc-notes.
    • Fonctions qui automatisent la découverte et la visualisation des relations dans vos modèles sémantiques.
  • Résolvez les problèmes liés au processus de découverte de relations pour les modèles sémantiques comportant plusieurs tables et interdépendances.

Conditions préalables

  • Obtenez un abonnement Microsoft Fabric . Vous pouvez également vous inscrire à une version d’évaluation gratuite de Microsoft Fabric .

  • Connectez-vous à Microsoft Fabric.

  • Basculez vers Fabric à l’aide du sélecteur d’expérience situé en bas à gauche de votre page d’accueil.

    Capture d’écran montrant la sélection de Fabric dans le menu du sélecteur d’expérience.

  • Sélectionnez espaces de travail dans le volet de navigation gauche pour rechercher et sélectionner votre espace de travail. Cet espace de travail devient votre espace de travail actuel.

Suivre le notebook

Le notebook relationships_detection_tutorial.ipynb accompagne ce tutoriel.

Configurer le notebook

Dans cette section, vous configurez un environnement de notebook avec les modules et données nécessaires.

  1. Installez SemPy à partir de PyPI à l’aide de la fonctionnalité d’installation en ligne %pip dans le notebook :

    %pip install semantic-link
    
  2. Effectuez les importations nécessaires de modules SemPy dont vous aurez besoin ultérieurement :

    import pandas as pd
    
    from sempy.samples import download_synthea
    from sempy.relationships import (
        find_relationships,
        list_relationship_violations,
        plot_relationship_metadata
    )
    
  3. Importez pandas pour appliquer une option de configuration qui permet de mettre en forme la sortie :

    import pandas as pd
    pd.set_option('display.max_colwidth', None)
    
  4. Extrayez les exemples de données. Pour ce tutoriel, vous utilisez le jeu de données Synthea de dossiers médicaux synthétiques (petite version pour plus de simplicité) :

    download_synthea(which='small')
    

Détecter les relations sur un petit sous-ensemble de tables Synthea

  1. Sélectionnez trois tables dans un ensemble plus grand :

    • patients spécifie des informations sur les patients
    • encounters spécifie les patients qui avaient des rencontres médicales (par exemple, un rendez-vous médical, une procédure)
    • providers spécifie quels prestataires médicaux ont assisté aux patients

    La table encounters résout une relation de plusieurs à plusieurs entre patients et providers et peut être décrite comme une entité associative :

    patients = pd.read_csv('synthea/csv/patients.csv')
    providers = pd.read_csv('synthea/csv/providers.csv')
    encounters = pd.read_csv('synthea/csv/encounters.csv')
    
  2. Recherchez des relations entre les tables à l’aide de la fonction find_relationships semPy :

    suggested_relationships = find_relationships([patients, providers, encounters])
    suggested_relationships
    
  3. Visualisez les relations DataFrame en tant que graphique à l’aide de la fonction plot_relationship_metadata semPy.

    plot_relationship_metadata(suggested_relationships)
    

    Capture d’écran montrant les relations entre les tables du jeu de données.

    La fonction définit la hiérarchie de relation du côté gauche vers le côté droit, qui correspond aux tables « from » et « to » dans la sortie. En d’autres termes, les tables indépendantes « from » situées à gauche utilisent leurs clés étrangères pour pointer vers leurs tables de dépendance « to » sur le côté droit. Chaque zone d’entité affiche les colonnes qui participent du côté « from » ou « to » d’une relation.

    Par défaut, les relations sont générées sous la forme « m :1 » (pas comme « 1 :m ») ou « 1:1 ». Les relations « 1:1 » peuvent être générées d’une ou des deux façons, selon que le ratio des valeurs mappées à toutes les valeurs dépasse coverage_threshold dans une ou les deux directions. Plus loin dans ce tutoriel, vous couvrez le cas moins fréquent de relations « m :m ».

Résoudre les problèmes de détection des relations

L’exemple de base montre une détection de relation réussie sur des données Synthea propres. En pratique, les données sont rarement propres, ce qui empêche la détection réussie. Il existe plusieurs techniques qui peuvent être utiles lorsque les données ne sont pas propres.

Cette section de ce didacticiel traite de la détection des relations lorsque le modèle sémantique contient des données incorrectes.

  1. Commencez par manipuler les DataFrames d’origine pour obtenir des données « sales » et imprimer la taille des données sales.

    # create a dirty 'patients' dataframe by dropping some rows using head() and duplicating some rows using concat()
    patients_dirty = pd.concat([patients.head(1000), patients.head(50)], axis=0)
    
    # create a dirty 'providers' dataframe by dropping some rows using head()
    providers_dirty = providers.head(5000)
    
    # the dirty dataframes have fewer records than the clean ones
    print(len(patients_dirty))
    print(len(providers_dirty))
    
    
  2. Pour la comparaison, les tailles d’impression des tables d’origine :

    print(len(patients))
    print(len(providers))
    
  3. Recherchez des relations entre les tables à l’aide de la fonction find_relationships semPy :

    find_relationships([patients_dirty, providers_dirty, encounters])
    

    La sortie du code indique qu’aucune relation n’est détectée en raison des erreurs que vous avez introduites précédemment pour créer le modèle sémantique « sale ».

Utiliser la validation

La validation est le meilleur outil pour résoudre les échecs de détection des relations, car :

  • Il signale clairement pourquoi une relation particulière ne suit pas les règles de clé étrangère et ne peut donc pas être détectée.
  • Il s’exécute rapidement avec des modèles sémantiques volumineux, car il se concentre uniquement sur les relations déclarées et n’effectue pas de recherche.

La validation peut utiliser n’importe quel DataFrame avec des colonnes similaires à celles générées par find_relationships. Dans le code suivant, le dataFrame suggested_relationships fait référence à patients plutôt qu’à patients_dirty, mais vous pouvez alias les DataFrames avec un dictionnaire :

dirty_tables = {
    "patients": patients_dirty,
    "providers" : providers_dirty,
    "encounters": encounters
}

errors = list_relationship_violations(dirty_tables, suggested_relationships)
errors

Assouplir les critères de recherche

Dans des scénarios plus sombres, vous pouvez essayer de relâcher vos critères de recherche. Cette méthode augmente la possibilité de faux positifs.

  1. Définissez include_many_to_many=True et évaluez s’il aide à :

    find_relationships(dirty_tables, include_many_to_many=True, coverage_threshold=1)
    

    Les résultats montrent que la relation entre encounters et patients a été détectée, mais il existe deux problèmes :

    • La relation indique une direction de patients à encounters, qui est une inverse de la relation attendue. Cela est dû au fait que toutes les patients ont été couvertes par encounters (Coverage From est de 1,0) tandis que les encounters ne sont couvertes que partiellement par patients (Coverage To = 0,85), car les lignes des patients sont manquantes.
    • Il existe une correspondance accidentelle sur une colonne GENDER de faible cardinalité, qui correspond par nom et valeur dans les deux tables, mais il ne s’agit pas d’une relation « m:1 » d’intérêt. La cardinalité faible est indiquée par les colonnes Unique Count From et Unique Count To.
  2. Réexécutez find_relationships pour rechercher uniquement les relations « m :1 », mais avec une coverage_threshold=0.5inférieure :

    find_relationships(dirty_tables, include_many_to_many=False, coverage_threshold=0.5)
    

    Le résultat montre la direction correcte des relations entre encounters et providers. Toutefois, la relation de encounters à patients n’est pas détectée, car patients n’est pas unique, de sorte qu’elle ne peut pas être du côté « Un » de la relation « m :1 ».

  3. Assouplissez include_many_to_many=True et coverage_threshold=0.5 :

    find_relationships(dirty_tables, include_many_to_many=True, coverage_threshold=0.5)
    

    Maintenant, les deux relations d’intérêt sont visibles, mais il y a beaucoup plus de bruit :

    • La correspondance de cardinalité faible sur GENDER est présente.
    • Une correspondance m:m de cardinalité plus élevée sur ORGANIZATION est apparue, ce qui indique que ORGANIZATION est probablement une colonne dé-normalisée pour les deux tables.

Mettre en correspondance les noms de colonnes

Par défaut, SemPy considère comme correspondant uniquement aux attributs qui affichent la similarité du nom, en tirant parti du fait que les concepteurs de base de données nomment généralement les colonnes associées de la même façon. Ce comportement permet d’éviter les relations erronées, qui se produisent le plus fréquemment avec des clés entières de cardinalité faible. Par exemple, s’il existe 1,2,3,...,10 catégories de produits et 1,2,3,...,10 code d’état de commande, ils sont confondus les uns avec les autres lorsque vous examinez uniquement les mappages de valeurs sans prendre en compte les noms de colonnes. Les relations erronées ne devraient pas être un problème avec les clés de type GUID.

SemPy examine une similarité entre les noms de colonnes et les noms de table. La correspondance est approximative et ne respecte pas la casse. Elle ignore les substrings « decorator » les plus fréquemment rencontrées, telles que « id », « code », « name », « key », « pk », « fk ». Par conséquent, les cas de correspondance les plus classiques sont les suivants :

  • un attribut appelé « column » dans l’entité « foo » correspond à un attribut appelé « column » (également « COLUMN » ou « Column ») dans l’entité « bar ».
  • un attribut appelé 'column' dans l’entité 'foo' correspond à un attribut appelé 'column_id' dans 'bar'.
  • un attribut appelé « bar » dans l’entité « foo » correspond à un attribut appelé « code » dans « bar ».

En mettant en correspondance les noms de colonnes en premier, la détection s’exécute plus rapidement.

  1. Mettre en correspondance les noms des colonnes :

    • Pour comprendre les colonnes sélectionnées pour une évaluation ultérieure, utilisez l’option verbose=2 (verbose=1 répertorie uniquement les entités en cours de traitement).
    • Le paramètre name_similarity_threshold détermine la façon dont les colonnes sont comparées. Le seuil de 1 indique que vous êtes intéressé uniquement par les correspondances à 100 %.
    find_relationships(dirty_tables, verbose=2, name_similarity_threshold=1.0);
    

    L’exécution avec une similarité à 100 % ne tient pas compte des petites différences entre les noms. Dans votre exemple, les tables ont une forme plurielle avec le suffixe « s », ce qui n’entraîne aucune correspondance exacte. Ceci est géré correctement avec la name_similarity_threshold=0.8par défaut .

  2. Réexécuter avec la name_similarity_threshold=0.8par défaut :

    find_relationships(dirty_tables, verbose=2, name_similarity_threshold=0.8);
    

    Notez que les ID de la forme plurielle patients sont maintenant comparés à la forme singulière patient sans ajouter trop d’autres comparaisons superflues au temps d’exécution.

  3. Réexécuter avec la name_similarity_threshold=0par défaut :

    find_relationships(dirty_tables, verbose=2, name_similarity_threshold=0);
    

    La modification de name_similarity_threshold à 0 est l’autre extrême et indique que vous souhaitez comparer toutes les colonnes. Cela est rarement nécessaire et entraîne une augmentation du temps d’exécution et des correspondances erronées qui doivent être examinées. Observez le nombre de comparaisons dans la sortie détaillée.

Résumé des conseils de résolution des problèmes

  1. Commencez à partir d’une correspondance exacte pour les relations « m :1 » (autrement dit, les include_many_to_many=False par défaut et les coverage_threshold=1.0). C’est généralement ce que vous voulez.
  2. Utilisez un focus étroit sur des sous-ensembles de tables plus petits.
  3. Utilisez la validation pour détecter les problèmes de qualité des données.
  4. Utilisez verbose=2 si vous souhaitez comprendre les colonnes prises en compte pour la relation. Cela peut générer une grande quantité de résultats.
  5. Soyez conscient des compromis liés aux arguments de recherche. include_many_to_many=True et coverage_threshold<1.0 peuvent produire des relations erronées qui peuvent être plus difficiles à analyser et qui devront être filtrées.

Détecter les relations sur le jeu de données complet Synthea

L’exemple de base simple était un outil pratique d’apprentissage et de résolution des problèmes. Dans la pratique, vous pouvez commencer à partir d’un modèle sémantique tel que le jeu de données Synthea complet, qui a beaucoup plus de tables. Explorez le jeu de données complet synthea comme suit.

  1. Lisez tous les fichiers du répertoire synthea/csv :

    all_tables = {
        "allergies": pd.read_csv('synthea/csv/allergies.csv'),
        "careplans": pd.read_csv('synthea/csv/careplans.csv'),
        "conditions": pd.read_csv('synthea/csv/conditions.csv'),
        "devices": pd.read_csv('synthea/csv/devices.csv'),
        "encounters": pd.read_csv('synthea/csv/encounters.csv'),
        "imaging_studies": pd.read_csv('synthea/csv/imaging_studies.csv'),
        "immunizations": pd.read_csv('synthea/csv/immunizations.csv'),
        "medications": pd.read_csv('synthea/csv/medications.csv'),
        "observations": pd.read_csv('synthea/csv/observations.csv'),
        "organizations": pd.read_csv('synthea/csv/organizations.csv'),
        "patients": pd.read_csv('synthea/csv/patients.csv'),
        "payer_transitions": pd.read_csv('synthea/csv/payer_transitions.csv'),
        "payers": pd.read_csv('synthea/csv/payers.csv'),
        "procedures": pd.read_csv('synthea/csv/procedures.csv'),
        "providers": pd.read_csv('synthea/csv/providers.csv'),
        "supplies": pd.read_csv('synthea/csv/supplies.csv'),
    }
    
  2. Recherchez des relations entre les tables à l’aide de la fonction find_relationships semPy :

    suggested_relationships = find_relationships(all_tables)
    suggested_relationships
    
  3. Visualiser les relations :

    plot_relationship_metadata(suggested_relationships)
    

    Capture d’écran des relations entre les tables.

  4. Comptez le nombre de nouvelles relations « m :m » découvertes avec include_many_to_many=True. Ces relations s'ajoutent aux relations de type « m:1 » précédemment affichées ; par conséquent, vous devez filtrer sur multiplicity:

    suggested_relationships = find_relationships(all_tables, coverage_threshold=1.0, include_many_to_many=True) 
    suggested_relationships[suggested_relationships['Multiplicity']=='m:m']
    
  5. Vous pouvez trier les données de relation par différentes colonnes pour mieux comprendre leur nature. Par exemple, vous pouvez choisir de classer la sortie par Row Count From et Row Count To, ce qui permet d’identifier les tables les plus volumineuses.

    suggested_relationships.sort_values(['Row Count From', 'Row Count To'], ascending=False)
    

    Dans un modèle sémantique différent, il serait peut-être important de se concentrer sur le nombre de valeurs null Null Count From ou Coverage To.

    Cette analyse peut vous aider à comprendre si l’une des relations peut être non valide et si vous devez les supprimer de la liste des candidats.

Consultez d’autres didacticiels pour le lien sémantique / SemPy :