Exportación Parquet
Exporta anotaciones al formato Apache Parquet para procesamiento eficiente de datos a gran escala.
Exportación Parquet
Nuevo en v2.3.0
Apache Parquet es un formato de almacenamiento columnar optimizado para cargas de trabajo analíticas. Ofrece ventajas significativas sobre JSON y CSV para conjuntos de datos de anotación grandes: tamaños de archivo más pequeños (típicamente 5-10x de compresión), lecturas más rápidas para consultas de subconjuntos de columnas y soporte nativo en prácticamente todas las herramientas de ciencia de datos (pandas, DuckDB, PyArrow, Spark, Polars, Hugging Face Datasets).
Potato puede exportar anotaciones directamente al formato Parquet, produciendo tres archivos estructurados que cubren todos los tipos de anotación.
Habilitar la Exportación Parquet
Como Formato de Salida Principal
output_annotation_dir: "output/"
output_annotation_format: "parquet"Como Exportación Secundaria (Mantener JSON como Principal)
output_annotation_dir: "output/"
output_annotation_format: "jsonl"
parquet_export:
enabled: true
output_dir: "output/parquet/"
auto_export: true # export after each annotation sessionBajo Demanda vía CLI
python -m potato.export parquet --config config.yaml --output ./parquet_output/Archivos de Salida
La exportación Parquet produce tres archivos, cada uno representando un nivel diferente de los datos de anotación.
1. annotations.parquet
El archivo de salida principal. Una fila por combinación de (instancia, anotador, esquema).
| Columna | Tipo | Descripción |
|---|---|---|
instance_id | string | Identificador de la instancia |
annotator | string | Nombre de usuario del anotador |
schema_name | string | Nombre del esquema de anotación |
value | string | Valor de la anotación (codificado en JSON para tipos complejos) |
timestamp | timestamp | Cuándo se creó la anotación |
duration_ms | int64 | Tiempo dedicado a esta instancia (milisegundos) |
session_id | string | Identificador de la sesión de anotación |
Para tipos de anotación simples (radio, likert, text), value contiene el valor en bruto. Para tipos complejos (multiselect, spans, events), value contiene una cadena JSON.
2. spans.parquet
Para tipos de anotación basados en spans (span, span_link, event_annotation, coreference). Una fila por span anotado.
| Columna | Tipo | Descripción |
|---|---|---|
instance_id | string | Identificador de la instancia |
annotator | string | Nombre de usuario del anotador |
schema_name | string | Nombre del esquema de anotación |
span_id | string | Identificador único del span |
text | string | Contenido textual del span |
start_offset | int32 | Desplazamiento de carácter inicial |
end_offset | int32 | Desplazamiento de carácter final |
label | string | Etiqueta del span |
field | string | Campo fuente (para anotación de span multi-campo) |
links | string | Datos de enlace codificados en JSON (para span_link) |
attributes | string | Atributos adicionales codificados en JSON |
3. items.parquet
Metadatos sobre cada instancia en el conjunto de datos. Una fila por instancia.
| Columna | Tipo | Descripción |
|---|---|---|
instance_id | string | Identificador de la instancia |
text | string | Contenido textual principal |
annotation_count | int32 | Número de anotaciones recibidas |
annotators | string | Lista JSON de nombres de usuario de anotadores |
status | string | Estado de la instancia (pending, in_progress, complete) |
metadata | string | Metadatos de la instancia codificados en JSON |
Opciones de Compresión
parquet_export:
enabled: true
output_dir: "output/parquet/"
compression: snappy # snappy (default), gzip, zstd, lz4, brotli, none
row_group_size: 50000 # rows per row group (affects read performance)
use_dictionary: true # dictionary encoding for string columns
write_statistics: true # column statistics for query optimizationComparación de Compresión
| Algoritmo | Ratio de Compresión | Velocidad de Escritura | Velocidad de Lectura | Mejor Para |
|---|---|---|---|---|
snappy | Moderado | Rápido | Rápido | Uso general (por defecto) |
gzip | Alto | Lento | Moderado | Archivado, archivos pequeños |
zstd | Alto | Rápido | Rápido | Mejor equilibrio de tamaño y velocidad |
lz4 | Bajo | Muy Rápido | Muy Rápido | Cargas de trabajo críticas en velocidad |
brotli | Muy Alto | Muy Lento | Moderado | Compresión máxima |
none | Ninguno | Más Rápido | Más Rápido | Depuración |
Para la mayoría de los proyectos de anotación, la compresión snappy por defecto es una buena opción. Para conjuntos de datos grandes donde el tamaño del archivo importa, usa zstd.
Cargar Datos Parquet
pandas
import pandas as pd
annotations = pd.read_parquet("output/parquet/annotations.parquet")
spans = pd.read_parquet("output/parquet/spans.parquet")
items = pd.read_parquet("output/parquet/items.parquet")
# Filter to a specific schema
sentiment = annotations[annotations["schema_name"] == "sentiment"]
# Compute inter-annotator agreement
from sklearn.metrics import cohen_kappa_score
pivot = sentiment.pivot(index="instance_id", columns="annotator", values="value")
kappa = cohen_kappa_score(pivot.iloc[:, 0], pivot.iloc[:, 1])DuckDB
-- Direct query without loading into memory
SELECT instance_id, value, COUNT(*) as annotator_count
FROM 'output/parquet/annotations.parquet'
WHERE schema_name = 'sentiment'
GROUP BY instance_id, value
ORDER BY annotator_count DESC;
-- Join annotations with items
SELECT a.instance_id, i.text, a.value, a.annotator
FROM 'output/parquet/annotations.parquet' a
JOIN 'output/parquet/items.parquet' i
ON a.instance_id = i.instance_id
WHERE a.schema_name = 'sentiment';PyArrow
import pyarrow.parquet as pq
# Read specific columns only (fast for wide tables)
table = pq.read_table(
"output/parquet/annotations.parquet",
columns=["instance_id", "value", "annotator"]
)
# Convert to pandas
df = table.to_pandas()
# Read with row group filtering
parquet_file = pq.ParquetFile("output/parquet/annotations.parquet")
print(f"Row groups: {parquet_file.metadata.num_row_groups}")
print(f"Total rows: {parquet_file.metadata.num_rows}")Hugging Face Datasets
from datasets import load_dataset
# Load directly from Parquet files
dataset = load_dataset("parquet", data_files={
"annotations": "output/parquet/annotations.parquet",
"spans": "output/parquet/spans.parquet",
"items": "output/parquet/items.parquet",
})
# Access as a regular HF dataset
print(dataset["annotations"][0])
# Push to Hugging Face Hub
dataset["annotations"].push_to_hub("my-org/my-annotations", split="train")Polars
import polars as pl
annotations = pl.read_parquet("output/parquet/annotations.parquet")
# Fast aggregation
label_counts = (
annotations
.filter(pl.col("schema_name") == "sentiment")
.group_by("value")
.agg(pl.count().alias("count"))
.sort("count", descending=True)
)
print(label_counts)Exportación Incremental
Para proyectos de anotación de larga duración, habilita la exportación incremental para evitar re-exportar todo el conjunto de datos cada vez:
parquet_export:
enabled: true
output_dir: "output/parquet/"
incremental: true
partition_by: date # date, annotator, or noneCon partition_by: date, los archivos Parquet se organizan en directorios particionados por fecha:
output/parquet/
annotations/
date=2026-03-01/part-0.parquet
date=2026-03-02/part-0.parquet
date=2026-03-03/part-0.parquet
spans/
date=2026-03-01/part-0.parquet
items/
part-0.parquet
Los conjuntos de datos particionados se pueden leer como una sola tabla lógica por todas las herramientas principales:
# pandas reads partitioned directories automatically
df = pd.read_parquet("output/parquet/annotations/")
# DuckDB handles partitions natively
# SELECT * FROM 'output/parquet/annotations/**/*.parquet'Referencia de Configuración
parquet_export:
enabled: true
output_dir: "output/parquet/"
# When to export
auto_export: true # export after each session (default: false)
export_on_shutdown: true # export when server stops (default: true)
# File settings
compression: snappy
row_group_size: 50000
use_dictionary: true
write_statistics: true
# Incremental settings
incremental: false
partition_by: none # none, date, annotator
# Schema-specific options
flatten_complex_types: false # flatten JSON values into columns
include_raw_json: true # include raw JSON alongside flattened columns
# Span export
export_spans: true # generate spans.parquet
export_items: true # generate items.parquetEjemplo Completo
task_name: "NER Annotation Project"
task_dir: "."
data_files:
- "data/documents.jsonl"
item_properties:
id_key: doc_id
text_key: text
annotation_schemes:
- annotation_type: span
name: entities
labels:
- name: PERSON
color: "#3b82f6"
- name: ORGANIZATION
color: "#22c55e"
- name: LOCATION
color: "#f59e0b"
output_annotation_dir: "output/"
output_annotation_format: "jsonl"
parquet_export:
enabled: true
output_dir: "output/parquet/"
compression: zstd
auto_export: true
export_spans: true
export_items: trueDespués de la anotación, carga y analiza:
import pandas as pd
spans = pd.read_parquet("output/parquet/spans.parquet")
# Entity type distribution
print(spans["label"].value_counts())
# Average span length by type
spans["length"] = spans["end_offset"] - spans["start_offset"]
print(spans.groupby("label")["length"].mean())Lecturas Adicionales
- Export Formats -- COCO, YOLO, CoNLL y otros formatos de exportación
- Remote Data Sources -- carga de datos desde almacenamiento en la nube
- Admin Dashboard -- monitoreo del estado de exportación
Para detalles de implementación, consulta la documentación fuente.