Python Advanced Series

1. Fuzzy Matching (Cruce Difuso)

1. Fuzzy Matching

Cruza listas de empresas o nombres que no coinciden exactamente debido a errores tipográficos usando la librería TheFuzz.

Match company or person-name lists that do not match exactly because of typos using the TheFuzz library.

⚠️ Advertencia de ciberseguridad y producción ⚠️ Cybersecurity and production warning

Este ejercicio es solo para aprendizaje y pruebas. No ejecutes scripts contra datos reales, ambientes de producción, archivos oficiales, carpetas compartidas, sistemas críticos o repositorios empresariales sin autorización, respaldos, pruebas previas, permisos mínimos, control de cambios y cumplimiento de los protocolos de ciberseguridad de tu organización.

This exercise is for learning and testing only. Do not run scripts against real data, production environments, official files, shared folders, critical systems, or enterprise repositories without authorization, backups, prior testing, least-privilege permissions, change control, and compliance with your organization's cybersecurity protocols.

Objetivo del ejercicio

Exercise objective

Identificar la mejor coincidencia entre un valor escrito con errores y una lista oficial. Este patrón es útil cuando los nombres vienen de fuentes distintas y no siempre tienen el mismo formato.

Identify the best match between a typo-filled value and an official list. This pattern is useful when names come from different sources and do not always share the same format.

Datos sintéticos

Synthetic data

Lista oficialOfficial listNombre recibidoReceived name
MicrosoftMicro soft Corp
Apple IncApple Incorporated
Google LLCGoogel LLC
AmazonAmazn

Ejemplo base

Base example

from thefuzz import process, fuzz

choices = ["Microsoft", "Apple Inc", "Google LLC"]
query = "Micro soft Corp"

match = process.extractOne(query, choices, scorer=fuzz.partial_ratio)
# ES: Mejor coincidencia | EN: Best match

Resultado esperado

Expected result

Valor recibidoReceived valueMejor coincidenciaBest matchScore
Micro soft CorpMicrosoft89
Apple IncorporatedApple Inc100
Googel LLCGoogle LLC90
AmaznAmazon91
Meta Platform IncMeta Platforms96

Salida esperada en consola

Expected console output

Al ejecutar el script completo, la consola debe mostrar una tabla parecida a esta. El score puede variar ligeramente según la versión de la librería, pero la lógica del resultado debe mantenerse.

When running the complete script, the console should display a table similar to this. The score may vary slightly depending on the library version, but the output logic should remain the same.

      Company_Received     Best_Match  Match_Score Needs_Review
0      Micro soft Corp      Microsoft           89           No
1   Apple Incorporated      Apple Inc          100           No
2            Googel LLC     Google LLC          90           No
3                 Amazn        Amazon           91           No
4     Meta Platform Inc  Meta Platforms         96           No

Report created: fuzzy_matching_report.csv

Reporte CSV generado

Generated CSV report

Company_ReceivedBest_MatchMatch_ScoreNeeds_Review
Micro soft CorpMicrosoft89No
Apple IncorporatedApple Inc100No
Googel LLCGoogle LLC90No
AmaznAmazon91No
Meta Platform IncMeta Platforms96No

Instalación de librería

Library installation

Ejecuta esta línea una sola vez si TheFuzz no está instalada en tu ambiente local o notebook.

Run this line once if TheFuzz is not installed in your local environment or notebook.

pip install thefuzz python-Levenshtein

Script completo

Complete script

# ==========================================================
# Python Advanced Topic 1
# Fuzzy Matching / Cruce Difuso
# ==========================================================

import pandas as pd
from thefuzz import process, fuzz

# 1. Official master list
master_companies = [
    "Microsoft",
    "Apple Inc",
    "Google LLC",
    "Amazon",
    "Meta Platforms"
]

# 2. Incoming values with typos or different writing styles
incoming_data = pd.DataFrame({
    "Company_Received": [
        "Micro soft Corp",
        "Apple Incorporated",
        "Googel LLC",
        "Amazn",
        "Meta Platform Inc"
    ]
})

# 3. Function to find the best fuzzy match
def get_best_match(value, choices):
    match = process.extractOne(value, choices, scorer=fuzz.partial_ratio)
    return pd.Series({
        "Best_Match": match[0],
        "Match_Score": match[1]
    })

# 4. Apply fuzzy matching
match_results = incoming_data["Company_Received"].apply(
    lambda x: get_best_match(x, master_companies)
)

# 5. Combine original values with match results
final_report = pd.concat([incoming_data, match_results], axis=1)

# 6. Add review flag
final_report["Needs_Review"] = final_report["Match_Score"].apply(
    lambda score: "Yes" if score < 85 else "No"
)

# 7. Export result
output_file = "fuzzy_matching_report.csv"
final_report.to_csv(output_file, index=False)

print(final_report)
print(f"Report created: {output_file}")

Versión con archivos CSV

CSV file version

Esta versión cruza un archivo maestro contra un archivo de actividad usando una columna de nombre.

This version matches a master file against an activity file using a name column.

# ==========================================================
# Fuzzy Matching from CSV files
# ==========================================================

import pandas as pd
from thefuzz import process, fuzz

master_file = r"C:\Data\master_companies.csv"
activity_file = r"C:\Data\activity_companies.csv"
output_file = r"C:\Data\fuzzy_matching_output.csv"

master = pd.read_csv(master_file)
activity = pd.read_csv(activity_file)

# Expected columns:
# master: Company_Official
# activity: Company_Received

choices = master["Company_Official"].dropna().astype(str).tolist()

def fuzzy_lookup(value):
    if pd.isna(value) or str(value).strip() == "":
        return pd.Series({"Best_Match": None, "Match_Score": 0})

    match = process.extractOne(str(value), choices, scorer=fuzz.partial_ratio)
    return pd.Series({"Best_Match": match[0], "Match_Score": match[1]})

results = activity["Company_Received"].apply(fuzzy_lookup)
final = pd.concat([activity, results], axis=1)

final["Needs_Review"] = final["Match_Score"].apply(
    lambda score: "Yes" if score < 85 else "No"
)

final.to_csv(output_file, index=False)

print("Fuzzy matching completed.")
print(f"Output file: {output_file}")

Aplicaciones reales

Real-world applications

  • Cruzar listas de compañías con nombres escritos diferente.
  • Detectar clientes duplicados por errores tipográficos.
  • Relacionar proveedores entre sistemas distintos.
  • Normalizar nombres antes de un proceso ETL.
  • Match company lists with differently written names.
  • Detect duplicate customers caused by typos.
  • Relate vendors across different systems.
  • Normalize names before an ETL process.

Recomendaciones

Recommendations

  • Usar un score mínimo, por ejemplo 85, para revisión manual.
  • Limpiar espacios, puntos y mayúsculas antes de comparar.
  • No aceptar automáticamente coincidencias con score bajo.
  • Guardar la coincidencia y el score como evidencia de auditoría.
  • Use a minimum score, such as 85, for manual review.
  • Clean spaces, dots, and casing before matching.
  • Do not automatically accept low-score matches.
  • Save the match and score as audit evidence.

Valor del tópico

Topic value

El fuzzy matching agrega una capa inteligente a los cruces de datos. En vez de depender solamente de coincidencias exactas, permite encontrar relaciones probables y acelerar tareas de limpieza, reconciliación y consolidación de información.

Fuzzy matching adds an intelligent layer to data matching. Instead of depending only on exact matches, it finds probable relationships and accelerates cleaning, reconciliation, and information consolidation tasks.