Udostępnij za pośrednictwem


Samouczek: odnajdywanie relacji w zestawie danych Synthea przy użyciu linku semantycznego

Ten samouczek pokazuje, jak wykrywać relacje w publicznym zestawie danych Synthea przy pomocy łącza semantycznego.

Podczas pracy z nowymi danymi lub pracy bez istniejącego modelu danych pomocne może być automatyczne odnajdywanie relacji. To wykrywanie relacji może pomóc w:

  • zrozumienie modelu na poziomie ogólnym
  • uzyskiwanie dodatkowych szczegółowych informacji podczas eksploracyjnej analizy danych,
  • weryfikowanie zaktualizowanych danych lub nowych danych przychodzących i
  • czyszczenie danych.

Nawet jeśli relacje są znane z wyprzedzeniem, wyszukiwanie relacji może pomóc w lepszym zrozumieniu modelu danych lub identyfikacji problemów z jakością danych.

W tym samouczku zaczniesz od prostego przykładu odniesienia, w którym eksperymentujesz tylko z trzema tabelami, aby połączenia między nimi były łatwe do naśladowania. Następnie przedstawiono bardziej złożony przykład z większym zestawem tabel.

Z tego samouczka dowiesz się, jak wykonywać następujące działania:

  • Użyj składników biblioteki języka Python łącza semantycznego (SemPy), które obsługują integrację z usługą Power BI i pomagają zautomatyzować analizę danych. Te składniki obejmują:
    • FabricDataFrame — struktura podobna do pandas, wzbogacona o dodatkowe informacje semantyczne.
    • Funkcje służące do ściągania modeli semantycznych z obszaru roboczego usługi Fabric do notesu.
    • Funkcje, które automatyzują odnajdywanie i wizualizację relacji w modelach semantycznych.
  • Rozwiązywanie problemów z procesem odnajdywania relacji dla modeli semantycznych z wieloma tabelami i współzależnościami.

Warunki wstępne

  • Wybierz pozycję Obszary robocze w okienku nawigacji po lewej stronie, aby znaleźć i wybrać obszar roboczy. Ten obszar roboczy staje się aktualnym obszarem roboczym.

Śledź w zeszycie

Zeszyt relationships_detection_tutorial.ipynb towarzyszy temu samouczkowi.

Konfigurowanie notesu

W tej sekcji skonfigurujesz środowisko notesu z niezbędnymi modułami i danymi.

  1. Zainstaluj SemPy z PyPI przy użyciu funkcji instalacji wbudowanej %pip w notesie:

    %pip install semantic-link
    
  2. Wykonaj niezbędne importy modułów SemPy, które będą potrzebne później:

    import pandas as pd
    
    from sempy.samples import download_synthea
    from sempy.relationships import (
        find_relationships,
        list_relationship_violations,
        plot_relationship_metadata
    )
    
  3. Zaimportuj bibliotekę pandas do wymuszania opcji konfiguracji, która ułatwia formatowanie danych wyjściowych:

    import pandas as pd
    pd.set_option('display.max_colwidth', None)
    
  4. Ściąganie przykładowych danych. Na potrzeby tego samouczka użyjesz zestawu danych Synthea syntetycznych dokumentacji medycznej (mała wersja dla uproszczenia):

    download_synthea(which='small')
    

Wykrywanie relacji w małym podzestawie tabel Synthea

  1. Wybierz trzy tabele z większego zestawu:

    • patients określa informacje o pacjentach
    • encounters określa pacjentów, którzy mieli spotkania medyczne (na przykład wizytę lekarską, procedurę)
    • providers określa, którzy dostawcy usług medycznych opiekowali się pacjentami

    Tabela encounters rozwiązuje relację wiele-do-wielu między patients i providers i może być opisana jako jednostka asocjacyjna :

    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. Znajdź relacje między tabelami przy użyciu funkcji find_relationships biblioteki SemPy:

    suggested_relationships = find_relationships([patients, providers, encounters])
    suggested_relationships
    
  3. Wizualizowanie ramki danych relacji jako grafu przy użyciu funkcji plot_relationship_metadata biblioteki SemPy.

    plot_relationship_metadata(suggested_relationships)
    

    Zrzut ekranu przedstawiający relacje między tabelami w zestawie danych.

    Funkcja określa hierarchię relacji od lewej strony do prawej strony, która odpowiada tabelom "from" i "to" w danych wyjściowych. Innymi słowy, niezależne tabele "from" po lewej stronie używają kluczy obcych, aby wskazać tabele zależności "do" po prawej stronie. Każde pole jednostki zawiera kolumny, które uczestniczą w relacji "od" lub "do".

    Domyślnie relacje są generowane jako "m:1" (nie jako "1:m") lub "1:1". Relacje "1:1" można wygenerować na jeden lub oba sposoby, w zależności od tego, czy stosunek wartości zamapowanych do wszystkich wartości przekracza coverage_threshold w jednym lub obu kierunkach. W dalszej części tego samouczka omówisz mniej częste przypadki relacji "m:m".

