Tutorial: Descubra relações no conjunto de dados Synthea, usando link semântico
Este tutorial ilustra como detetar relações no conjunto de dados público Synthea , usando link semântico.
Quando você está trabalhando com novos dados ou sem um modelo de dados existente, pode ser útil descobrir relacionamentos automaticamente. Essa deteção de relacionamento pode ajudá-lo a:
- compreender o modelo a um nível elevado,
- obter mais informações durante a análise exploratória de dados,
- validar dados atualizados ou dados novos recebidos e
- dados limpos.
Mesmo que os relacionamentos sejam conhecidos antecipadamente, uma busca por relacionamentos pode ajudar com uma melhor compreensão do modelo de dados ou a identificação de problemas de qualidade de dados.
Neste tutorial, você começa com um exemplo de linha de base simples onde experimenta apenas três tabelas para que as conexões entre elas sejam fáceis de seguir. Em seguida, você mostra um exemplo mais complexo com um conjunto de tabelas maior.
Neste tutorial, irá aprender a:
- Use componentes da biblioteca Python (SemPy) do link semântico que suportam a integração com o Power BI e ajudam a automatizar a análise de dados. Esses componentes incluem:
- FabricDataFrame - uma estrutura semelhante a pandas aprimorada com informações semânticas adicionais.
- Funções para extrair modelos semânticos de um espaço de trabalho do Fabric para o seu bloco de anotações.
- Funções que automatizam a descoberta e visualização de relacionamentos em seus modelos semânticos.
- Solucione problemas do processo de descoberta de relacionamentos para modelos semânticos com várias tabelas e interdependências.
Pré-requisitos
Obtenha uma assinatura do Microsoft Fabric. Ou inscreva-se para uma avaliação gratuita do Microsoft Fabric.
Entre no Microsoft Fabric.
Use o seletor de experiência no lado esquerdo da sua página inicial para alternar para a experiência Synapse Data Science.
- Selecione Espaços de trabalho no painel de navegação esquerdo para localizar e selecionar seu espaço de trabalho. Este espaço de trabalho torna-se o seu espaço de trabalho atual.
Acompanhe no caderno
O notebook relationships_detection_tutorial.ipynb acompanha este tutorial.
Para abrir o bloco de anotações que acompanha este tutorial, siga as instruções em Preparar seu sistema para tutoriais de ciência de dados, para importar o bloco de anotações para seu espaço de trabalho.
Se preferir copiar e colar o código desta página, pode criar um novo bloco de notas.
Certifique-se de anexar um lakehouse ao bloco de anotações antes de começar a executar o código.
Configurar o bloco de notas
Nesta seção, você configura um ambiente de notebook com os módulos e dados necessários.
Instale
SemPy
a partir do PyPI usando o%pip
recurso de instalação em linha no notebook:%pip install semantic-link
Execute as importações necessárias de módulos SemPy que você precisará mais tarde:
import pandas as pd from sempy.samples import download_synthea from sempy.relationships import ( find_relationships, list_relationship_violations, plot_relationship_metadata )
Importe pandas para impor uma opção de configuração que ajude na formatação de saída:
import pandas as pd pd.set_option('display.max_colwidth', None)
Puxe os dados de exemplo. Para este tutorial, você usa o conjunto de dados Synthea de registros médicos sintéticos (versão pequena para simplificar):
download_synthea(which='small')
Detetar relações em um pequeno subconjunto de tabelas Synthea
Selecione três tabelas de um conjunto maior:
patients
especifica as informações do pacienteencounters
especifica os pacientes que tiveram encontros médicos (por exemplo, uma consulta médica, procedimento)providers
especifica quais os prestadores de cuidados médicos que atenderam os doentes
A
encounters
tabela resolve uma relação muitos-para-muitos entrepatients
eproviders
pode ser descrita como uma entidade associativa:patients = pd.read_csv('synthea/csv/patients.csv') providers = pd.read_csv('synthea/csv/providers.csv') encounters = pd.read_csv('synthea/csv/encounters.csv')
Encontre relações entre as tabelas usando a função do
find_relationships
SemPy:suggested_relationships = find_relationships([patients, providers, encounters]) suggested_relationships
Visualize as relações DataFrame como um gráfico, usando a função do
plot_relationship_metadata
SemPy.plot_relationship_metadata(suggested_relationships)
A função estabelece a hierarquia de relacionamento do lado esquerdo para o lado direito, que corresponde às tabelas "de" e "para" na saída. Em outras palavras, as tabelas independentes "de" no lado esquerdo usam suas chaves estrangeiras para apontar para suas tabelas de dependência "para" no lado direito. Cada caixa de entidade mostra colunas que participam no lado "de" ou "para" de uma relação.
Por padrão, as relações são geradas como "m:1" (não como "1:m") ou "1:1". As relações "1:1" podem ser geradas de uma ou ambas as maneiras, dependendo se a proporção de valores mapeados para todos os valores excede
coverage_threshold
em apenas uma ou ambas as direções. Mais adiante neste tutorial, você abordará o caso menos frequente de relacionamentos "m:m".
Solucionar problemas de deteção de relacionamento
O exemplo de linha de base mostra uma deteção de relacionamento bem-sucedida em dados Synthea limpos. Na prática, os dados raramente são limpos, o que impede uma deteção bem-sucedida. Existem várias técnicas que podem ser úteis quando os dados não estão limpos.
Esta seção deste tutorial aborda a deteção de relacionamento quando o modelo semântico contém dados sujos.
Comece manipulando os DataFrames originais para obter dados "sujos" e imprima o tamanho dos dados sujos.
# 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))
Para comparação, tamanhos de impressão das tabelas originais:
print(len(patients)) print(len(providers))
Encontre relações entre as tabelas usando a função do
find_relationships
SemPy:find_relationships([patients_dirty, providers_dirty, encounters])
A saída do código mostra que não há relações detetadas devido aos erros introduzidos anteriormente para criar o modelo semântico "sujo".
Validação de uso
A validação é a melhor ferramenta para solucionar problemas de falhas de deteção de relacionamento porque:
- Ele relata claramente por que um relacionamento específico não segue as regras da Chave Estrangeira e, portanto, não pode ser detetado.
- Ele é executado rapidamente com grandes modelos semânticos porque se concentra apenas nas relações declaradas e não realiza uma pesquisa.
A validação pode usar qualquer DataFrame com colunas semelhantes à gerada pelo find_relationships
. No código a seguir, o suggested_relationships
DataFrame refere-se a patients
em vez de patients_dirty
, mas você pode alias os DataFrames com um dicionário:
dirty_tables = {
"patients": patients_dirty,
"providers" : providers_dirty,
"encounters": encounters
}
errors = list_relationship_violations(dirty_tables, suggested_relationships)
errors
Afrouxar os critérios de pesquisa
Em cenários mais obscuros, você pode tentar afrouxar seus critérios de pesquisa. Este método aumenta a possibilidade de falsos positivos.
Defina
include_many_to_many=True
e avalie se isso ajuda:find_relationships(dirty_tables, include_many_to_many=True, coverage_threshold=1)
Os resultados mostram que a relação de
encounters
parapatients
foi detetada, mas há dois problemas:- A relação indica uma direção de
patients
paraencounters
, que é um inverso da relação esperada. Isso ocorre porque todospatients
foram cobertos porencounters
(Coverage From
é 1,0) enquantoencounters
são apenas parcialmente cobertos porpatients
(Coverage To
= 0,85), uma vez que as filas de pacientes estão faltando. - Há uma correspondência acidental em uma coluna de cardinalidade
GENDER
baixa, que acontece de corresponder por nome e valor em ambas as tabelas, mas não é uma relação de interesse "m:1". A cardinalidade baixa é indicada porUnique Count From
eUnique Count To
colunas.
- A relação indica uma direção de
Execute
find_relationships
novamente para procurar apenas relações "m:1", mas com um menorcoverage_threshold=0.5
:find_relationships(dirty_tables, include_many_to_many=False, coverage_threshold=0.5)
O resultado mostra a direção correta das relações de
encounters
atéproviders
. No entanto, a relação deencounters
parapatients
não é detetada, porquepatients
não é única, então não pode estar no lado "Um" da relação "m:1".Solte ambos
include_many_to_many=True
ecoverage_threshold=0.5
:find_relationships(dirty_tables, include_many_to_many=True, coverage_threshold=0.5)
Agora ambas as relações de interesse são visíveis, mas há muito mais ruído:
- O jogo de baixa cardinalidade está
GENDER
presente. - Uma correspondência de cardinalidade mais alta "m:m" apareceu
ORGANIZATION
, tornando aparente que é provável queORGANIZATION
uma coluna seja desnormalizada para ambas as tabelas.
- O jogo de baixa cardinalidade está
Corresponder nomes de colunas
Por padrão, o SemPy considera como correspondências apenas atributos que mostram semelhança de nomes, aproveitando o fato de que os designers de banco de dados geralmente nomeiam colunas relacionadas da mesma maneira. Esse comportamento ajuda a evitar relacionamentos espúrios, que ocorrem com mais frequência com chaves inteiras de baixa cardinalidade. Por exemplo, se houver 1,2,3,...,10
categorias de produtos e 1,2,3,...,10
código de status do pedido, eles serão confundidos uns com os outros quando apenas olharem para mapeamentos de valor sem levar em conta os nomes das colunas. Relações espúrias não devem ser um problema com chaves semelhantes a GUID.
O SemPy analisa uma semelhança entre nomes de colunas e nomes de tabelas. A correspondência é aproximada e não diferencia maiúsculas de minúsculas. Ele ignora as substrings "decorador" mais frequentemente encontradas, como "id", "code", "name", "key", "pk", "fk". Como resultado, os casos de correspondência mais típicos são:
- um atributo chamado 'coluna' na entidade 'foo' corresponde a um atributo chamado 'coluna' (também 'COLUNA' ou 'Coluna') na entidade 'bar'.
- Um atributo chamado 'coluna' na entidade 'foo' corresponde a um atributo chamado 'column_id' em 'barra'.
- Um atributo chamado 'bar' na entidade 'foo' corresponde a um atributo chamado 'code' em 'bar'.
Ao corresponder os nomes das colunas primeiro, a deteção é executada mais rapidamente.
Corresponder aos nomes das colunas:
- Para entender quais colunas são selecionadas para avaliação posterior, use a
verbose=2
opção (verbose=1
lista apenas as entidades que estão sendo processadas). - O
name_similarity_threshold
parâmetro determina como as colunas são comparadas. O limite de 1 indica que você está interessado apenas em 100% de correspondência.
find_relationships(dirty_tables, verbose=2, name_similarity_threshold=1.0);
Correr a 100% de semelhança não leva em conta pequenas diferenças entre os nomes. No seu exemplo, as tabelas têm uma forma plural com sufixo "s", o que resulta em nenhuma correspondência exata. Isso é bem tratado com o padrão
name_similarity_threshold=0.8
.- Para entender quais colunas são selecionadas para avaliação posterior, use a
Execute novamente com o padrão
name_similarity_threshold=0.8
:find_relationships(dirty_tables, verbose=2, name_similarity_threshold=0.8);
Observe que o Id para a forma
patients
plural agora é comparado ao singularpatient
sem adicionar muitas outras comparações espúrias ao tempo de execução.Execute novamente com o padrão
name_similarity_threshold=0
:find_relationships(dirty_tables, verbose=2, name_similarity_threshold=0);
Mudar
name_similarity_threshold
para 0 é o outro extremo e indica que você deseja comparar todas as colunas. Isso raramente é necessário e resulta em maior tempo de execução e partidas espúrias que precisam ser revistas. Observe o número de comparações na saída detalhada.
Resumo das dicas de solução de problemas
- Comece a partir da correspondência exata para relações "m:1" (ou seja, o padrão
include_many_to_many=False
ecoverage_threshold=1.0
). Isso geralmente é o que você quer. - Use um foco estreito em subconjuntos menores de tabelas.
- Use a validação para detetar problemas de qualidade de dados.
- Use
verbose=2
se quiser entender quais colunas são consideradas para relacionamento. Isso pode resultar em uma grande quantidade de saída. - Esteja ciente das compensações dos argumentos de pesquisa.
include_many_to_many=True
ecoverage_threshold<1.0
pode produzir relações espúrias que podem ser mais difíceis de analisar e precisarão ser filtradas.
Detetar relações no conjunto de dados Synthea completo
O exemplo de linha de base simples foi uma ferramenta conveniente de aprendizagem e solução de problemas. Na prática, você pode começar a partir de um modelo semântico, como o conjunto de dados Synthea completo, que tem muito mais tabelas. Explore o conjunto de dados synthea completo da seguinte maneira.
Leia todos os arquivos do diretório 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'), }
Encontre relações entre as tabelas, usando a função do
find_relationships
SemPy:suggested_relationships = find_relationships(all_tables) suggested_relationships
Visualize relacionamentos:
plot_relationship_metadata(suggested_relationships)
Conte quantas novas relações "m:m" serão descobertas com
include_many_to_many=True
o . Estas relações são adicionais às relações "m:1" mostradas anteriormente; portanto, você tem que filtrar emmultiplicity
:suggested_relationships = find_relationships(all_tables, coverage_threshold=1.0, include_many_to_many=True) suggested_relationships[suggested_relationships['Multiplicity']=='m:m']
Você pode classificar os dados de relacionamento por várias colunas para obter uma compreensão mais profunda de sua natureza. Por exemplo, você pode optar por ordenar a saída por
Row Count From
eRow Count To
, que ajudam a identificar as tabelas maiores.suggested_relationships.sort_values(['Row Count From', 'Row Count To'], ascending=False)
Em um modelo semântico
Null Count From
diferente, talvez fosse importante focar no número de nulos ouCoverage To
.Essa análise pode ajudá-lo a entender se algum dos relacionamentos pode ser inválido e se você precisa removê-los da lista de candidatos.
Conteúdos relacionados
Confira outros tutoriais para link semântico / SemPy: