| """
|
| Dataset concreto do pipeline ``atualizado`` — dados tabulares + PyTorch.
|
|
|
| A maior parte da lógica está em :class:`base_dataset.BaseDataset`
|
| (``docker/base_dataset.py``). Aqui só fica o que é específico:
|
|
|
| - :py:meth:`build_features` — seleciona colunas numéricas do DataFrame,
|
| descartando colunas de identificação (``id``, ``image_path``, ...).
|
| - :py:meth:`get_data_loader` — devolve ``DataLoader`` do PyTorch
|
| montado em cima dos arrays preparados pela base.
|
| """
|
|
|
| from __future__ import annotations
|
|
|
| import os
|
| import sys
|
| from typing import Optional, Tuple
|
|
|
| import numpy as np
|
| import pandas as pd
|
|
|
| try:
|
| import torch
|
| from torch.utils.data import DataLoader, TensorDataset
|
| _TORCH_AVAILABLE = True
|
| except ImportError:
|
| _TORCH_AVAILABLE = False
|
|
|
|
|
| sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
| from base_dataset import BaseDataset
|
|
|
|
|
| class TrainingDataset(BaseDataset):
|
| """Dataset tabular para o pipeline em ``docker/atualizado``."""
|
|
|
|
|
|
|
|
|
| def build_features(self) -> None:
|
| if self.df is None:
|
| raise RuntimeError("self.df está vazio; load_raw_data() não rodou.")
|
|
|
|
|
| explicit = self.metadata.get("features")
|
| if explicit:
|
| missing = [c for c in explicit if c not in self.df.columns]
|
| if missing:
|
| raise ValueError(
|
| f"Colunas declaradas em metadata['features'] não encontradas no DataFrame: {missing}"
|
| )
|
| self.feature_columns = list(explicit)
|
| self.X = self.df[self.feature_columns].to_numpy(dtype=np.float32)
|
| return
|
|
|
|
|
| feats = []
|
| for col in self.df.columns:
|
| if col == self.target_column:
|
| continue
|
| if col.lower() in self.NON_FEATURE_COLS:
|
| continue
|
| if not pd.api.types.is_numeric_dtype(self.df[col]):
|
| continue
|
| feats.append(col)
|
|
|
| if not feats:
|
| raise ValueError(
|
| "Nenhuma coluna numérica encontrada para usar como feature."
|
| )
|
|
|
| self.feature_columns = feats
|
| self.X = self.df[feats].to_numpy(dtype=np.float32)
|
|
|
| def get_data_loader(
|
| self,
|
| batch_size: int = 32,
|
| train_ratio: Optional[float] = None,
|
| seed: Optional[int] = None,
|
| ) -> Tuple["DataLoader", "DataLoader"]:
|
| if not _TORCH_AVAILABLE:
|
| raise RuntimeError(
|
| "PyTorch não está instalado; instale-o ou use get_arrays()."
|
| )
|
|
|
| train_ratio, seed = self._resolve_split_params(train_ratio, seed)
|
| idx_train, idx_val = self._split_indices(train_ratio, seed)
|
|
|
| assert self.X is not None and self.y is not None
|
|
|
| X_train = torch.from_numpy(self.X[idx_train])
|
| y_train = torch.from_numpy(self.y[idx_train]).long()
|
| X_val = torch.from_numpy(self.X[idx_val])
|
| y_val = torch.from_numpy(self.y[idx_val]).long()
|
|
|
| bs = self._resolve_batch_size(batch_size)
|
| train_loader = DataLoader(
|
| TensorDataset(X_train, y_train), batch_size=bs, shuffle=True
|
| )
|
| val_loader = DataLoader(
|
| TensorDataset(X_val, y_val), batch_size=bs, shuffle=False
|
| )
|
|
|
| print(
|
| f" - Train samples: {len(X_train)} | Val samples: {len(X_val)}"
|
| f" | Batch size: {bs}"
|
| )
|
| return train_loader, val_loader
|
|
|