Cómo trabajar con Clustering en Python
Aspose.PDF FOSS para Python incluye una pequeña utilidad de clustering jerárquico aglomerativo de propósito general — independiente de cualquier operación PDF individual — para agrupar objetos DataPoint relacionados en instancias Cluster y calcular el centroide de un clúster. Tú decides qué representa cada punto de datos y proporcionas sus coordenadas tú mismo; la utilidad no las rellena automáticamente. La biblioteca se instala con el comando a continuación.
Guía paso a paso
Paso 1: Instalar el paquete
Instala el paquete FOSS de Aspose.PDF:
git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .Verifica la instalación importando Cluster y mostrando un mensaje de confirmación:
from aspose_pdf import Cluster
print("aspose-pdf-foss-for-python is ready.")Paso 2: Importar las clases requeridas
Importa las tres clases que conforman la utilidad de clustering:
from aspose_pdf import Cluster, ClusterCollection, DataPointPaso 3: Crear puntos de datos
Un DataPoint empareja una cadena name con una lista value de flotantes — las coordenadas o vector de características que decidas que son significativas para tu propia lógica de agrupamiento:
from aspose_pdf import DataPoint
point_a = DataPoint("item-1", [12.0, 45.0])
point_b = DataPoint("item-2", [13.5, 44.0])
point_c = DataPoint("item-3", [98.0, 5.0])
print(point_a.name, point_a.value)DataPoint no vincula value a ningún concepto particular de PDF — coordenadas de página, métricas de fuente, o cualquier otro vector de características numérico funcionan igualmente bien.
Paso 4: Agrupar puntos de datos en un clúster
Pasa la lista completa de miembros al constructor Cluster. No hay método para añadir elementos a un Cluster después de que se haya construido, así que decide la membresía primero:
from aspose_pdf import Cluster
nearby = Cluster([point_a, point_b])
print(nearby.count) # 2
print(nearby.contains(point_a)) # Truecontains() coincide por igualdad — DataPoint define la igualdad sobre name y value juntos, por lo que una instancia diferente de DataPoint con el mismo nombre y valor también se reporta como contenida.
Paso 5: Calcular el centroide del clúster
DataPoint.get_centroid(cluster) es un método estático que promedia cada dimensión de cada DataPoint.value en el clúster y devuelve el resultado como un nuevo DataPoint llamado "centroid":
from aspose_pdf import DataPoint
centroid = DataPoint.get_centroid(nearby)
print(centroid.name) # "centroid"
print(centroid.value) # per-dimension average across the clusterCada lista de DataPoint.value en el clúster debe tener la misma longitud — get_centroid promedia posición por posición y no valida que las longitudes coincidan. Llamarlo sobre Cluster.empty(), o cualquier clúster con count == 0, genera ValueError.
Paso 6: Clonar un clúster o reutilizar la instancia vacía compartida
clone() devuelve un Cluster independiente que contiene los mismos elementos; Cluster.empty() siempre devuelve la misma instancia de clúster vacío en caché en lugar de crear una nueva:
from aspose_pdf import Cluster
backup = nearby.clone()
print(backup is nearby) # False -- independent copy
print(backup.contains(point_a)) # True -- same items
placeholder = Cluster.empty()
print(placeholder.count) # 0Paso 7: Agrupar varios clústeres en un ClusterCollection
ClusterCollection agrupa varios objetos Cluster detrás de un único contenedor compatible con len():
from aspose_pdf import Cluster, ClusterCollection
outliers = Cluster([point_c])
collection = ClusterCollection([nearby, outliers])
print(len(collection)) # 2ClusterCollection no expone un método para recuperar sus clústeres — mantén una referencia a la lista que pasas al constructor si necesitas iterar los clústeres posteriormente.
Problemas comunes y soluciones
No hay ningún método para agregar un elemento a un existente Cluster
Cluster solo acepta su lista de membresía en el momento de la construcción (Cluster(items)). Construye primero la lista completa de objetos DataPoint, luego construye el Cluster — no hay add() ni append() para llamar después.
DataPoint.get_centroid() raises ValueError
Esto ocurre cuando el clúster proporcionado está vacío (count == 0), incluyendo Cluster.empty(). Verifica cluster.count antes de llamar a get_centroid, o maneja la excepción si un clúster vacío es una entrada válida en tu flujo de trabajo.
Los valores del centroide parecen incorrectos
get_centroid suma cada posición de DataPoint.value posición por posición y divide por el número de puntos — no verifica que cada lista value en el clúster tenga la misma longitud. Mezclar objetos DataPoint con dimensionalidad no coincidente produce un promedio incorrecto de forma silenciosa en lugar de lanzar una excepción.
Expecting Cluster.empty() para crear un clúster vacío y nuevo cada vez
Cluster.empty() es un accessor singleton — cada llamada devuelve la misma instancia en caché. Use Cluster() (sin argumentos) en su lugar si necesita un clúster vacío distinto e independiente.
Esperando que la biblioteca agrupe los puntos automáticamente
DataPoint, Cluster y ClusterCollection son estructuras de datos para representar puntos, clústeres y un cálculo de centróide — el módulo no incluye una función de enlace o distancia que decida qué puntos pertenecen juntos. Su propio código determina la pertenencia a clúster antes de construir un Cluster.
Preguntas frecuentes
¿Este módulo agrupa automáticamente los puntos de datos por distancia?
No. Cluster, DataPoint y ClusterCollection son bloques de construcción para representar agrupaciones ya decididas y calcular un centróide — no hay un paso incorporado de aglomeración o asignación basada en distancia.
¿Cuál es la diferencia entre Cluster() y Cluster.empty()?
Cluster(items=None) crea una nueva instancia cada vez que se llama. Cluster.empty() es un método de clase que devuelve la misma instancia de clúster vacío almacenada en caché y compartida en cada llamada.
¿Puedo añadir elementos a un Cluster después de crearlo?
No. Cluster solo expone contains(), clone() y la propiedad count más allá de la construcción — la membresía se fija una vez que se ejecuta el constructor.
¿Funciona get_centroid() con cualquier número de dimensiones?
Sí, siempre que cada lista de DataPoint.value en el clúster tenga la misma longitud. get_centroid promedia cada dimensión de forma independiente y devuelve el resultado como un nuevo DataPoint.
¿Qué añade ClusterCollection más allá de una simple lista de clústeres Python?
Principalmente un contenedor tipado con soporte len(). No añade comportamiento de iteración, búsqueda o fusión más allá de lo que ya tienes en la lista de la que lo construiste.