Rozwiązywanie problemów z wykrywaniem relacji

W przykładzie odniesienia pokazano udane wykrywanie relacji na czystych danych Synthea. W praktyce dane są rzadko czyste, co uniemożliwia pomyślne wykrywanie. Istnieje kilka technik, które mogą być przydatne, gdy dane nie są czyste.

Ta sekcja tego samouczka dotyczy wykrywania relacji, gdy model semantyczny zawiera zanieczyszczone dane.

  1. Zacznij od manipulowania oryginalnymi ramkami danych w celu uzyskania "brudnych" danych i wydrukowania rozmiaru zanieczyszczonych danych.

    # 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. Dla porównania rozmiary wydruku oryginalnych tabel:

    print(len(patients))
    print(len(providers))
    
  3. Znajdź relacje między tabelami przy użyciu funkcji find_relationships biblioteki SemPy:

    find_relationships([patients_dirty, providers_dirty, encounters])
    

    Dane wyjściowe kodu pokazują, że nie wykryto żadnych relacji z powodu błędów, które zostały wprowadzone wcześniej w celu utworzenia modelu semantycznego "brudnego".

Korzystanie z walidacji

Walidacja to najlepsze narzędzie do rozwiązywania problemów z błędami wykrywania relacji, ponieważ:

  • Raportuje jasno, dlaczego określona relacja nie jest zgodna z regułami klucza obcego i dlatego nie można jej wykryć.
  • Działa szybko z dużymi modelami semantycznymi, ponieważ koncentruje się tylko na zadeklarowanych relacjach i nie wykonuje wyszukiwania.

Walidacja może używać dowolnej ramki danych z kolumnami podobnymi do tej wygenerowanej przez find_relationships. W poniższym kodzie ramka danych suggested_relationships odnosi się do patients, a nie patients_dirty, ale można przypisać aliasy ramkom danych za pomocą słownika.

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

errors = list_relationship_violations(dirty_tables, suggested_relationships)
errors

Luźne kryteria wyszukiwania

W bardziej mętnych scenariuszach możesz spróbować poluzować kryteria wyszukiwania. Ta metoda zwiększa możliwość fałszywie dodatnich wyników.

  1. Ustaw include_many_to_many=True i oceń, czy pomaga:

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

    Wyniki pokazują, że wykryto relację z encounters do patients, ale występują dwa problemy:

    • Relacja wskazuje kierunek od patients do encounters, który jest odwrotnością oczekiwanej relacji. Dzieje się tak, ponieważ wszystkie patients okazały się objęte przez encounters (Coverage From wynosi 1,0), podczas gdy encounters są objęte tylko częściowo przez patients (Coverage To = 0,85), ponieważ brakuje wierszy dotyczących pacjentów.
    • Istnieje przypadkowe dopasowanie w kolumnie GENDER o niskiej kardynalności, która dopasowuje się nazwą i wartością w obu tabelach, ale nie jest to interesująca relacja "m:1". Niska kardynalność jest wskazywana przez kolumny Unique Count From i Unique Count To.
  2. Ponownie uruchom find_relationships, aby wyszukiwać tylko relacje "m:1", ale z niższym coverage_threshold=0.5:

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

    Wynik przedstawia prawidłowy kierunek relacji z encounters do providers. Jednak relacja z encounters do patients nie jest wykrywana, ponieważ patients nie jest unikalna, więc nie może być po stronie "Jeden" w relacji "m:1".

  3. Poluzuj zarówno include_many_to_many=True, jak i coverage_threshold=0.5:

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

    Teraz obie relacje zainteresowania są widoczne, ale jest o wiele więcej szumu:

    • Dopasowanie o niskiej kardynalności dla GENDER jest obecne.
    • Na ORGANIZATION pojawiło się dopasowanie o wyższej kardynalności "m:m", co sprawia, że kolumna ORGANIZATION prawdopodobnie jest zdenormalizowana do obu tabel.

Dopasowywanie nazw kolumn

Domyślnie narzędzie SemPy traktuje jako dopasowania tylko atrybutów, które pokazują podobieństwo nazw, korzystając z faktu, że projektanci baz danych zwykle nazywają powiązane kolumny w taki sam sposób. To zachowanie pomaga uniknąć fałszywych relacji, które występują najczęściej z kluczami liczb całkowitych o niskiej kardynalności. Jeśli na przykład istnieją 1,2,3,...,10 kategorii produktów i 1,2,3,...,10 kod stanu zamówienia, będą one mylić się ze sobą tylko podczas przeglądania mapowań wartości bez uwzględniania nazw kolumn. Pozorne związki nie powinny być problemem z kluczami typu GUID.

