class_docstr: PyTorch Dataset for fitting timeseries models.
  
  The dataset automates common tasks such as
  
  * scaling and encoding of variables
  * normalizing the target variable
  * efficiently converting timeseries in pandas dataframes to torch tensors
  * holding information about static and time-varying variables known and unknown in the future
  * holiding information about related categories (such as holidays)
  * downsampling for data augmentation
  * generating inference, validation and test datasets
  * etc.
class_docstr_tok: ["PyTorch","Dataset","for","fitting","timeseries","models",".","The","dataset","automates","common","tasks","such","as","*","scaling","and","encoding","of","variables","*","normalizing","the","target","variable","*","efficiently","converting","timeseries","in","pandas","dataframes","to","torch","tensors","*","holding","information","about","static","and","time-varying","variables","known","and","unknown","in","the","future","*","holiding","information","about","related","categories","(","such","as","holidays",")","*","downsampling","for","data","augmentation","*","generating","inference",",","validation","and","test","datasets","*","etc","."]
docstr: Collate function to combine items into mini-batch for dataloader.
  
  Args:
      batches (List[Tuple[Dict[str, torch.Tensor], torch.Tensor]]): List of samples generated with
          :py:meth:`~__getitem__`.
  
  Returns:
      Tuple[Dict[str, torch.Tensor], Tuple[Union[torch.Tensor, List[torch.Tensor]], torch.Tensor]: minibatch
code: def _collate_fn(
      batches: List[Tuple[Dict[str, torch.Tensor], torch.Tensor]]
  ) -> Tuple[Dict[str, torch.Tensor], torch.Tensor]:
      """
      Collate function to combine items into mini-batch for dataloader.
  
      Args:
          batches (List[Tuple[Dict[str, torch.Tensor], torch.Tensor]]): List of samples generated with
              :py:meth:`~__getitem__`.
  
      Returns:
          Tuple[Dict[str, torch.Tensor], Tuple[Union[torch.Tensor, List[torch.Tensor]], torch.Tensor]: minibatch
      """
      # collate function for dataloader
      # lengths
      encoder_lengths = torch.tensor(
          [batch[0]["encoder_length"] for batch in batches],
          dtype=torch.long,
      )
      decoder_lengths = torch.tensor(
          [batch[0]["decoder_length"] for batch in batches],
          dtype=torch.long,
      )
  
      # ids
      decoder_time_idx_start = (
          torch.tensor(
              [batch[0]["encoder_time_idx_start"] for batch in batches],
              dtype=torch.long,
          )
          + encoder_lengths
      )
      decoder_time_idx = decoder_time_idx_start.unsqueeze(
          1
      ) + torch.arange(decoder_lengths.max()).unsqueeze(0)
      groups = torch.stack([batch[0]["groups"] for batch in batches])
  
      # features
      encoder_cont = rnn.pad_sequence(
          [
              batch[0]["x_cont"][:length]
              for length, batch in zip(encoder_lengths, batches)
          ],
          batch_first=True,
      )
      encoder_cat = rnn.pad_sequence(
          [
              batch[0]["x_cat"][:length]
              for length, batch in zip(encoder_lengths, batches)
          ],
          batch_first=True,
      )
  
      decoder_cont = rnn.pad_sequence(
          [
              batch[0]["x_cont"][length:]
              for length, batch in zip(encoder_lengths, batches)
          ],
          batch_first=True,
      )
      decoder_cat = rnn.pad_sequence(
          [
              batch[0]["x_cat"][length:]
              for length, batch in zip(encoder_lengths, batches)
          ],
          batch_first=True,
      )
  
      # target scale
      if isinstance(
          batches[0][0]["target_scale"], torch.Tensor
      ):  # stack tensor
          target_scale = torch.stack(
              [batch[0]["target_scale"] for batch in batches]
          )
      elif isinstance(batches[0][0]["target_scale"], (list, tuple)):
          target_scale = []
          for idx in range(len(batches[0][0]["target_scale"])):
              if isinstance(
                  batches[0][0]["target_scale"][idx], torch.Tensor
              ):  # stack tensor
                  scale = torch.stack(
                      [
                          batch[0]["target_scale"][idx]
                          for batch in batches
                      ]
                  )
              else:
                  scale = torch.from_numpy(
                      np.array(
                          [
                              batch[0]["target_scale"][idx]
                              for batch in batches
                          ],
                          dtype=np.float32,
                      ),
                  )
              target_scale.append(scale)
      else:  # convert to tensor
          target_scale = torch.from_numpy(
              np.array(
                  [batch[0]["target_scale"] for batch in batches],
                  dtype=np.float32,
              ),
          )
  
      # target and weight
      if isinstance(batches[0][1][0], (tuple, list)):
          target = [
              rnn.pad_sequence(
                  [batch[1][0][idx] for batch in batches],
                  batch_first=True,
              )
              for idx in range(len(batches[0][1][0]))
          ]
          encoder_target = [
              rnn.pad_sequence(
                  [
                      batch[0]["encoder_target"][idx]
                      for batch in batches
                  ],
                  batch_first=True,
              )
              for idx in range(len(batches[0][1][0]))
          ]
      else:
          target = rnn.pad_sequence(
              [batch[1][0] for batch in batches], batch_first=True
          )
          encoder_target = rnn.pad_sequence(
              [batch[0]["encoder_target"] for batch in batches],
              batch_first=True,
          )
  
      if batches[0][1][1] is not None:
          weight = rnn.pad_sequence(
              [batch[1][1] for batch in batches], batch_first=True
          )
      else:
          weight = None
  
      return (
          dict(
              encoder_cat=encoder_cat,
              encoder_cont=encoder_cont,
              encoder_target=encoder_target,
              encoder_lengths=encoder_lengths,
              decoder_cat=decoder_cat,
              decoder_cont=decoder_cont,
              decoder_target=target,
              decoder_lengths=decoder_lengths,
              decoder_time_idx=decoder_time_idx,
              groups=groups,
              target_scale=target_scale,
          ),
          (target, weight),
      )
  
imports: from copy import copy, deepcopy
  from functools import lru_cache
  import inspect
  from typing import Any, Callable, Dict, List, Tuple, Union
  import warnings
  import matplotlib.pyplot
  import numpy
  import pandas
  from sklearn.exceptions import NotFittedError
  from sklearn.preprocessing import RobustScaler, StandardScaler
  from sklearn.utils.validation import check_is_fitted
  import torch
  from torch.distributions import Beta
  from torch.nn.utils import rnn
  from torch.utils.data import DataLoader, Dataset
  from torch.utils.data.sampler import Sampler, SequentialSampler
  from pytorch_forecasting.data.encoders import EncoderNormalizer, GroupNormalizer, MultiNormalizer, NaNLabelEncoder, TorchNormalizer
  from pytorch_forecasting.data.samplers import TimeSynchronizedBatchSampler
  from pytorch_forecasting.utils import repr_class
label_desc: Use image node_id 37 for calling the TimeSeriesDataSet obj's underlying member method code with example usage: obj._collate_fn(batches) and returns: dict,  target,  weight