Otros procedimientos de búsqueda
Cuando lo que buscamos está bien definido y también el módo en que se expresa en el nombre del archivo, posiblemente la mejor solución sea la planteada en el segundo script de la entrada anterior: es simple, seguda y precisa. Pero cuando no contamos con esas seguridades y se pueden haber cometido errores o la misma realidad (el mismo tipo de archivo) se puede expresar de otras formas, puede ser necesario recurrir a otro tipo de procedimientos.
Uno de ellos consiste en crear una lista de posibles nombres (conjuntos de caracteres) y utilizarla como términos para la búsqueda. Un ejemplo: supongamos que además o en lugar de "SISE", los archivos que deseamos buscar pueden contener "seguimiento" o "PTSC". En ese caso sustituímos la referencia exclusiva IDENTIFICADOR = "SISE" por unq lista, tal y como se propone en el siguiente script:
#Bibliotecas a emplear -----------------------------------------------------------------
from pathlib import Path
#Función -------------------------------------------------------------------------------
def buscar_multiples_identificadores(ruta_raiz, lista_keywords):
directorio = Path(ruta_raiz)
if not directorio.is_dir():
print(f"Error: La ruta '{ruta_raiz}' no es válida.")
return
# Convertimos los términos a minúsculas para una búsqueda insensible a mayúsculas
keywords = [k.lower() for k in lista_keywords]
print(f"Buscando archivos que contengan: {lista_keywords}")
print("-" * 50)
conteo = 0
# rglob('*') recorre todos los archivos de la ruta
for archivo in directorio.rglob('*'):
if archivo.is_file():
nombre_archivo = archivo.name.lower()
# Verificamos si AL MENOS UNO de los identificadores está en el nombre
if any(key in nombre_archivo for key in keywords):
print(archivo.name)
conteo += 1
print("-" * 50)
print(f"Búsqueda finalizada. Total de archivos encontrados: {conteo}")
# Llamada a la función ---------------------------------------------------------
ruta = r"Mi_Ruta" #Ruta en la que buscar los archivos
# Puedes añadir tantos identificadores como necesites en esta lista
mis_identificadores = ["SISE", "Seguimiento", "PTSC", "PSC"] # Sustituye estos por tus términos
buscar_multiples_identificadores(ruta, mis_identificadores)
Como principales diferencias respecto al script de elemento único, ahora empleamos la lista mis_identificadores = ["SISE", "Seguimiento", "PTSC", "PSC"] como parámetro y lo utilizamos como referente para la búsqueda if any(key in nombre_archivo for key in keywords)::
- El operador
incomprueba la existencia de cada uno de los elementos de la lista y devuelve True cuando lo encuentra. - La parte
keydefor key in keywordses un pequeño motor de búsqueda que recorre la lista de identificadores uno por uno y contrasta con el nombre del archivo para comprobar la presencia del elemento o "palabra". - Y la función
any()actúa como un conmutador binario inicialmente posicionado como False que pasa a True en cuanto una de las comprobaciones anteriores resulta también True. Esto hace que, en este caso, el archivo pase a ser mostrado en consola.
Aun disponemos de otra opción que supone un cambio en el planteamiento de trabajo y un salto en el modelo de script. Me estoy refiriendo al uso de la bibliteca Rapidfuzz que se debe instalar previamente pip install rapidfuzz.
Aunque no me voy a deterner a explicar esta biblioteca, pero sí parece pertinente una breve referencia a qué hace esta biblioteca y por qué es interesante para nuestro objetivo.
Empezaré diciendo que es una biblioteca de comparación de cadenas que se basa en el cálculo de similitud de cadenas de la función de Levenshtein...
... lo que supone realizar comparaciones entre string (cadena de texto) de forma “difusa” (fuzzy matching) y no mediante procedimientos como los empleados en la programación tradicional. Esto supone que lo que obtenemos es una lista de probabilidad de similitud, no una lista de resultados supuestamente seguros, de ahí que sea necesario establecer el porcentaje deseado, dependiendo del cual, en este caso, obtendermos una lista más o menos extensa.
#Bibliotecas necesarias ---------------------------------------------------------
from pathlib import Path
from rapidfuzz import fuzz # Algoritmo de similitud
#Función -------------------------------------------------------------------------
def buscador_inteligente(ruta_raiz, identificadores, umbral):
directorio = Path(ruta_raiz)
if not directorio.is_dir():
print(f"Error: {ruta_raiz} no es una ruta válida.")
return
print(f"Buscando coincidencias inteligentes para: {identificadores}")
print(f"Umbral de precisión: {umbral}%\n")
conteo = 0
# Recorremos todos los archivos en profundidad
for archivo in directorio.rglob('*'):
if archivo.is_file():
nombre_archivo = archivo.name.lower()
# Comparamos cada identificador con el nombre del archivo
for iden in identificadores:
# partial_ratio busca si la palabra "encaja" dentro de otra aunque haya errores
similitud = fuzz.partial_ratio(iden.lower(), nombre_archivo)
if similitud >= umbral:
# Si la similitud es alta, lo damos por válido
status = "EXACTO" if similitud == 100 else f"{similitud}%"
print(f"[{status}] -> {archivo.name}")
conteo += 1
break # Pasamos al siguiente archivo si ya encontramos coincidencia
print(f"\n--- Búsqueda finalizada. Total: {conteo} archivos ---")
# Llamada a función ---------------------------------------------------------------
ruta_trabajo = r"Mi_Ruta" # Tu carpeta compleja
mis_ids = ["SISE", "PTSC","PSC","Seguimiento"] # Plantea aquí tu lista de términos
punteria = 000 # Ajusta: 100 es exacto, 60 es muy flexible
buscador_inteligente(ruta_trabajo, mis_ids, punteria)
Para hacerse una idea del funcionamiento real de estos sistemas de búsqueda por comparación con el empleado en el primer script de este tipo (ver segundo script de la entrada) veamos qué resultados obtenemos en una búsqueda real de archivos SISE (informes de seguimiento de PSC/PTSC) en un conjunto de expedientes SEO.
| Buscado | Número de archivos |
|---|---|
Buscador simple (SISE) |
34 archivos |
Buscador múltiple (["SISE", "PTSC","PSC","Seguimiento"]) |
65 archivos |
Buscador fuzz ["SISE", "PTSC","PSC","Seguimiento"](75%) |
450 archivos |
Buscador fuzz ["SISE", "PTSC","PSC","Seguimiento"](85%) |
65 archivos |
Buscador fuzz ["SISE", "PTSC","PSC","Seguimiento"](95%) |
65 archivos |
Buscador fuzz ["SISE", "PTSC","PSC","Seguimiento"](100%) |
65 archivos |
Una correcta valoración de estos resultados pasaría por comprobar cuantos de los archivos detectados con los procedimientos menos restricitivos son realmente seguimientos de alumnado realizado por PTSC/PSC. Evidentemente, salvo error de denominación, podemos estar seguros de que los 34 archivos identificados con el procedimiento restrictivo lo son (ese mismo es el número de archivos obtenemos si reducimos la lista fuzz a únicamente "SISE", como cabe esperar). También podemos estar seguros de que los 450 archivos que derivan de un 75% de nivel de similitud está dando lugar a múltiples falsos positivos; pero lo que no podemos saber sin "mirar dentro" de los archivos es cuantos del resto de los procedimientos, de esos 65 que derivan de sistemas más abiertos de búsqueda (donde la causa de la variación está en el número de "palabras" que incluya la búsqueda y no el porcentaje de similitud que apliquemos), son realmente "SISE".
Estas cuestiones quedarán aquí pendientes de comprobación, porque no es esta sección lugar para este tipo de análisis. Es posible que las retome en otro momento y lugar, pero por ahora finalizamos esta entrada. Quedan algunas cosas pendientes, pero serán para otra.
Aquí, y a modo de resumen, recordar la línea de trabajo en la que hemos avanzado hasta el momento: empezamos por buscar archivos considerando al archivo como dato en si mismo; avanzamos en los procedimientos de búsqueda de archivos, proimero superficial y después en profundidad, y nos planteamos una segunda forma de entender el archivo como dato: la extensión y el nombre. Para el análisis del nombre se han empleado procedimientos simples (un término) y complejos (una colección de términos), pero ambos dentro de lo que nos permite la biblioteca pathlib. Pero además podemos aplicar procedimientos matemáticos de análisis de texto (string) de base estadística como los que aporta la biblioteca rapidfuzz. Y aun no hemos terminado...
No hay comentarios:
Publicar un comentario
Comenta esta entrada