# API Details: zyplib.dataset Full Parameter Reference

## fileseg_pipeline / basic_pipeline

```python
fileseg_pipeline(
    files: Sequence[str],
    fn_read: ReadFunction,              # (file_path: str) -> ndarray
    label: int | LabelFunction,         # int or (file_path: str) -> int | list[int]
    fn_segment: SegmentFunction | None, # (signal: [C, T]) -> [N, C, T], None skips segmentation
    fn_before_segment: SignalProcessFunction | None,  # pre-segment processing
    fn_after_segment: SignalProcessFunction | None,    # post-segment processing
    fn_encode_label: EncodeLabelFunction | None,       # default: to_onehot(squeeze_2_class=True)
    show_progress: bool = True,
    random_shuffle: bool | int = False,  # False=no shuffle, True=random shuffle, int=seeded shuffle
) -> tuple[ndarray, ndarray]  # (X, y)
```

Callback signatures:

| Callback | Signature | Description |
|----------|-----------|-------------|
| `fn_read` | `(file_path: str) -> ndarray` | Read a single file, return [C, T] signal |
| `fn_segment` | `(signal: ndarray) -> ndarray` | Input [C, T], output [N, C, T] |
| `label` | `int` or `(file_path: str) -> int \| list[int]` | Constant int or file-path-based label |
| `fn_before_segment` | `(signal: ndarray) -> ndarray` | [C, T] -> [C, T] preprocessing |
| `fn_after_segment` | `(signal: ndarray) -> ndarray` | [N, C, T] -> [N, C, T] post-processing |
| `fn_encode_label` | `(label: Sequence[int] \| ndarray) -> ndarray` | Label encoding, default onehot |

`fn_encode_label` default behavior: calls `to_onehot(label, squeeze_2_class=True)`. For binary classification, labels are reshaped to `[N, 1]` (not squeezed to 1D). For multi-class, labels become one-hot `[N, n_classes]`. Passing `None` still uses the default (due to `fn_encode_label or _default_encode_label` in source); to truly skip encoding, pass an identity function like `lambda labels: np.asarray(labels)`.

`random_shuffle` uses an independent `np.random.RandomState` and does not affect global random state.

## fileloader_pipeline / simple_pipeline

```python
fileloader_pipeline(
    files: Sequence[str],
    fn_fileloader: TransformFunction,   # (file_path: str) -> (ndarray, ndarray)
    fn_encode_label: EncodeLabelFunction | None,
    show_progress: bool = True,
    random_shuffle: bool | int = False,
) -> tuple[ndarray, ndarray]
```

The y arrays returned by `fn_fileloader` are concatenated (not extended), so y must be an ndarray, not an int list.

## train_test_pipeline

```python
train_test_pipeline(
    split_size: float | int | tuple,
    all_files: Sequence[str] | Sequence[Sequence[str]],
    random_seed: int | None = None,
    return_split_files: bool = False,
    *,
    fn_pipeline: FuncPipeline | Literal['fileseg', 'fileloader', 'basic', 'simple'],
    pipeline_kwargs: Mapping | None = None,
)
```

`split_size` semantics:

| Form | Meaning | Returns |
|------|---------|---------|
| `float` (e.g. `0.8`) | Train set ratio, remainder is test | `X_train, X_test, y_train, y_test` |
| `int` (e.g. `50`) | Train set file count, remainder is test | Same as above |
| `(train, test)` | 2-way split | Same as above |
| `(train, val, test)` | 3-way split | `X_train, X_val, X_test, y_train, y_val, y_test` |

Sizes can be `int` (absolute count) or `float` (ratio).

`all_files` grouping mechanism:
- `list[str]`: Split the entire list directly
- `(group_a, group_b, ...)`: Each group is split independently by ratio, then merged. Used to maintain class balance.

When `return_split_files=True`, the split file lists are appended after the data arrays in the return value.

When `fn_pipeline` is a string, use `pipeline_kwargs` to pass arguments to the corresponding pipeline function.

## kfold_pipeline

```python
kfold_pipeline(
    k: int,
    all_files: Sequence[str] | Sequence[Sequence[str]],
    random_seed: int | None = None,
    yield_split_files: bool = False,
    *,
    fn_pipeline: FuncPipeline | Literal['fileseg', 'fileloader', 'basic', 'simple'],
    pipeline_kwargs: Mapping | None = None,
)
# yields: (X_train, X_val, y_train, y_val[, train_files, val_files])
```

Generator function, yields one fold's data per iteration. When `yield_split_files=True`, file lists are also yielded.

Grouping mechanism is the same as `train_test_pipeline`: each group undergoes independent K-fold, then results are merged per fold.

## make_basic_dataloader

```python
make_basic_dataloader(
    *datasets: tuple[ndarray, ndarray] | Dataset,
    batch_size: int = 64,
    num_workers: int = 0,
    pin_memory: bool = False,
    shuffle: ShuffleMode = 'shuffle-first',
    dtype: torch.dtype | tuple[torch.dtype, torch.dtype] = torch.float32,
    **kwargs,
) -> tuple[DataLoader, ...] | DataLoader
```

Return value rules:
- Multiple datasets passed -> returns `tuple[DataLoader, ...]`
- Single dataset passed -> returns a single `DataLoader` (not a tuple)

`None` and empty datasets are skipped.

### ShuffleMode reference

| Value | Behavior |
|-------|----------|
| `True` | All DataLoaders shuffle |
| `False` | No DataLoaders shuffle |
| `'shuffle-first'` | Only the first DataLoader shuffles (default, assumes train/val/test order) |
| `'shuffle-all'` | Same as `True` |
| `'shuffle-train'` | Same as `'shuffle-first'` |
| `list[bool]` | Specify per-DataLoader shuffle individually |

### dtype parameter

- Single `torch.dtype`: Applied to both data and target
- `(data_dtype, target_dtype)` tuple: Specify separately

## make_split_dataloader

```python
make_split_dataloader(
    xy: tuple[ndarray, ndarray] | Dataset,
    split_size: int | Sequence[int | float],
    batch_size: int = 64,
    shuffle: ShuffleMode = 'shuffle-first',
    ...
) -> tuple[DataLoader, ...]
```

`split_size` semantics:
- `int`: Split evenly into N parts
- `Sequence[int]`: Split by absolute counts
- `Sequence[float]`: Split by ratios

Internally uses `torch.utils.data.random_split` — this is a segment-level random split.

## make_kfold_dataloader

```python
make_kfold_dataloader(
    *,
    xy: tuple[ndarray, ndarray] | None = None,
    dataset: Dataset | None = None,
    k: int = 5,
    random_seed: int | None = None,
    batch_size: int = 64,
    shuffle: bool | tuple[bool, bool] | Literal['shuffle-train'] = 'shuffle-train',
    ...
)
# yields: (train_loader, val_loader)
```

`xy` and `dataset` — at least one must be provided. If both are given, `xy` takes priority and `dataset` is ignored.

Shuffle semantics (kfold-specific):
- `bool`: Same setting for both train and val
- `(True, False)`: Specify separately
- `'shuffle-train'`: Train shuffles, val does not (default, recommended)

## BasicXyDataset

```python
BasicXyDataset(
    data: ndarray | Tensor,
    target: ndarray | Tensor,
    data_dtype: torch.dtype = torch.float32,
    target_dtype: torch.dtype = torch.float32,
    transform: Callable | None = None,  # (x, y) -> x | (x, y)
    p_trans: float = 0,                 # probability of applying transform
    cache_transformed: bool = False,
)
```

`transform` signature: receives `(x, y)` for a single sample, returns `x` or `(x, y)`.
When `p_trans=0`, transform is never called (default behavior).

## random_split

```python
random_split(
    data: list | ndarray,
    proportion: Sequence[float] | Sequence[int],
    seed: int | None = None,
) -> list
```

Unlike `torch.utils.data.random_split`: returns actual data slices, not Subset objects.

- `float` list: Ratios, must sum to 1.0
- `int` list: Absolute counts, must sum to `len(data)`

## analyze_dataloader

```python
analyze_dataloader(
    loader: DataLoader,
    prefix_name: str = 'DataLoader',
    balance_range: tuple[float, float] = (0.4, 0.6),
    verbose: bool = True,
) -> dict
```

Returns `{'num_samples', 'num_batches', 'label_ratios', 'is_shuffle', 'balance_issues'}`.

`balance_range` defines the "balanced" label ratio range. Labels with ratios outside this range are flagged in `balance_issues`.
