Tutorial: Detección de relaciones en el conjunto de datos de Synthea con el vínculo semántico
En este tutorial se muestra cómo detectar relaciones en el conjunto de datos público de Synthea con el vínculo semántico.
Al trabajar con nuevos datos o sin un modelo de datos existente, puede resultar útil detectar relaciones automáticamente. Esta detección de relaciones puede ayudarle a:
- Comprender el modelo en un nivel alto
- Obtener más información durante el análisis de datos exploratorios
- Validar datos actualizados o nuevos, datos entrantes
- Limpiar datos
Incluso si las relaciones se conocen de antemano, una búsqueda de relaciones puede ayudar a comprender mejor el modelo de datos o la identificación de problemas de calidad de los datos.
En este tutorial, comenzará con un ejemplo de línea base simple en el que experimentará con solo tres tablas para que las conexiones entre ellas sean fáciles de seguir. A continuación, se mostrará un ejemplo más complejo con un conjunto de tablas más grande.
En este tutorial, aprenderá a:
- Utilice los componentes de la biblioteca Python de vínculo semántico (SemPy), que admiten la integración con Power BI y le ayudarán a automatizar el análisis de datos. Estos componentes incluyen:
- FabricDataFrame: una estructura similar a Pandas mejorada con información semántica adicional.
- Funciones para extraer modelos semánticos de un área de trabajo de Fabric en el cuaderno.
- Funciones que automatizan la detección y visualización de relaciones en los modelos semánticos.
- Solución de problemas del proceso de detección de relaciones para modelos semánticos con varias tablas e interdependencias.
Requisitos previos
Obtenga una suscripción a Microsoft Fabric. También puede registrarse para obtener una evaluación gratuita de Microsoft Fabric.
Inicie sesión en Microsoft Fabric.
Cambie a la experiencia de ciencia de datos de Synapse mediante el conmutador de experiencia en el lado izquierdo de la página principal.
- Seleccione Áreas de trabajo en el panel de navegación izquierdo para buscar y seleccionar el área de trabajo. Esta área de trabajo se convertirá en el área de trabajo actual.
Seguimiento en el cuaderno
El cuaderno relationships_detection_tutorial.ipynb acompaña a este tutorial.
Para abrir el cuaderno complementario para este tutorial, siga las instrucciones en Preparación del sistema para los tutoriales de ciencia de datos para importar el cuaderno en el área de trabajo.
Si prefiere copiar y pegar el código de esta página, puede crear un cuaderno nuevo.
Asegúrese de adjuntar una instancia de LakeHouse al cuaderno antes de empezar a ejecutar código.
Configuración del cuaderno
En esta sección, configurará un entorno de cuaderno con los módulos y los datos necesarios.
Instale
SemPy
desde PyPI mediante la funcionalidad de instalación en línea%pip
en el cuaderno:%pip install semantic-link
Realice las importaciones necesarias de módulos SemPy que necesitará más adelante:
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 aplicar una opción de configuración que ayude con el formato de salida:
import pandas as pd pd.set_option('display.max_colwidth', None)
Incorpore los datos de ejemplo. En este tutorial, usará el conjunto de datos de Synthea de registros médicos sintéticos (versión reducida, para simplificar):
download_synthea(which='small')
Detección de relaciones en un pequeño subconjunto de tablas de Synthea
Seleccione tres tablas de un conjunto mayor:
patients
especifica la información de los pacientes.encounters
especifica los pacientes que tuvieron encuentros médicos (por ejemplo, una cita médica, un procedimiento).providers
especifica qué proveedores médicos asistieron a los pacientes.
La tabla
encounters
resuelve una relación de varios a varios entrepatients
yproviders
, y se puede describir como una entidad asociativa:patients = pd.read_csv('synthea/csv/patients.csv') providers = pd.read_csv('synthea/csv/providers.csv') encounters = pd.read_csv('synthea/csv/encounters.csv')
Busque relaciones entre las tablas mediante la función
find_relationships
de SemPy:suggested_relationships = find_relationships([patients, providers, encounters]) suggested_relationships
Visualice las relaciones de DataFrame como un grafo mediante la función
plot_relationship_metadata
de SemPy.plot_relationship_metadata(suggested_relationships)
La función establece la jerarquía de relaciones desde el lado izquierdo hasta el lado derecho, que corresponde a las tablas de origen y de destino de la salida. En otras palabras, las tablas de origen independientes del lado izquierdo usan sus claves externas para apuntar a sus tablas de dependencias de destino en el lado derecho. Cada cuadro de entidad muestra columnas que participan en el lado de origen o de destino de una relación.
De forma predeterminada, las relaciones se generan como "m:1" (no como "1:m") o "1:1". Las relaciones "1:1" se pueden generar de una o ambas maneras, dependiendo de si la proporción de valores asignados a todos los valores supera
coverage_threshold
en una o ambas direcciones. Más adelante en este tutorial, tratará el caso menos frecuente de relaciones "m:m".
Solución de problemas de detección de relaciones
En el ejemplo de base de referencia se muestra una detección correcta de relaciones en datos limpios de Synthea. En la práctica, los datos rara vez están limpios, lo que impide la detección correcta. Hay varias técnicas que pueden ser útiles cuando los datos no están limpios.
En esta sección de este tutorial se aborda la detección de relaciones cuando el modelo semántico contiene datos sucios.
Comience manipulando los DataFrames originales para obtener datos "sucios" e imprima el tamaño de estos datos.
# 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 comparar, imprima los tamaños de las tablas originales:
print(len(patients)) print(len(providers))
Busque relaciones entre las tablas mediante la función
find_relationships
de SemPy:find_relationships([patients_dirty, providers_dirty, encounters])
La salida del código muestra que no se detectó ninguna relación debido a los errores que introdujo anteriormente para crear el modelo semántico "sucio".
Uso de la validación
La validación es la mejor herramienta para solucionar errores de detección de relaciones porque:
- Informa claramente por qué una relación determinada no sigue las reglas de clave externa y, por lo tanto, no se puede detectar.
- Se ejecuta rápidamente con grandes modelos semánticos debido a que solo se centra en las relaciones declaradas y no realiza una búsqueda.
La validación puede usar cualquier DataFrame con columnas similares a las generadas por find_relationships
. En el código siguiente, el DataFrame suggested_relationships
hace referencia a patients
en lugar de a patients_dirty
, pero puede establecer un alias en los objetos DataFrame con un diccionario:
dirty_tables = {
"patients": patients_dirty,
"providers" : providers_dirty,
"encounters": encounters
}
errors = list_relationship_violations(dirty_tables, suggested_relationships)
errors
Criterios de búsqueda flexibles
En escenarios más confusos, puede intentar flexibilizar los criterios de búsqueda. Este método aumenta la posibilidad de falsos positivos.
Establezca
include_many_to_many=True
y evalúe si ayuda:find_relationships(dirty_tables, include_many_to_many=True, coverage_threshold=1)
Los resultados muestran que se detectó la relación de
encounters
apatients
, pero hay dos problemas:- La relación indica una dirección de
patients
aencounters
, que es la inversa de la relación esperada. Esto se debe a que toda la tablapatients
resultó estar cubierta porencounters
(Coverage From
es 1,0) mientras queencounters
solo está cubierta parcialmente porpatients
(Coverage To
= 0,85), ya que faltan filas de pacientes. - Hay una coincidencia accidental en una columna
GENDER
de cardinalidad baja, que coincide por nombre y valor en ambas tablas, pero no es una relación "m:1" de interés. La cardinalidad baja se indica mediante las columnasUnique Count From
yUnique Count To
.
- La relación indica una dirección de
Vuelva a ejecutar
find_relationships
para buscar solo las relaciones "m:1", pero con un valor decoverage_threshold=0.5
inferior:find_relationships(dirty_tables, include_many_to_many=False, coverage_threshold=0.5)
El resultado muestra la dirección correcta de las relaciones de
encounters
aproviders
. Sin embargo, no se detecta la relación deencounters
apatients
, porquepatients
no es única, por lo que no puede estar en el lado "Uno" de la relación "m:1".Flexibilice tanto
include_many_to_many=True
comocoverage_threshold=0.5
:find_relationships(dirty_tables, include_many_to_many=True, coverage_threshold=0.5)
Ahora ambas relaciones de interés son visibles, pero hay mucho más ruido:
- Está presente una coincidencia de cardinalidad baja en
GENDER
. - Aparece una coincidencia de cardinalidad más alta de "m:m" en
ORGANIZATION
lo que hace que sea evidente queORGANIZATION
se trate probablemente de una columna desnormalizada en ambas tablas.
- Está presente una coincidencia de cardinalidad baja en
Coincidencia de nombres de columna
De forma predeterminada, SemPy considera como coincidencias solo los atributos que muestran similitud de nombres, aprovechando el hecho de que los diseñadores de bases de datos suelen nombrar de la misma manera las columnas relacionadas. Este comportamiento ayuda a evitar relaciones falsas, que se producen con más frecuencia con claves de enteros de cardinalidad baja. Por ejemplo, si hay categorías de producto 1,2,3,...,10
y un código de estado de pedido 1,2,3,...,10
, se confundirán entre sí cuando solo se examinen las asignaciones de valores sin tener en cuenta los nombres de columna. Las relaciones falsas no deberían ser un problema con las claves de tipo GUID.
SemPy busca una similitud entre los nombres de columna y los nombres de tabla. La coincidencia es aproximada y no distingue mayúsculas de minúsculas. Omite las subcadenas de "decorador" más frecuentes, como "id", "code", "name", "key", "pk" o "fk". Como resultado, los casos de coincidencia más típicos son:
- Un atributo denominado "column" en la entidad "foo" coincide con un atributo denominado "column" (también "COLUMN" o "Column") en la entidad "bar".
- Un atributo denominado "column" en la entidad "foo" coincide con un atributo denominado "column_id" en "bar".
- Un atributo denominado "bar" en la entidad "foo" coincide con un atributo denominado "code" en "bar".
Al hacer coincidir primero los nombres de las columnas, la detección se ejecuta más rápidamente.
Hacer coincidir con los nombres de columna:
- Para comprender qué columnas se seleccionan para su posterior evaluación, use la opción
verbose=2
(verbose=1
enumera solo las entidades que se están procesando). - El parámetro
name_similarity_threshold
determina cómo se comparan las columnas. El umbral de 1 indica que solo se está interesado en la coincidencia del 100 %.
find_relationships(dirty_tables, verbose=2, name_similarity_threshold=1.0);
La ejecución con una similitud del 100 % no tiene en cuenta las pequeñas diferencias entre los nombres. En el ejemplo, las tablas tienen un formato plural con sufijo "s", lo que da como resultado una coincidencia exacta. Esto se controla bien con el valor predeterminado
name_similarity_threshold=0.8
.- Para comprender qué columnas se seleccionan para su posterior evaluación, use la opción
Vuelva a ejecutar con el valor predeterminado
name_similarity_threshold=0.8
:find_relationships(dirty_tables, verbose=2, name_similarity_threshold=0.8);
Observe que el identificador para la forma plural
patients
ahora se compara con la singularpatient
sin agregar demasiadas otras comparaciones falsas al tiempo de ejecución.Vuelva a ejecutar con el valor predeterminado
name_similarity_threshold=0
:find_relationships(dirty_tables, verbose=2, name_similarity_threshold=0);
Cambiar
name_similarity_threshold
a 0 es el otro extremo e indica que se quiere comparar todas las columnas. Esto rara vez es necesario y da como resultado un mayor tiempo de ejecución y coincidencias falsas que deben revisarse. Observe el número de comparaciones en la salida detallada.
Resumen de sugerencias de solución de problemas
- Comience desde una coincidencia exacta para las relaciones "m:1" (es decir, los valores predeterminados
include_many_to_many=False
ycoverage_threshold=1.0
). Esto suele ser lo que se quiere. - Use un enfoque restringido en los subconjuntos más pequeños de tablas.
- Utilice la validación para detectar problemas de calidad de datos.
- Use
verbose=2
si quiere comprender qué columnas se consideran para la relación. Esto puede dar lugar a una gran cantidad de valores de salida. - Tenga en cuenta las ventajas y desventajas de los argumentos de búsqueda.
include_many_to_many=True
ycoverage_threshold<1.0
pueden producir relaciones falsas que quizá sean más difíciles de analizar y que deberán filtrarse.
Detección de relaciones en el conjunto de datos completo de Synthea
El ejemplo sencillo de base de referencia fue una cómoda herramienta de aprendizaje y solución de problemas. En la práctica, puede empezar desde un modelo semántico como el conjunto de datos completo de Synthea, que tiene muchas más tablas. Explore el conjunto de datos completo de Synthea como se indica a continuación.
Lea todos los archivos del directorio 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'), }
Busque relaciones entre las tablas mediante la función
find_relationships
de SemPy:suggested_relationships = find_relationships(all_tables) suggested_relationships
Visualice las relaciones:
plot_relationship_metadata(suggested_relationships)
Cuente cuántas relaciones "m:m" nuevas se detectarán con
include_many_to_many=True
. Estas relaciones se agregan a las relaciones "m:1" mostradas anteriormente; por lo tanto, debe filtrar pormultiplicity
:suggested_relationships = find_relationships(all_tables, coverage_threshold=1.0, include_many_to_many=True) suggested_relationships[suggested_relationships['Multiplicity']=='m:m']
Puede ordenar los datos de relación por varias columnas para comprender mejor su naturaleza. Por ejemplo, podría optar por ordenar la salida por
Row Count From
yRow Count To
, lo que ayuda a identificar las tablas más grandes.suggested_relationships.sort_values(['Row Count From', 'Row Count To'], ascending=False)
En un modelo semántico diferente, quizás sería importante centrarse en el número de valores null
Null Count From
oCoverage To
.Este análisis puede ayudarle a comprender si alguna de las relaciones podría no ser válida y si necesita quitarla de la lista de candidatos.
Contenido relacionado
Consulte otros tutoriales para el vínculo semántico/SemPy:
- Tutorial: Limpieza de datos con dependencias funcionales
- Tutorial: Análisis de dependencias funcionales en un modelo semántico de ejemplo
- Tutorial: Detección de relaciones en un modelo semántico mediante el vínculo semántico
- Tutorial: Extracción y cálculo de medidas de Power BI de un cuaderno de Jupyter