Narzędzie SemPy analizuje podobieństwo między nazwami kolumn i nazwami tabel. Dopasowanie jest przybliżone i bez uwzględniania wielkości liter. Ignoruje on najczęściej spotykane podciągy "decorator", takie jak "id", "code", "name", "key", "pk", "fk". W rezultacie najbardziej typowe przypadki dopasowania to:

  • atrybut o nazwie "column" w encji "foo" pasuje do atrybutu o nazwie "column" (także "COLUMN" lub "Column") w encji "bar".
  • atrybut o nazwie "column" w jednostce "foo" pasuje do atrybutu o nazwie "column_id" w 'bar'.
  • atrybut o nazwie "bar" w jednostce "foo" pasuje do atrybutu o nazwie "code" na pasku.

Najpierw dopasowując nazwy kolumn, wykrywanie przebiega szybciej.

  1. Dopasuj nazwy kolumn:

    • Aby zrozumieć, które kolumny są wybrane do dalszej oceny, użyj opcji verbose=2 (verbose=1 wyświetla tylko przetwarzane jednostki).
    • Parametr name_similarity_threshold określa sposób porównywania kolumn. Próg 1 wskazuje, że interesuje Cię tylko 100% dopasowania.
    find_relationships(dirty_tables, verbose=2, name_similarity_threshold=1.0);
    

    Uruchamianie z podobieństwem 100% nie uwzględnia drobnych różnic między nazwami. W tym przykładzie tabele mają postać mnogią z sufiksem "s", co nie powoduje dokładnego dopasowania. Jest to dobrze obsługiwane z domyślnym name_similarity_threshold=0.8.

  2. Uruchom ponownie przy użyciu domyślnego name_similarity_threshold=0.8:

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

    Zwróć uwagę, że identyfikator liczby mnogiej patients jest teraz porównywany z liczbą pojedynczą patient bez dodawania zbyt wielu innych niepotrzebnych porównań do czasu wykonywania.

  3. Uruchom ponownie przy użyciu domyślnego name_similarity_threshold=0:

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

    Zmiana name_similarity_threshold na 0 jest drugą skrajnością i wskazuje, że chcesz porównać wszystkie kolumny. Rzadko jest to konieczne i skutkuje wydłużonym czasem wykonywania oraz fałszywymi dopasowaniami, które należy przejrzeć. Obserwuj liczbę porównań w pełnych danych wyjściowych.

Podsumowanie porad dotyczących rozwiązywania problemów

  1. Zacznij od dokładnego dopasowania relacji "m:1" (czyli domyślnych include_many_to_many=False i coverage_threshold=1.0). Jest to zwykle to, co chcesz.
  2. Użyj wąskiego fokusu na mniejszych podzestawach tabel.
  3. Użyj walidacji, aby wykryć problemy z jakością danych.
  4. Użyj verbose=2, jeśli chcesz zrozumieć, które kolumny są brane pod uwagę w kontekście relacji. Może to spowodować dużą ilość danych wyjściowych.
  5. Należy zwrócić uwagę na kompromisy, które mogą wynikać z użycia argumentów wyszukiwania. include_many_to_many=True i coverage_threshold<1.0 mogą generować fałszywe relacje, które mogą być trudniejsze do przeanalizowania i muszą być filtrowane.

Wykrywanie relacji w pełnym zestawie danych Synthea

Prosty przykład punktu odniesienia to wygodne narzędzie do uczenia się i rozwiązywania problemów. W praktyce można zacząć od modelu semantycznego, takiego jak pełny zestaw danych Synthea, który zawiera o wiele więcej tabel. Zapoznaj się z pełnym zestawem danych synthea w następujący sposób.

  1. Odczytaj wszystkie pliki z katalogu 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. Znajdź relacje między tabelami przy użyciu funkcji find_relationships biblioteki SemPy:

    suggested_relationships = find_relationships(all_tables)
    suggested_relationships
    
  3. Wizualizacja relacji:

    plot_relationship_metadata(suggested_relationships)
    

    Zrzut ekranu przedstawiający relacje między tabelami.

  4. Zlicz, ile nowych relacji "m:m" zostanie odnalezionych przy użyciu include_many_to_many=True. Te relacje są dodatkiem do poprzednio wyświetlanych relacji "m:1"; w związku z tym należy filtrować według multiplicity:

    suggested_relationships = find_relationships(all_tables, coverage_threshold=1.0, include_many_to_many=True) 
    suggested_relationships[suggested_relationships['Multiplicity']=='m:m']
    
  5. Dane relacji można sortować według różnych kolumn, aby lepiej zrozumieć ich charakter. Na przykład można wybrać kolejność danych wyjściowych według Row Count From i Row Count To, co pomaga zidentyfikować największe tabele.

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

    W innym modelu semantycznym warto skupić się na liczbie wartości null Null Count From lub Coverage To.

    Ta analiza może pomóc w zrozumieniu, czy którakolwiek z relacji może być nieprawidłowa, a jeśli trzeba je usunąć z listy kandydatów.

Zapoznaj się z innymi samouczkami dotyczącymi linku semantycznego /SemPy: