Parquet एक्सपोर्ट
Potato annotations को Apache Parquet में export करें, जो pandas, DuckDB, Spark, Polars और Hugging Face Datasets के साथ बड़े पैमाने के विश्लेषण के लिए एक columnar format है।
v2.3.0 में नया
Apache Parquet analytical workloads के लिए बना एक columnar storage format है। बड़े annotation datasets के लिए यह JSON या CSV से बेहतर compress करता है, बाकी file को छुए बिना columns का एक subset पढ़ता है, और pandas, DuckDB, PyArrow, Spark, Polars और Hugging Face Datasets में सीधे load होता है।
Parquet export के लिए PyArrow चाहिए:
pip install "pyarrow>=12.0.0"Export चलाना
Parquet, Potato के registered export formats में से एक है, इसलिए export CLI इसे सीधे लिखता है:
python -m potato.export -c config.yaml -f parquet -o ./parquet_export/Potato config के output_annotation_dir में दर्ज annotations पढ़ता है और Parquet tables को आपके बताए output directory में लिखता है।
तय अंतराल पर Export
लंबे समय तक चलने वाले study में आमतौर पर Parquet snapshot चाहिए होता है, बिना इस पर निर्भर हुए कि कोई CLI चलाना याद रखे। export_annotation_format set करने पर Potato annotation चलते समय समय-समय पर export लिखता है:
output_annotation_dir: "output/"
# A list is accepted, so Parquet can sit alongside another format
export_annotation_format:
- parquet
- jsonl
# Seconds between automatic exports (default: 60)
auto_export_interval: 300Auto-exports <output_annotation_dir>/exports/<format>/ में जाते हैं, इसलिए Parquet tables output/exports/parquet/ के अंतर्गत दिखती हैं। Annotations खुद इस setting से स्वतंत्र, हमेशा <output_annotation_dir>/<user>/user_state.json के रूप में store होते हैं।
पुरानी output_annotation_format key deprecated है। Potato इसे export_annotation_format के रूप में पढ़ता है और एक warning log करता है, इसलिए इसका नाम बदल दें।
Output Files
एक export अधिकतम चार tables बनाता है, और हर table data के एक अलग स्तर को cover करती है।
annotations.parquet
हर (instance, annotator) जोड़ी के लिए एक row, जिसमें schemas columns में flatten किए जाते हैं।
| Column | Type | विवरण |
|---|---|---|
instance_id | string | Annotate किए गए item का ID |
user_id | string | Annotator का ID |
| <schema_name> | बदलता है | हर annotation schema के लिए एक column |
Column types annotation type के अनुसार होते हैं: radio और select चुने गए label वाली strings बनते हैं, likert, slider और number float64 बनते हैं (या named labels वाले scale के लिए string), multiselect strings की list बनता है, और text string बनता है।
जो schema एक साथ कई answers store करता है, उसे हर sub-answer के लिए एक column मिलता है, जिसका नाम <schema>.<key> होता है। handling नाम का एक multirate schema handling.Urgency और handling.Customer tone बनाता है; constant_sum और soft_label भी इसी तरह बँटते हैं। Single-select एक ही column में रहता है, क्योंकि dataframe में काम की चीज़ severity में "Serious" होना है।
हर column हर row में मौजूद होता है, और जहाँ annotator ने जवाब नहीं दिया वहाँ null भरा जाता है, इसलिए जिस schema तक केवल कुछ annotators पहुँचे, वह भी file में मौजूद रहता है।
spans.parquet
हर span annotation के लिए एक row, जो तब लिखी जाती है जब study में span schemas हों।
| Column | Type | विवरण |
|---|---|---|
instance_id | string | Annotate किए गए item का ID |
user_id | string | Annotator का ID |
schema_name | string | Span schema का नाम |
start | int | वह character offset जहाँ span शुरू होता है |
end | int | वह character offset जहाँ span खत्म होता है |
label | string | Span का label |
text | string | Span का text content |
target_field | string | वह display field जिसमें span बनाया गया, single-field page पर "" |
title | string | Label का display title |
span_id | string | Stored span का id, schema_label_start_end |
format_coords | string | JSON: PDF span के लिए page और box, spreadsheet span के लिए row और column |
additional_parts | string | JSON: discontinuous span के बाकी ranges |
kb_id, kb_source, kb_label | string | वह entity जिसकी ओर linked span इशारा करता है |
जब भी किसी study में एक से ज़्यादा span target हों, target_field पढ़ें। एक ही span schema page के हर span-target field में record करता है, इसलिए field एक schema के भीतर बदलता रहता है, और span_id से उसे वापस नहीं निकाला जा सकता: दो fields में mark किए गए वही शब्द ऐसी rows बनाते हैं जो बाकी हर तरह से एक जैसी होती हैं।
text को store नहीं किया जाता, बल्कि export के समय offsets से निकाला जाता है, इसलिए यह उनसे कभी असहमत नहीं हो सकता।
items.parquet
हर source item के लिए एक row, जिसमें original data होता है।
| Column | Type | विवरण |
|---|---|---|
item_id | string | Item का ID |
| <field_name> | बदलता है | Original data के हर field के लिए एक column (nested dicts और lists JSON में serialize होती हैं) |
phase_responses.parquet
तब लिखी जाती है जब study ने phase data इकट्ठा किया हो, जैसे consent form या post-study survey, और export_include_phase_data true हो। इस key का default false है, इसलिए जिस study ने consent और post-study questionnaire इकट्ठा किया, उसे तब तक कोई phase_responses.parquet नहीं मिलता जब तक आप इसे चालू न करें, और export छोड़े गए responses को एक warning में सूचीबद्ध करता है।
Export Options
Format options --option key=value से दें, हर option के लिए flag दोहराते हुए:
python -m potato.export -c config.yaml -f parquet -o ./parquet_export/ \
--option compression=zstd --option include_items=false| Option | Default | विवरण |
|---|---|---|
compression | snappy | Compression codec: snappy, gzip, zstd, lz4, या none |
include_items | true | Source data के साथ items.parquet लिखें |
include_spans | true | Span annotations होने पर spans.parquet लिखें |
row_group_size | PyArrow default | annotations.parquet के लिए row group size |
ज़्यादातर projects के लिए snappy सही default है, क्योंकि यह इतनी तेज़ी से decompress करता है कि reads interactive बनी रहती हैं। जब dataset इतना बड़ा हो कि file size मायने रखे, तब zstd चुनें, क्योंकि यह लगभग उसी speed पर काफ़ी बेहतर compress करता है।
Parquet Data लोड करना
pandas
import pandas as pd
annotations = pd.read_parquet("parquet_export/annotations.parquet")
spans = pd.read_parquet("parquet_export/spans.parquet")
items = pd.read_parquet("parquet_export/items.parquet")
# One column per schema, so a schema is selected by name
print(annotations["sentiment"].value_counts())
# Compute inter-annotator agreement on the sentiment schema
from sklearn.metrics import cohen_kappa_score
pivot = annotations.pivot(index="instance_id", columns="user_id", values="sentiment")
kappa = cohen_kappa_score(pivot.iloc[:, 0], pivot.iloc[:, 1])DuckDB
-- Direct query without loading into memory
SELECT instance_id, sentiment, COUNT(*) AS annotator_count
FROM 'parquet_export/annotations.parquet'
GROUP BY instance_id, sentiment
ORDER BY annotator_count DESC;
-- Join annotations with the source items
SELECT a.instance_id, i.text, a.sentiment, a.user_id
FROM 'parquet_export/annotations.parquet' a
JOIN 'parquet_export/items.parquet' i
ON a.instance_id = i.item_id;PyArrow
import pyarrow.parquet as pq
# Read specific columns only (fast for wide tables)
table = pq.read_table(
"parquet_export/annotations.parquet",
columns=["instance_id", "user_id", "sentiment"]
)
df = table.to_pandas()
parquet_file = pq.ParquetFile("parquet_export/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
dataset = load_dataset("parquet", data_files={
"annotations": "parquet_export/annotations.parquet",
"spans": "parquet_export/spans.parquet",
"items": "parquet_export/items.parquet",
})
print(dataset["annotations"][0])
dataset["annotations"].push_to_hub("my-org/my-annotations", split="train")Potato एक huggingface exporter भी देता है जो यही splits सीधे बनाता है, जिससे Hub destination होने पर intermediate files की ज़रूरत नहीं पड़ती।
Polars
import polars as pl
annotations = pl.read_parquet("parquet_export/annotations.parquet")
label_counts = (
annotations
.group_by("sentiment")
.agg(pl.len().alias("count"))
.sort("count", descending=True)
)
print(label_counts)पूर्ण उदाहरण
एक span-annotation project जो JSONL को working format के रूप में रखता है और विश्लेषण के लिए उसके साथ Parquet भी लिखता है:
annotation_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
description: "Highlight named entities"
labels:
- name: PERSON
- name: ORGANIZATION
- name: LOCATION
output_annotation_dir: "output/"
# Both formats are written periodically to output/exports/<format>/
export_annotation_format:
- jsonl
- parquet
auto_export_interval: 300
user_config:
allow_all_users: trueAnnotation के बाद, span table ही entity offsets रखती है:
import pandas as pd
spans = pd.read_parquet("output/exports/parquet/spans.parquet")
# Entity type distribution
print(spans["label"].value_counts())
# Average span length by type
spans["length"] = spans["end"] - spans["start"]
print(spans.groupby("label")["length"].mean())आगे पढ़ें
- निर्यात प्रारूप: COCO, YOLO, CoNLL, और बाकी registered exporters
- रिमोट डेटा स्रोत: cloud storage से data load करना
- एडमिन डैशबोर्ड: annotation progress की निगरानी
कार्यान्वयन विवरण के लिए, स्रोत दस्तावेज़ देखें।