# Dataset

## timenet.dataset

The in-memory TimeF model a connector populates during `convert()`.

### Sample `dataclass`

One logical unit of time-series data: a recording, a session, a sensor bundle, a market window.

Created via :meth:`~timenet.dataset.TimeFDataset.add_sample`. Mutable so `task_ids` and
`annotations` can be populated after construction.

#### annotations `class-attribute` `instance-attribute`

```
annotations: tuple[Annotation, ...] = ()
```

Annotations attached to the sample.

#### sample\_id `class-attribute` `instance-attribute`

```
sample_id: str = field(default_factory=new_id)
```

Unique id for the sample (default: an auto-generated uuid7).

#### subject\_ids `class-attribute` `instance-attribute`

```
subject_ids: tuple[str, ...] = ()
```

Subjects this sample belongs to (empty for subject-less domains).

#### task\_ids `class-attribute` `instance-attribute`

```
task_ids: tuple[str, ...] = ()
```

Ids of the tasks attached to this sample.

#### time\_series `instance-attribute`

```
time_series: tuple[TimeSeries, ...]
```

One :class:`TimeSeries` per channel the sample uses.

#### view `class-attribute` `instance-attribute`

```
view: View = View.FULL
```

Which slice of the source this sample represents (defaults to the full recording).

#### add\_annotation

```
add_annotation(annotation: Annotation) -> Annotation
```

Attach an annotation to the sample and return it.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `annotation` | `Annotation` | A `StaticAnnotation`, `PointAnnotation`, or `IntervalAnnotation`. | *required* |

Returns:

| Type | Description |
| --- | --- |
| `Annotation` | The attached annotation (the same instance). |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If a temporal annotation's `time_series_ids` is empty or references a series not on this sample, or a trial-level `IntervalAnnotation` is added when the sample's series do not share a common `(t_start_s, t_end_s)` span. |

#### to\_arrow

```
to_arrow() -> Array
```

Read the sole channel's values as an Arrow array, for the common single-channel sample.

Returns:

| Type | Description |
| --- | --- |
| `Array` | The single :class:`TimeSeries`' values as a 1-D Arrow array. |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If the sample has more than one channel; read `time_series[i]` explicitly then. |

#### to\_numpy

```
to_numpy() -> ndarray
```

Read the sole channel's values as a NumPy array (materializes :meth:`to_arrow`).

Returns:

| Type | Description |
| --- | --- |
| `ndarray` | The single :class:`TimeSeries`' values as a 1-D `np.ndarray`. |

### TimeFDataset

Holds samples and their tasks as Python objects. No I/O: persistence is the writer's concern.

#### metadata `property`

```
metadata: DatasetMetadata
```

The dataset's descriptive identity.

#### samples `property`

```
samples: tuple[Sample, ...]
```

All samples in insertion order.

#### schema `property`

```
schema: DatasetSchema | None
```

The derived schema, or `None` until :meth:`derive_schema` is called.

#### tasks `property`

```
tasks: tuple[Task, ...]
```

All tasks in insertion order.

#### add\_sample

```
add_sample(
    *,
    time_series: tuple[TimeSeries, ...],
    view: View = FULL,
    subject_ids: tuple[str, ...] = (),
    sample_id: str | None = None,
) -> Sample
```

Create a sample, register it, and return it.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `time_series` | `tuple[TimeSeries, ...]` | One :class:`TimeSeries` per channel the sample uses. | *required* |
| `view` | `View` | Which slice of the source this sample represents (defaults to the full recording). | `FULL` |
| `subject_ids` | `tuple[str, ...]` | Subjects this sample belongs to (empty for subject-less domains). | `()` |
| `sample_id` | `str | None` | An explicit id (default: an auto-generated uuid4). Pass one for deterministic output, e.g. when generating golden fixtures. | `None` |

Returns:

| Type | Description |
| --- | --- |
| `Sample` | The newly created :class:`Sample`. |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If `time_series` is empty. |

#### add\_task

```
add_task(
    samples: Sample | Iterable[Sample],
    task: Task,
    *,
    from_tasks: tuple[Task, ...] = (),
) -> Task
```

Register a task and link it to its samples.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `samples` | `Sample | Iterable[Sample]` | The sample, or samples, the task is attached to. | *required* |
| `task` | `Task` | The task instance (payload already set by the caller). | *required* |
| `from_tasks` | `tuple[Task, ...]` | Source tasks this task derives from. Overrides the task's own `from_tasks` only when non-empty, so a task constructed with `from_tasks=` is not clobbered. | `()` |

Returns:

| Type | Description |
| --- | --- |
| `Task` | The registered task (same instance, with `sample_ids` populated). |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If `samples` is empty, or a `LabelingTask`'s `time_series_ids` does not resolve to a series on every target sample. |

#### derive\_schema

```
derive_schema() -> DatasetSchema
```

Walk the dataset's instances and build its :class:`DatasetSchema`.

Collects the distinct spec, data-source, annotation, and task types, stores the result on the
dataset, and returns it.

Returns:

| Type | Description |
| --- | --- |
| `DatasetSchema` | The derived :class:`DatasetSchema`. |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If one annotation key yields conflicting descriptors across samples (e.g. the same key seen with different value types or units). |

#### describe

```
describe(
    *, rows: int = 5, file: TextIO | None = None
) -> None
```

Print a plain-text summary: identity, counts, specs/columns, and a sample preview.

Like pandas' `describe`/`info`. The preview reads only span metadata (no series values);
value dtypes are sampled from one series per spec. Works before :meth:`derive_schema` since
everything is computed from the samples.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `rows` | `int` | Number of samples to show in the preview. | `5` |
| `file` | `TextIO | None` | Where to write (defaults to `sys.stdout`). | `None` |

#### from\_parts `classmethod`

```
from_parts(
    *,
    metadata: DatasetMetadata,
    samples: Iterable[Sample],
    tasks: Iterable[Task],
    schema: DatasetSchema,
) -> TimeFDataset
```

Build a dataset from already-constructed parts (used by the reader on read-back).

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `metadata` | `DatasetMetadata` | The dataset's descriptive identity. | *required* |
| `samples` | `Iterable[Sample]` | Fully-built samples (their loaders pull from disk). | *required* |
| `tasks` | `Iterable[Task]` | Fully-built tasks with resolved `from_tasks`. | *required* |
| `schema` | `DatasetSchema` | The schema reconstructed from the manifest. | *required* |

Returns:

| Type | Description |
| --- | --- |
| `TimeFDataset` | The hydrated dataset. |

#### tasks\_for

```
tasks_for(sample: Sample) -> tuple[Task, ...]
```

```
tasks_for(
    sample: Sample, task_type: type[TTask]
) -> tuple[TTask, ...]
```

```
tasks_for(
    sample: Sample, task_type: type[Task] = Task
) -> tuple[Task, ...]
```

Return the tasks attached to a sample, optionally filtered by type.

The inverse of the stored direction: tasks reference their samples, so this resolves a
sample's `task_ids` back to the task objects.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `sample` | `Sample` | The sample whose tasks to resolve. | *required* |
| `task_type` | `type[Task]` | Keep only tasks of this subclass (defaults to every task on the sample). | `Task` |

Returns:

| Type | Description |
| --- | --- |
| `tuple[Task, ...]` | The sample's tasks of `task_type`, in the sample's task order. |

#### tasks\_of

```
tasks_of(task_type: type[TTask]) -> tuple[TTask, ...]
```

Return every task of a given type, in insertion order.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `task_type` | `type[TTask]` | The task subclass to keep (e.g. :class:`~timenet.types.ClassificationTask`). | *required* |

Returns:

| Type | Description |
| --- | --- |
| `tuple[TTask, ...]` | The matching tasks. |

#### to\_features\_and\_targets

```
to_features_and_targets(
    *,
    task: type[TargetTask] | None = ...,
    output: Literal["arrow"] = ...,
    features: Literal["timestep", "series"] = ...,
) -> tuple[Array, Array]
```

```
to_features_and_targets(
    *,
    task: type[TargetTask] | None = ...,
    output: Literal["numpy"],
    features: Literal["timestep", "series"] = ...,
) -> tuple[ndarray, ndarray]
```

```
to_features_and_targets(
    *,
    task: type[TargetTask] | None = None,
    output: Literal["arrow", "numpy"] = "arrow",
    features: Literal["timestep", "series"] = "timestep",
) -> tuple[Array, Array] | tuple[ndarray, ndarray]
```

Build an `(X, y)` training pair, deferring materialization by default.

Keeps every sample with exactly one task of `task` and pairs its sole channel's values with
that task's `target`. `features` chooses the shape of `X`:

* `"timestep"` (default): one feature per point, a rectangular matrix. Needs equal-length
  samples. Arrow `FixedSizeListArray[T]`; NumPy `(n, T)` `float32`.
* `"series"`: one sequence feature per sample, so variable-length series are fine. Arrow
  `ListArray`; NumPy `(n,)` object array of 1-D arrays.

`output="arrow"` (the default) builds those straight from the series loaders with no NumPy copy
in between; `output="numpy"` materializes them. `y` is always the targets (an Arrow string
array or a 1-D NumPy array).

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `task` | `type[TargetTask] | None` | The target-bearing task type to read labels from (e.g. :class:`~timenet.types.ClassificationTask`). Omit it to infer the type when the dataset has exactly one target-bearing task type; `ForecastingTask` has no target. | `None` |
| `output` | `Literal['arrow', 'numpy']` | `"arrow"` to keep the deferred Arrow arrays, or `"numpy"` to materialize them. | `'arrow'` |
| `features` | `Literal['timestep', 'series']` | `"timestep"` for a rectangular per-point matrix, or `"series"` for one variable-length sequence per sample. | `'timestep'` |

Returns:

| Type | Description |
| --- | --- |
| `tuple[Array, Array] | tuple[ndarray, ndarray]` | `(X, y)` as two Arrow arrays (`output="arrow"`) or two NumPy arrays (`output="numpy"`). |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If `output`/`features` is invalid; if `task` is omitted and the dataset has zero or several target-bearing task types; if no sample carries exactly one such task; if a matched sample is not single-channel; or `features="timestep"` is asked of samples that are not all the same length. |

### TimeSeries `dataclass`

Reference to one channel of time-series data, with optional windowing and a lazy loader.

Identity-based equality (`eq=False`): the writer dedupes by `time_series_id`, not by value, so
reusing one instance across samples (or giving two instances the same explicit id) shares one chunk
on disk. Consumers read values through :meth:`to_arrow` / :meth:`to_numpy`; `loader` is plumbing
supplied by the connector (raw source) at curation or by :class:`~timenet.reader.TimeFReader`
(shard parquet) on read-back.

#### channel `instance-attribute`

```
channel: str
```

Name of this channel within the modality; must be non-empty.

#### loader `instance-attribute`

```
loader: Callable[[], Array]
```

Lazy callable returning the series' values as an Arrow array.

#### sampling\_rate\_hz `instance-attribute`

```
sampling_rate_hz: float
```

Sampling rate in hertz; must be positive and finite.

#### source\_id `class-attribute` `instance-attribute`

```
source_id: str | None = None
```

Optional identifier of the raw source recording.

#### spec `instance-attribute`

```
spec: TimeSeriesSpec
```

Measurement-modality contract: type tag, name, and axis units.

#### t\_end\_s `class-attribute` `instance-attribute`

```
t_end_s: float | None = None
```

Optional end of the series window in seconds; must exceed t\_start\_s.

#### t\_start\_s `class-attribute` `instance-attribute`

```
t_start_s: float = 0.0
```

Start of the series window in seconds; must be non-negative.

#### time\_series\_id `class-attribute` `instance-attribute`

```
time_series_id: str = field(default_factory=new_id)
```

Stable identity used to dedupe and share chunks; defaults to a UUIDv7.

#### from\_values `classmethod`

```
from_values(
    values: ndarray | Sequence[float],
    *,
    spec: TimeSeriesSpec,
    channel: str,
    sampling_rate_hz: float,
    source_id: str | None = None,
    time_series_id: str | None = None,
    t_start_s: float = 0.0,
    t_end_s: float | None = None,
) -> TimeSeries
```

Build a series from already-materialized values, wrapping them in a float32 loader.

The convenience path for connectors that hold an in-memory array: it caches `values` as a
float32 Arrow array behind the loader and derives `t_end_s` from the length when omitted. Use
the `loader=` constructor directly for genuinely lazy sources (files, remote shards).

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `values` | `ndarray | Sequence[float]` | The channel's values (cast to float32). | *required* |
| `spec` | `TimeSeriesSpec` | The series' measurement-modality spec. | *required* |
| `channel` | `str` | The channel name. | *required* |
| `sampling_rate_hz` | `float` | Sampling rate in hertz. | *required* |
| `source_id` | `str | None` | Optional id of the raw source recording. | `None` |
| `time_series_id` | `str | None` | Explicit id, or `None` for an auto-generated UUIDv7. | `None` |
| `t_start_s` | `float` | Start of the window in seconds. | `0.0` |
| `t_end_s` | `float | None` | End of the window in seconds, or `None` to derive it from the length. | `None` |

Returns:

| Type | Description |
| --- | --- |
| `TimeSeries` | The constructed :class:`TimeSeries`. |

#### to\_arrow

```
to_arrow() -> Array
```

Read the series' values as an Arrow array.

Returns:

| Type | Description |
| --- | --- |
| `Array` | The series' 1-D Arrow array of values, produced by `loader`. |

#### to\_numpy

```
to_numpy() -> ndarray
```

Read the series' values as a NumPy array.

Returns:

| Type | Description |
| --- | --- |
| `ndarray` | The series' values as a 1-D `np.ndarray`. |
