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
Características • Instalación • Uso Rápido • Documentación • Ejemplos
🎯 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
- JSON_GUIDE.md: Guía completa de formatos JSON con ejemplos
- API.md: Referencia detallada de la API
- INSTALL.md: Guía de instalación y configuración
- CHANGELOG.md: Historial de cambios
💡 Ejemplos
La carpeta examples/ contiene ejemplos completos de uso (no incluida en el repositorio):
json_usage.py: Ejemplos con JSON en memoriajson_file_processing.py: Procesamiento de archivos JSONinput_*.json: Archivos de ejemplo de entradaquick_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:
- Convierte CSVs de términos históricos a JSON
- Carga listas de voces normalizadas
- Procesa 100 términos reales con los algoritmos
- 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
- INGLATERRA: 34,976 ocurrencias
- NACIONAL_AR: 14,921 ocurrencias
- FRANCIA: 9,982 ocurrencias
- ITALIA: 9,283 ocurrencias
- ALEMANIA: 6,421 ocurrencias
- URUGUAY: 5,987 ocurrencias
- ESPAÑA: 5,711 ocurrencias
- ESTADOS UNIDOS: 4,272 ocurrencias
- NORUEGA: 3,717 ocurrencias
- 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:
- Fork el proyecto
- Crea una rama para tu feature (
git checkout -b feature/AmazingFeature) - Commit tus cambios (
git commit -m 'Add some AmazingFeature') - Push a la rama (
git push origin feature/AmazingFeature) - 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e4364ce14f5d10ec7c752fb228b0d588110ce14c62f6b909afbe7928891ce65
|
|
| MD5 |
63084bfcc6cbd03b79e4ef853fc3f9e5
|
|
| BLAKE2b-256 |
014bb94d62436a9c793c20a952a5e00f732470ba2088096cbaa5cf15001f4819
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a95c9b895c55f363ac80e65244c209115ff1f3da97d19b44f866ced89c5215c
|
|
| MD5 |
1f3ee99633f5750e2d98ef7568807e62
|
|
| BLAKE2b-256 |
f6c1d21d55d30957b4f4fd348d1d2e742dfb4e9e0ac76b55289842585b40b92e
|