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, você aprenderá a:
- Use componentes da biblioteca Python do link semântico (SemPy) 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 notebook.
- 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 Microsoft Fabric. Ou inscreva-se para obter uma avaliação gratuita do Microsoft Fabric.
Inicie sessão em Microsoft Fabric.
Use o seletor de experiência no canto inferior esquerdo da página inicial para alternar para o Fabric.
- Selecione Workspaces 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 caderno relationships_detection_tutorial.ipynb acompanha este tutorial.
Para abrir o bloco de anotações que acompanha este tutorial, siga as instruções em Preparar o seu sistema para tutoriais de ciência de dados para importar o bloco de anotações para o 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* a um bloco de anotações antes de começar a executar o código.
Configurar o portátil
Nesta seção, você configura um ambiente de notebook com os módulos e dados necessários.
Instale
SemPy
do PyPI usando a capacidade de instalação em linha%pip
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 Synthea conjunto de dados de registros médicos sintéticos (versão pequena para simplificar):
download_synthea(which='small')
Detetar relações num pequeno subconjunto de tabelas Synthea de
Selecione três tabelas de um conjunto maior:
-
patients
especifica as informações do paciente -
encounters
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 tabela
encounters
resolve uma relação muitos-para-muitos entrepatients
eproviders
e 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
find_relationships
do SemPy:suggested_relationships = find_relationships([patients, providers, encounters]) suggested_relationships
Visualize as relações DataFrame como um gráfico, usando a função
plot_relationship_metadata
do 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" na parte esquerda utilizam as suas chaves estrangeiras para referir-se às suas tabelas de dependência "para" na parte direita. 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 relações
O exemplo de referência mostra um reconhecimento de padrões bem-sucedido 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
find_relationships
do 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".
Utilizar validação
A validação é a melhor ferramenta para solucionar problemas de falhas de deteção de relacionamento porque:
- Relata claramente por que um relacionamento específico não segue as regras da chave estrangeira e, portanto, não é possível 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 por 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 todos ospatients
passaram a ser cobertos porencounters
(Coverage From
é 1,0) enquantoencounters
são apenas parcialmente cobertos porpatients
(Coverage To
= 0,85), uma vez que faltam filas de pacientes. - Ocorre uma correspondência acidental numa coluna
GENDER
de baixa cardinalidade, que acontece de coincidir por nome e valor em ambas as tabelas, mas não se trata de uma relação 'm:1' de interesse. A cardinalidade baixa é indicada pelas colunasUnique Count From
eUnique Count To
.
- A relação indica uma direção de
Execute novamente
find_relationships
para procurar apenas relações "m:1", mas com umcoverage_threshold=0.5
mais baixo: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
paraproviders
. 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 tanto
include_many_to_many=True
quantocoverage_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:
- Existe uma correspondência de baixa cardinalidade em
GENDER
. - Uma correspondência de cardinalidade mais alta "m:m" em
ORGANIZATION
apareceu, indicando claramente queORGANIZATION
é provavelmente uma coluna desnormalizada em ambas as tabelas.
- Existe uma correspondência de baixa cardinalidade em
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ódigos de status do pedido, poderão ser confundidos entre si ao se olhar apenas para os 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' identifica-se com um atributo chamado "coluna" (também "COLUNA" ou "Coluna") na entidade 'bar'.
- Um atributo chamado 'coluna' na entidade 'foo' alinha-se com um atributo chamado 'column_id' em 'bar'.
- Um atributo chamado 'bar' na entidade 'foo' corresponde a um atributo denominado 'code' em 'bar'.
Ao corresponder os nomes das colunas primeiro, a deteção é executada mais rapidamente.
Faça corresponder os nomes das colunas:
- Para entender quais colunas são selecionadas para avaliação posterior, use a opção
verbose=2
(verbose=1
lista apenas as entidades que estão sendo processadas). - O parâmetro
name_similarity_threshold
determina como as colunas são comparadas. O limiar de 1 indica que está interessado apenas em 100 correspondências%.
find_relationships(dirty_tables, verbose=2, name_similarity_threshold=1.0);
Executar com 100% de semelhança% não considera 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
name_similarity_threshold=0.8
padrão.- Para entender quais colunas são selecionadas para avaliação posterior, use a opção
Execute novamente com o
name_similarity_threshold=0.8
padrão :find_relationships(dirty_tables, verbose=2, name_similarity_threshold=0.8);
Observe que o Id para a forma plural
patients
agora é comparado aopatient
singular sem adicionar muitas outras comparações espúrias ao tempo de execução.Execute novamente com o
name_similarity_threshold=0
padrão :find_relationships(dirty_tables, verbose=2, name_similarity_threshold=0);
Alterar
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, as
include_many_to_many=False
ecoverage_threshold=1.0
padrão). 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
para entender quais colunas são consideradas para relacionamento. Isso pode resultar numa grande quantidade de resultados. - Esteja ciente das compensações dos argumentos de pesquisa.
include_many_to_many=True
ecoverage_threshold<1.0
podem 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 completo do Synthea
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 completo Synthea, que tem muito mais tabelas. Explore o conjunto de dados completo synthea 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
find_relationships
do 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
. Estas relações são adicionais às relações "m:1" mostradas anteriormente; Portanto, você tem que filtrarmultiplicity
: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 diferente, talvez fosse importante focar no número de nulos
Null Count From
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údo relacionado
Confira outros tutoriais para link semântico / SemPy: