Skip to main content

Biblioteca de algoritmos de similitud para desambiguación de términos históricos

Project description

Portada S-Index

Biblioteca Python para desambiguación de términos históricos mediante algoritmos de similitud de cadenas

PyPI version Python Version License Downloads Code style: black Maintained PRs Welcome

CaracterísticasInstalaciónUso RápidoDocumentaciónEjemplos


🎯 Descripción

Portada S-Index es una biblioteca especializada en la desambiguación automática de términos históricos mediante el análisis de similitud con vocabularios controlados. Desarrollada para el proyecto PORTADA, utiliza múltiples algoritmos de similitud de cadenas y un sistema de consenso para clasificar términos con diferentes niveles de confianza.

Interfaz principal: JSON - Todas las entradas y salidas se manejan exclusivamente mediante JSON para máxima interoperabilidad.

✨ Características

🔧 Algoritmos de Similitud

  • Levenshtein OCR: Distancia de Levenshtein con corrección para errores comunes de OCR
  • Levenshtein Ratio: Distancia de Levenshtein estándar normalizada
  • Jaro-Winkler: Algoritmo optimizado para nombres propios con énfasis en prefijos
  • N-gramas (2 y 3): Similitud basada en bigramas y trigramas

📊 Sistema de Clasificación

Clasificación automática en 5 niveles de confianza:

Nivel Descripción Criterio
CONSENSUADO Alta confianza 2+ algoritmos votan por la misma entidad + Levenshtein OCR incluido
CONSENSUADO_DEBIL Confianza moderada 2+ algoritmos aprueban sin criterio estricto
SOLO_1_VOTO Baja confianza Solo 1 algoritmo supera el umbral
ZONA_GRIS Ambiguo Al menos 1 algoritmo en zona gris
RECHAZADO Sin correspondencia Ningún algoritmo supera umbrales

🎛️ Configuración Flexible

  • Selección de algoritmos a utilizar
  • Umbrales de aprobación personalizables por algoritmo
  • Zonas grises ajustables para casos ambiguos
  • Normalización automática de texto (Unicode, diacríticos, minúsculas)
  • Mapeo de voces a entidades para agrupación semántica

🚀 Procesamiento Avanzado

  • Procesamiento por lotes: Múltiples operaciones en una sola llamada
  • Entrada flexible: Diccionarios Python, strings JSON o archivos JSON
  • Salida estructurada: Siempre en formato JSON con información completa
  • Reportes estadísticos: Generación automática de métricas y cobertura

📦 Instalación

Requisitos

  • Python >= 3.12
  • Sin dependencias externas (solo biblioteca estándar de Python)

Instalación desde PyPI

pip install portada-s-index

O con uv (más rápido):

uv pip install portada-s-index

Instalación desde código fuente

git clone <repository>
cd portada-s-index
pip install -e .

O con uv:

uv pip install -e .

🚀 Uso Rápido

Calcular Similitud

from portada_s_index import calculate_similarity_json
import json

# Entrada JSON
input_data = {
    "term": "alemán",
    "voices": ["aleman", "alemana", "germano", "frances"]
}

# Procesar
result_json = calculate_similarity_json(input_data)
result = json.loads(result_json)

# Resultado
print(json.dumps(result, indent=2, ensure_ascii=False))

Salida:

{
  "term": "alemán",
  "results": {
    "levenshtein_ocr": {
      "voice": "aleman",
      "similarity": 1.0,
      "approved": true
    },
    "jaro_winkler": {
      "voice": "aleman",
      "similarity": 1.0,
      "approved": true
    },
    "ngram_2": {
      "voice": "aleman",
      "similarity": 1.0,
      "approved": true
    }
  }
}

Clasificar Términos

from portada_s_index import classify_terms_json
import json

# Entrada JSON
input_data = {
    "terms": ["aleman", "frances", "ingles"],
    "voices": ["aleman", "alemana", "frances", "francesa", "ingles", "inglesa"],
    "frequencies": {
        "aleman": 100,
        "frances": 80,
        "ingles": 150
    }
}

# Procesar
result_json = classify_terms_json(input_data)
result = json.loads(result_json)

print(f"Términos clasificados: {result['total_terms']}")

Clasificar con Reporte

from portada_s_index import classify_terms_with_report_json
import json

# Entrada JSON (mismo formato que classify_terms)
input_data = {
    "terms": ["aleman", "frances"],
    "voices": ["aleman", "frances"]
}

# Procesar
result_json = classify_terms_with_report_json(input_data)
result = json.loads(result_json)

# Acceder al reporte
report = result["report"]
print(f"Cobertura: {report['coverage']['consensuado_strict']['percentage']:.2f}%")

Procesamiento por Lotes

from portada_s_index import process_batch_json
import json

# Múltiples operaciones en una llamada
input_data = {
    "operations": [
        {
            "type": "calculate_similarity",
            "data": {
                "term": "alemán",
                "voices": ["aleman", "alemana"]
            }
        },
        {
            "type": "classify_terms",
            "data": {
                "terms": ["frances", "ingles"],
                "voices": ["frances", "ingles"]
            }
        }
    ],
    "config": {
        "algorithms": ["levenshtein_ocr", "jaro_winkler"],
        "normalize": true
    }
}

# Procesar
result_json = process_batch_json(input_data)
result = json.loads(result_json)

print(f"Operaciones exitosas: {result['successful']}/{result['total_operations']}")

Procesar desde Archivos

from portada_s_index import classify_terms_from_file

# Procesar archivo JSON y guardar resultado
result_json = classify_terms_from_file(
    input_file="input.json",
    output_file="output.json"
)

📖 Documentación

Estructura de Entrada JSON

Entrada Mínima

{
  "terms": ["aleman", "frances"],
  "voices": ["aleman", "frances"]
}

Entrada Completa

{
  "terms": ["aleman", "frances"],
  "voices": ["aleman", "alemana", "frances", "francesa"],
  "frequencies": {
    "aleman": 100,
    "frances": 80
  },
  "voice_to_entity": {
    "aleman": "ALEMANIA",
    "alemana": "ALEMANIA",
    "frances": "FRANCIA",
    "francesa": "FRANCIA"
  },
  "config": {
    "algorithms": ["levenshtein_ocr", "jaro_winkler", "ngram_2"],
    "thresholds": {
      "levenshtein_ocr": 0.75,
      "jaro_winkler": 0.85,
      "ngram_2": 0.66
    },
    "gray_zones": {
      "levenshtein_ocr": [0.71, 0.749],
      "jaro_winkler": [0.80, 0.849],
      "ngram_2": [0.63, 0.659]
    },
    "normalize": true,
    "min_votes_consensus": 2,
    "require_levenshtein_ocr": true
  }
}

API Principal

Funciones de Entrada JSON

Función Descripción
calculate_similarity_json(input_json) Calcula similitud de un término con voces
classify_terms_json(input_json) Clasifica múltiples términos
classify_terms_with_report_json(input_json) Clasifica términos y genera reporte resumen
process_batch_json(input_json) Procesa múltiples operaciones en lote

Funciones de Archivo JSON

Función Descripción
calculate_similarity_from_file(input_file, output_file) Procesa archivo de similitud
classify_terms_from_file(input_file, output_file) Procesa archivo de clasificación
classify_terms_with_report_from_file(input_file, output_file) Procesa con reporte
process_batch_from_file(input_file, output_file) Procesa lote desde archivo

Algoritmos y Umbrales

Algoritmo Identificador Umbral Default Zona Gris Default
Levenshtein OCR levenshtein_ocr 0.75 [0.71, 0.749]
Levenshtein Ratio levenshtein_ratio 0.75 [0.71, 0.749]
Jaro-Winkler jaro_winkler 0.85 [0.80, 0.849]
N-gramas 2 ngram_2 0.66 [0.63, 0.659]
N-gramas 3 ngram_3 0.60 [0.55, 0.599]

📚 Documentación Completa

💡 Ejemplos

La carpeta examples/ contiene ejemplos completos de uso (no incluida en el repositorio):

  • json_usage.py: Ejemplos con JSON en memoria
  • json_file_processing.py: Procesamiento de archivos JSON
  • input_*.json: Archivos de ejemplo de entrada
  • quick_test.py: Tests rápidos sin instalación

Ejecutar Ejemplos

# Desde el directorio del proyecto
python3 examples/json_usage.py
python3 examples/json_file_processing.py

🧪 Testing

Tests Unitarios

# Tests básicos
python3 tests/test_basic.py

Test Externo (Simulación Real)

# Test que simula uso real desde fuera del proyecto
python3 test_portada_external.py

Resultado esperado:

✓ TEST 1: Similitud simple
✓ TEST 2: Clasificación de términos
✓ TEST 3: Clasificación con reporte
✓ TEST 4: Configuración personalizada
✓ TEST 5: Procesamiento por lotes
✓ TEST 6: Mapeo de voces a entidades
✓ TEST 7: Entrada como string JSON

✓ TODOS LOS TESTS EXTERNOS PASARON CORRECTAMENTE

Test con Datos Reales

# Test con datos reales del proyecto similitudes
python3 test_real_data.py

Este test:

  1. Convierte CSVs de términos históricos a JSON
  2. Carga listas de voces normalizadas
  3. Procesa 100 términos reales con los algoritmos
  4. Genera reportes estadísticos detallados

Resultados con datos reales (100 términos, 110,924 ocurrencias):

Clasificación Términos Ocurrencias Porcentaje
CONSENSUADO 92 110,567 99.68%
SOLO_1_VOTO 7 322 0.29%
RECHAZADO 1 35 0.03%

Cobertura consensuada: 99.68%

Top entidades identificadas:

  • INGLATERRA: 34,976 ocurrencias
  • NACIONAL_AR: 14,921 ocurrencias
  • FRANCIA: 9,982 ocurrencias
  • ITALIA: 9,283 ocurrencias
  • ALEMANIA: 6,421 ocurrencias

🔧 Configuración Avanzada

Personalizar Algoritmos

{
  "config": {
    "algorithms": ["levenshtein_ocr", "jaro_winkler"],
    "thresholds": {
      "levenshtein_ocr": 0.80,
      "jaro_winkler": 0.90
    }
  }
}

Ajustar Criterios de Consenso

{
  "config": {
    "min_votes_consensus": 3,
    "require_levenshtein_ocr": false
  }
}

Desactivar Normalización

{
  "config": {
    "normalize": false
  }
}

🎯 Casos de Uso

Desambiguación de Banderas de Barcos

input_data = {
    "terms": ["aleman", "alemana", "germano"],
    "voices": ["aleman", "alemana", "germano"],
    "voice_to_entity": {
        "aleman": "ALEMANIA",
        "alemana": "ALEMANIA",
        "germano": "ALEMANIA"
    }
}

Normalización de Puertos

input_data = {
    "terms": ["barcelona", "barzelona", "barcino"],
    "voices": ["barcelona"],
    "voice_to_entity": {
        "barcelona": "BARCELONA"
    }
}

Clasificación de Tipos de Embarcación

input_data = {
    "terms": ["bergantin", "bergantín", "bergatin"],
    "voices": ["bergantin"],
    "frequencies": {
        "bergantin": 150,
        "bergantín": 80,
        "bergatin": 20
    }
}

📊 Formato de Salida

Resultado de Similitud

{
  "term": "alemán",
  "results": {
    "levenshtein_ocr": {
      "term": "alemán",
      "voice": "aleman",
      "algorithm": "levenshtein_ocr",
      "similarity": 1.0,
      "approved": true,
      "in_gray_zone": false
    }
  }
}

Clasificación de Términos

{
  "total_terms": 2,
  "classifications": [
    {
      "term": "aleman",
      "frequency": 100,
      "results": {...},
      "votes_approval": 3,
      "entity_consensus": "ALEMANIA",
      "voice_consensus": "aleman",
      "votes_entity": 3,
      "levenshtein_ocr_in_consensus": true,
      "classification": "CONSENSUADO"
    }
  ]
}

Reporte Resumen

{
  "report": {
    "total_terms": 100,
    "total_occurrences": 5000,
    "by_level": {
      "CONSENSUADO": {
        "count": 75,
        "occurrences": 4500,
        "percentage": 90.0
      }
    },
    "coverage": {
      "consensuado_strict": {
        "occurrences": 4500,
        "percentage": 90.0
      }
    }
  },
  "classifications": [...]
}

