102 lines
3.4 KiB
Python
102 lines
3.4 KiB
Python
from datetime import datetime
|
|
from math import ceil
|
|
from random import shuffle
|
|
from typing import Any, Iterable, List, TypeVar, cast
|
|
from uuid import uuid4
|
|
|
|
from ..constants import (
|
|
GROUND_TRUTH_TAG_NAME,
|
|
TEST_SPLIT_TAG_NAME,
|
|
TRAIN_SPLIT_TAG_NAME,
|
|
VALIDATION_SPLIT_TAG_NAME,
|
|
)
|
|
from ..context import get_context
|
|
from ..views import Trace
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
def add_ground_truth(
|
|
inputs: Iterable[Any],
|
|
expected_outputs: Iterable[T],
|
|
*,
|
|
tags: List[str] = [],
|
|
train_split_ratio: float = 1,
|
|
test_split_ratio: float = 0,
|
|
validation_split_ratio: float = 0
|
|
) -> None:
|
|
"""Add training data (with optional train-test splitting).
|
|
|
|
Add and tag datapoints, wrap them into traces. The `inputs` are available via the
|
|
`.input` property, while `expected_outputs` under both the `.output` and `.feedback`
|
|
properties.
|
|
|
|
All generated traces are tagged with `ground_truth` by default. Additional tags can
|
|
be also provided. Using the `split_ratio` arguments, tags can be given randomly with
|
|
a user-defined distribution. Only the ratio of the splits matter, they don't have to
|
|
add up to 1.
|
|
|
|
Examples:
|
|
>>> add_ground_truth(
|
|
... [1, 2, 3],
|
|
... ['odd', 'even', 'odd'],
|
|
... tags='my_tag',
|
|
... train_split_ratio=1,
|
|
... test_split_ratio=1,
|
|
... validation_split_ratio=0.5,
|
|
... )
|
|
|
|
Args:
|
|
inputs: The inputs. (X in scikit-learn)
|
|
expected_outputs: The ground-truth values corresponding to the inputs. (y in
|
|
scikit-learn)
|
|
tags: A single tag or a list of tags to append to each generated trace's tags.
|
|
train_split_ratio: The probability-weight of giving each trace the `train` tag.
|
|
test_split_ratio: The probability-weight of giving each trace the `test` tag.
|
|
validation_split_ratio: The probability-weight of giving each trace the
|
|
`validation` tag.
|
|
"""
|
|
|
|
inputs = list(inputs)
|
|
expected_outputs = list(expected_outputs)
|
|
assert len(inputs) == len(
|
|
expected_outputs
|
|
), "The length of the inputs and expected_outputs must be equal"
|
|
|
|
sum_ratio = train_split_ratio + test_split_ratio + validation_split_ratio
|
|
assert sum_ratio > 0, "The sum of the split ratios must be a positive number"
|
|
|
|
train_split_ratio /= sum_ratio
|
|
test_split_ratio /= sum_ratio
|
|
validation_split_ratio /= sum_ratio
|
|
|
|
values = list(zip(inputs, expected_outputs))
|
|
shuffle(values)
|
|
|
|
split_tags = (
|
|
[TRAIN_SPLIT_TAG_NAME] * ceil(train_split_ratio * len(inputs))
|
|
+ [TEST_SPLIT_TAG_NAME] * ceil(test_split_ratio * len(inputs))
|
|
+ [VALIDATION_SPLIT_TAG_NAME] * ceil(validation_split_ratio * len(inputs))
|
|
)
|
|
shuffle(split_tags)
|
|
|
|
created = datetime.utcnow().isoformat()
|
|
traces = [
|
|
cast(
|
|
Trace[T],
|
|
Trace( # avoid ValueError: "Trace" object has no field "__orig_class__"
|
|
trace_id=str(uuid4()),
|
|
created=created,
|
|
original_execution_time_ms=0,
|
|
logged_values=X if isinstance(X, dict) else {"input": X},
|
|
models=[],
|
|
output=y,
|
|
feedback=y,
|
|
exception=None,
|
|
tags=[GROUND_TRUTH_TAG_NAME, split_tag, *tags],
|
|
),
|
|
)
|
|
for ((X, y), split_tag) in zip(values, split_tags)
|
|
]
|
|
|
|
get_context().tracing_database.save_batch(traces)
|