Fuzzy Matching en Microsoft Fabric: La solución elegante cuando tus datos "casi" coinciden
- Gabriel Peralta
- hace 16 horas
- 6 Min. de lectura
Actualizado: hace 11 minutos
El dilema de los datos dispares: Cuando "igual" no significa "idéntico"
¿Alguna vez te has encontrado frente a dos conjuntos de datos que deberían encajar perfectamente, pero simplemente no lo hacen? Imagina este escenario: tienes datos de clientes de dos sistemas diferentes. En uno aparece "Ana Torres García, El Ejido" y en el otro "Ana Torres, Ejido". Para ti es evidente que se trata de la misma persona, pero para tu sistema son entidades completamente distintas. Este es el tipo de problema que puede convertir un proyecto de integración de datos aparentemente sencillo en un dolor de cabeza monumental... a menos que conozcas el poder del fuzzy matching
¿Qué es exactamente el Fuzzy Matching?
A diferencia de las comparaciones exactas (donde "Almería" y "Almeria" son tratadas como diferentes), el fuzzy matching evalúa la similitud entre textos, asignando un porcentaje que indica cuán parecidos son. Es como si le dieras a tu sistema la capacidad de decir: "Estos textos son un 95% iguales, probablemente se refieren a lo mismo." En este artículo, te mostraré cómo implementar esta poderosa técnica en Microsoft Fabric para unificar datos que representan la misma información, pero que han sido registrados con ligeras variaciones.
Nuestro caso práctico: Dos listas de contactos que no coinciden
Para este tutorial, trabajaremos con dos archivos CSV que contienen información sobre los mismos contactos, pero estructurados de manera diferente:
Nombre | Primer Apellido | Segundo Apellido | Lugar de Nacimiento |
María | González | Pérez | Almería |
Juan | Martínez | López | Roquetas de Mar |
Ana | Torres | García | El Ejido |
Pedro | Hernádez | Sánchez | Adra |
Lucía | Fernádez | Díaz | Vícar |
Carlos | López | Ruiz | Níjar |
Sofía | Pérez | Torres | Huércal-Overa |
Miguel | Álvarez | Gómez | Vera |
Elena | Sánchez | Moreno | Berja |
José | Ruiz | Castro | Carboneras |
Tabla 1. Datos del primer archivo CSV
Mientras que en el segundo origen los datos en el csv son los que siguen:
Nombre contacto | Ciudad |
María González | Almería |
Juan Martínez | Roquetas |
Ana Torres | Ejido |
Pedro Hernández | Adra |
Lucía Fernández | Vícar |
Carlos López | Níjar |
Sofía Pérez | Huércal |
Miguel Álvarez | Vera |
Elena Sánchez | Berja |
José Ruiz | Carboneras |
Tabla 2. Datos del segundo archivo CSV
Como puedes observar, no solo la estructura es diferente, sino que la información misma presenta variaciones: - "Roquetas de Mar" vs "Roquetas" - "El Ejido" vs "Ejido" - "Almería" vs "Almeria" (sin tilde) Además, no existe un identificador único (como un ID de cliente) que permita relacionar ambas fuentes de manera confiable. Es aquí donde el fuzzy matching se convierte en nuestro mejor aliado.
Preparando el entorno en Microsoft Fabric
Antes de sumergirnos en el código, necesitamos configurar nuestro entorno de trabajo en Microsoft Fabric:
Paso 1: Crear un Lakehouse
El Lakehouse nos permitirá almacenar y procesar nuestros archivos CSV de manera eficiente: 1. Accede a tu workspace de Fabric 2. Selecciona "Crear" → "Lakehouse" en la sección "Almacenar datos" 3. Asigna un nombre descriptivo y haz clic en "Crear"
Paso 2: Cargar los archivos CSV
Una vez creado el Lakehouse: 1. Haz clic en "Cargar archivos" 2. Selecciona tus archivos CSV 3. Verifica que los archivos aparezcan en la carpeta "Files" de tu Lakehouse
Paso 3: Crear un Notebook
Para ejecutar nuestro análisis: 1. Vuelve a "Crear" y esta vez selecciona "Notebook" en la sección "Análisis y entrenamiento de datos" 2. Asegúrate de que el lenguaje seleccionado sea "PySpark (Python)" 3. Conecta el notebook a tu Lakehouse desde la opción "Agregar orígenes de datos" ¡Y ya estamos listos para empezar a escribir código!
El código: Haciendo magia con Fuzzy Matching
En primer lugar, deben de instalarse las librerías que se requieran y no disponga el kernel sobre el que se ejecuta el notebook de forma predeterminada. En este caso, se añadirá la librería fuzzywuzzy que proporciona los algoritmos de comparación aproximada:
!pip install fuzzywuzzy
Requirement already satisfied: fuzzywuzzy in /home/trusted-service-user/cluster-env/trident_env/lib/python3.11/site-packages (0.18.0)
A continuación, se cargan las librerías a utilizar: - PySpark.sql.functions para importar funciones que facilitan el procesamiento de los dataframes. - Fuzzywuzzy para realizar la comparación de los datos y obtener porcentajes de equidad.
from pyspark.sql.functions import concat_ws, lower, trim, udf
from fuzzywuzzy import fuzz
Llegó el momento de leer los datos, para lo que se necesita conocer la ruta en la que se encuentran. Dado que se ha conectado el lakehouse al notebook y se utilizará PySpark se puede aprovechar la ruta relativa que ofrece el archivo. Para ello, navegar a la sección Files, clicar sobre el icono de tres puntos (···) asociado al archivo y obtener la ruta relativa para Spark.
ruta_jugadores1 = 'Files/datos_1.csv'
ruta_jugadores2 = 'Files/datos_2.csv'
df1 = spark.read.option("header", "true").csv(ruta_jugadores1)
df2 = spark.read.option("header", "true").csv(ruta_jugadores2)
A continuación, se va a hacer un preprocesamiento de los datos en el que se transformarán en un formato uniforme de manera que la comparación sea lo más eficaz posible:
# Combinar nombre y lugar en una sola cadena
combined_expr1 = concat_ws(" ", df1["Nombre"], df1["Primer Apellido"], df1["Segundo Apellido"], df1["Lugar de Nacimiento"])
combined_expr2 = concat_ws(" ", df2["Nombre contacto"], df2["Ciudad"])
# Generar dataframe combinado de cada origen de datos habiendo convertido todo a minúsculas y limpiando espacios en blanco
df1_combined = df1.withColumn("Combined", lower(trim(combined_expr1)))
df2_combined = df2.withColumn("Combined", lower(trim(combined_expr2)))
En este punto es necesario aclarar qué son lo que se conoce por las siglas UDF dentro del ecosistema de PySpark. Las UDF (User-Defined Functions, o Funciones Definidas por el Usuario) son una característica que permite definir funciones personalizadas en Python y aplicarlas a columnas de un DataFrame de Spark. En este caso, se usan para calcular la similitud entre cadenas con la librería fuzzywuzzy, ya que Spark no tiene una función nativa para fuzzy matching. Aquí es donde realmente brilla nuestra solución. Utilizaremos una udf para calcular la similitud entre las cadenas combinadas:
# Definir UDF para similitud combinada
fuzzy_combined_udf = udf(lambda x, y: fuzz.token_sort_ratio(x, y), IntegerType())
# Cruzar y calcular similitud
matched_df = df1_combined.crossJoin(df2_combined).withColumn(
"Similarity", fuzzy_combined_udf(df1_combined["Combined"], df2_combined["Combined"])
)
# Filtrar por umbral del 70%
resultado = matched_df.filter(matched_df["Similarity"] > 70).orderBy("Similarity", ascending=False)
# Mostrar resultados
display(resultado)
¿Qué está pasando aquí exactamente? 1. Creamos una función (fuzzy_combined_udf) que utiliza el algoritmo token_sort_ratio para comparar dos cadenas de texto 2. Realizamos un "cross join" para comparar cada fila del primer conjunto con cada fila del segundo 3. Calculamos el porcentaje de similitud para cada par 4. Filtramos aquellos pares que superen el 70% de similitud 5. Ordenamos los resultados por similitud descendente El algoritmo token_sort_ratio es especialmente útil porque considera las palabras como "tokens" independientemente de su orden, lo que permite manejar casos como "Juan Martínez López" vs "Martínez Juan". Con la ejecución del código se obtienen los resultados de la tabla siguiente:
Nombre | Primer Apellido | Segundo Apellido | Lugar de nacimiento | Similarity | Combined | Nombre contacto | Ciudad | Combined |
Lucía | Fernández | Díaz | Vícar | 90 | lucía fernández díaz vícar | Lucía Fernández | Vícar | lucía fernández vícar |
Miguel | Álvarez | Gómez | Vera | 88 | miguel ávarez gómez vera | Miguel Álvarez | Vera | miguel álvarez vera |
María | González | Pérez | Almería | 86 | maría gonzález pérez vera | María González | Almeria | maría gonzález almeria |
Carlos | López | Ruiz | Níjar | 86 | carlos lópez ruiz níjar | Carlos López | Níjar | carlos lopez níjar |
Pedro | Hernández | Sánchez | Adra | 84 | pedro hernández sánchez adra | Pedro Hernández | Adra | pedro hernández adra |
Elena | Sánchez | Moreno | Berja | 84 | elena sánchez moreno berja | Elena Sánchez | Berja | elena sánchez berja |
José | Ruiz | Castro | Carboneras | 84 | josé ruiz castro carboneras | José Ruiz | Carboneras | josé ruiz carboneras |
Juan | Martínez | López | Roquetas de Mar | 78 | juan martinez lópez roquetas de mar | Juan Martínez | Roquetas | juan martínez roquetas |
Ana | Torres | García | El Ejido | 78 | ana torres garcía el ejido | Ana Torres | Ejido | ana torres ejido |
Sofía | Pérez | Torres | Huércal-Overa | 71 | sofía pérez torres huércal-overa | Sofía Pérez | Huércal | sofía pérez huércal |
Tabla 3. Resultados de la comparación.
Por último, para completar la gracia de realizar un procesamiento como el mostrado hasta ahora, queda el unificar la información en un solo lugar desde el que se pueda hacer uso. Para ello, creamos una tabla en el Lakehouse relacionado:
# Seleccionar y renombrar columnas para la tabla unificada
tabla_unificada = resultado.select(
resultado["Nombre"].alias("nombre"),
resultado["Primer Apellido"].alias("apellido_1"),
resultado["Segundo Apellido"].alias("apellido_2"),
resultado["Lugar de Nacimiento"].alias("lugar_nacimiento"),
resultado["Similarity"].alias("similaridad")
)
# Guardar como tabla en el Lakehouse
tabla_unificada.write.mode("overwrite").format("delta").saveAsTable("Clientes_Unificados")
Más allá del ejemplo básico: Aplicaciones prácticas
Este enfoque puede extenderse a escenarios mucho más complejos:
Deduplicación de bases de datos de clientes
¿Tienes una base de datos con miles de clientes que sospechas contiene duplicados? El fuzzy matching puede ayudarte a identificar entradas como "Javier Rodríguez" y "J. Rodriguez" como potencialmente el mismo cliente.
Integración de catálogos de productos
Cuando necesitas fusionar catálogos de productos de diferentes proveedores donde los nombres de productos varían ligeramente ("iPhone 13 Pro Max 256GB" vs "Apple iPhone 13 Pro Max (256 GB)").
Normalización de dirección geográfica
Para estandarizar referencias geográficas como "Calle Mayor, 5" y "C/ Mayor nº5" o "Barcelona, España" y "BCN, ES".
Mejoras y consideraciones avanzadas
Para implementaciones más sofisticadas, considera: 1. Ajustar el umbral de similitud: El 70% funciona para nuestro ejemplo, pero según tus datos podrías necesitar un valor diferente. 2. Utilizar diferentes algoritmos: Además de token_sort_ratio, la biblioteca fuzzywuzzy ofrece otras funciones como partial_ratio o token_set_ratio que pueden funcionar mejor dependiendo del tipo de variaciones en tus datos. 3. Paralelizar el proceso: Para conjuntos de datos grandes, aprovecha la capacidad de Spark para distribuir el cálculo en varios nodos. 4. Pre-filtrado: Para optimizar rendimiento, puedes implementar un pre-filtrado que reduzca el número de comparaciones necesarias.
Conclusión: El poder de la flexibilidad
En un mundo ideal, todos los sistemas utilizarían identificadores universales y formatos de datos estandarizados. Pero en la realidad empresarial, nos enfrentamos constantemente a la heterogeneidad y las inconsistencias.
El fuzzy matching en Microsoft Fabric nos proporciona una herramienta elegante para navegar este caos de datos, permitiéndonos unificar información valiosa que de otro modo permanecería fragmentada. Esta técnica no solo ahorra tiempo en la limpieza manual de datos, sino que también desbloquea nuevas posibilidades para el análisis integrado y la toma de decisiones.
La próxima vez que te enfrentes a conjuntos de datos que deberían coincidir pero no lo hacen, recuerda: a veces la solución no es forzar la exactitud, sino abrazar la similitud.
Comments