🎖️ Resultados con Datos Reales

Pruebas realizadas con datos históricos reales del proyecto PORTADA:

Dataset de Prueba

  • Fuente: Banderas de barcos históricos
  • Términos procesados: 100
  • Ocurrencias totales: 110,924
  • Voces de referencia: 324 (134 entidades)

Resultados de Clasificación

Nivel Términos Ocurrencias Cobertura
CONSENSUADO 92 110,567 99.68%
SOLO_1_VOTO 7 322 0.29%
RECHAZADO 1 35 0.03%

Ejemplos de Clasificación Exitosa

Términos con alta frecuencia correctamente identificados:

Término Original Frecuencia Entidad Identificada Confianza
ingles 28,247 INGLATERRA CONSENSUADO
nacional 14,921 NACIONAL_AR CONSENSUADO
frances 6,933 FRANCIA CONSENSUADO
inglesa 6,153 INGLATERRA CONSENSUADO
aleman 5,154 ALEMANIA CONSENSUADO
italiano 4,924 ITALIA CONSENSUADO

Top 10 Entidades Identificadas

  1. INGLATERRA: 34,976 ocurrencias
  2. NACIONAL_AR: 14,921 ocurrencias
  3. FRANCIA: 9,982 ocurrencias
  4. ITALIA: 9,283 ocurrencias
  5. ALEMANIA: 6,421 ocurrencias
  6. URUGUAY: 5,987 ocurrencias
  7. ESPAÑA: 5,711 ocurrencias
  8. ESTADOS UNIDOS: 4,272 ocurrencias
  9. NORUEGA: 3,717 ocurrencias
  10. ARGENTINA: 3,241 ocurrencias

Análisis de Rendimiento

  • Precisión: 99.68% de las ocurrencias clasificadas con alta confianza
  • Cobertura: 92% de términos únicos consensuados
  • Algoritmos: 91 términos con 3 votos de aprobación
  • Tiempo de procesamiento: < 1 segundo para 100 términos

Conclusiones

✅ Los algoritmos demuestran alta precisión en la identificación de términos históricos
✅ El sistema de consenso funciona efectivamente para reducir falsos positivos
✅ La normalización de texto maneja correctamente variaciones ortográficas
✅ El mapeo a entidades permite agrupación semántica efectiva

🤝 Contribuir

Las contribuciones son bienvenidas. Por favor:

  1. Fork el proyecto
  2. Crea una rama para tu feature (git checkout -b feature/AmazingFeature)
  3. Commit tus cambios (git commit -m 'Add some AmazingFeature')
  4. Push a la rama (git push origin feature/AmazingFeature)
  5. Abre un Pull Request

📝 Licencia

[Especificar licencia]

👥 Autores

Proyecto PORTADA - Desambiguación de términos históricos marítimos

🙏 Agradecimientos

  • Proyecto PORTADA
  • Comunidad de investigación histórica marítima

📧 Contacto

Para preguntas, sugerencias o reportar problemas, por favor abre un issue en el repositorio.


Hecho con ❤️ para el proyecto PORTADA

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

portada_s_index-0.1.0.tar.gz (25.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

portada_s_index-0.1.0-py3-none-any.whl (19.1 kB view details)

Uploaded Python 3

File details

Details for the file portada_s_index-0.1.0.tar.gz.

File metadata

  • Download URL: portada_s_index-0.1.0.tar.gz
  • Upload date:
  • Size: 25.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.3","id":"zena","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for portada_s_index-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6e4364ce14f5d10ec7c752fb228b0d588110ce14c62f6b909afbe7928891ce65
MD5 63084bfcc6cbd03b79e4ef853fc3f9e5
BLAKE2b-256 014bb94d62436a9c793c20a952a5e00f732470ba2088096cbaa5cf15001f4819

See more details on using hashes here.

File details

Details for the file portada_s_index-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: portada_s_index-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.3","id":"zena","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for portada_s_index-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9a95c9b895c55f363ac80e65244c209115ff1f3da97d19b44f866ced89c5215c
MD5 1f3ee99633f5750e2d98ef7568807e62
BLAKE2b-256 f6c1d21d55d30957b4f4fd348d1d2e742dfb4e9e0ac76b55289842585b40b92e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page