Source code for scitex_dataset.general.openml
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
OpenML API client for machine learning dataset discovery.
OpenML is an open platform for sharing machine learning datasets,
tasks, and experiments. It hosts thousands of curated ML datasets.
API Documentation: https://www.openml.org/apis
"""
from typing import Optional
import httpx
from scitex_dev.decorators import supports_return_as
OPENML_API = "https://www.openml.org/api/v1/json"
[docs]
@supports_return_as
def fetch_datasets(
offset: int = 0,
limit: int = 100,
status: str = "active",
) -> dict:
"""
Fetch datasets from OpenML.
Parameters
----------
offset : int
Offset for pagination.
limit : int
Number of results per request (max 10000).
status : str
Dataset status filter: 'active', 'deactivated', 'all'.
Returns
-------
dict
API response with dataset list.
"""
params = {
"offset": offset,
"limit": limit,
"status": status,
}
response = httpx.get(
f"{OPENML_API}/data/list",
params=params,
timeout=60,
)
response.raise_for_status()
return response.json()
[docs]
@supports_return_as
def fetch_all_datasets(
max_datasets: Optional[int] = None,
page_size: int = 100,
logger=None,
) -> list[dict]:
"""
Fetch all datasets from OpenML with pagination.
Parameters
----------
max_datasets : int, optional
Maximum number of datasets to fetch.
page_size : int
Datasets per request.
logger : optional
Logger for progress messages.
Returns
-------
list[dict]
List of raw dataset dictionaries.
"""
all_datasets = []
offset = 0
while True:
if logger:
logger.info(f"Fetching OpenML offset {offset}...")
try:
data = fetch_datasets(offset=offset, limit=page_size)
except httpx.HTTPStatusError as e:
if e.response.status_code == 412:
# 412 = no results at this offset
break
raise
datasets = data.get("data", {}).get("dataset", [])
if not datasets:
break
all_datasets.extend(datasets)
if logger:
logger.info(
f" Retrieved {len(datasets)} records (total: {len(all_datasets)})"
)
if max_datasets and len(all_datasets) >= max_datasets:
all_datasets = all_datasets[:max_datasets]
break
if len(datasets) < page_size:
break
offset += page_size
return all_datasets
[docs]
@supports_return_as
def format_dataset(record: dict) -> dict:
"""
Format an OpenML dataset into a standardized dataset dictionary.
Parameters
----------
record : dict
Raw OpenML dataset from list API.
Returns
-------
dict
Standardized dataset dictionary.
"""
did = record.get("did", "")
name = record.get("name", "")
n_instances = record.get("NumberOfInstances", 0)
n_features = record.get("NumberOfFeatures", 0)
n_classes = record.get("NumberOfClasses", 0)
n_missing = record.get("NumberOfMissingValues", 0)
# Qualities that OpenML provides
qualities = record.get("quality", [])
quality_dict = {}
if isinstance(qualities, list):
for q in qualities:
if isinstance(q, dict):
quality_dict[q.get("name", "")] = q.get("value", "")
return {
"id": str(did),
"doi": "",
"name": name,
"description": "",
"created": record.get("upload_date", ""),
"modified": record.get("upload_date", ""),
"version": str(record.get("version", "")),
"authors": [],
"keywords": [],
"license": "",
"n_instances": int(n_instances) if n_instances else 0,
"n_features": int(n_features) if n_features else 0,
"n_classes": int(n_classes) if n_classes else 0,
"n_missing_values": int(n_missing) if n_missing else 0,
"n_downloads": int(record.get("NumberOfDownloads", 0) or 0),
"views": 0,
"downloads": int(record.get("NumberOfDownloads", 0) or 0),
"url": f"https://www.openml.org/d/{did}",
"source": "openml",
}
# EOF