docstr: Samples the input DataFrame and Series to
  
  Parameters
  ----------
  X : pd.DataFrame
      Feature matrix.
  y : pd.Series
      Label vector.
  s : pd.Series, optional
      Protected attribute vector.
  
  Returns
  -------
  tuple[pd.DataFrame, pd.Series, pd.Series]
      The transformed input, X, y, and s.
code: def transform(
      self, X: pd.DataFrame, y: pd.Series, s: Optional[pd.Series] = None
  ) -> tuple[pd.DataFrame, pd.Series, pd.Series]:
      """Samples the input DataFrame and Series to
  
      Parameters
      ----------
      X : pd.DataFrame
          Feature matrix.
      y : pd.Series
          Label vector.
      s : pd.Series, optional
          Protected attribute vector.
  
      Returns
      -------
      tuple[pd.DataFrame, pd.Series, pd.Series]
          The transformed input, X, y, and s.
      """
      self.logger.info("Transforming data.")
      if s is None:
          raise ValueError("Sensitive Attribute `s` not passed.")
  
      final_X = X.copy()
      final_y = y.copy()
      final_s = s.copy()
      for group, (label, size) in self.sampling_rate.items():
          self.logger.debug(
              f"Original group {group} size: {s[(s == group)].shape[0]}"
          )
          if self.strategy == "oversample":
              # Obtain indexes to resample
              sample_indexes = (
                  s[(s == group) & (y == label)]
                  .sample(n=size, replace=True, random_state=self.seed)
                  .index
              )
  
              sampled_X = X.loc[sample_indexes]
              sampled_y = y.loc[sample_indexes]
              sampled_s = s.loc[sample_indexes]
  
              final_X = pd.concat([final_X, sampled_X])
              final_y = pd.concat([final_y, sampled_y])
              final_s = pd.concat([final_s, sampled_s])
  
          else:  # Strategy = undersampling
              sample_indexes = (
                  s[(s == group) & (y == label)]
                  .sample(n=size, replace=False, random_state=self.seed)
                  .index
              )
  
              final_X = final_X.drop(sample_indexes)
              final_y = final_y.drop(sample_indexes)
              final_s = final_s.drop(sample_indexes)
  
          self.logger.debug(
              f"Final group {group} size: {final_s[(final_s == group)].shape[0]}"
          )
  
      self.logger.info("Data transformed.")
      return final_X.copy(), final_y.copy(), final_s.copy()
  
file_path: aequitas/src/aequitas/fairflow/methods/preprocessing/prevalence_sample.py
imports: from typing import Any, Optional
  import pandas
  from ...utils import create_logger
  from .preprocessing import PreProcessing
label_desc: Use image node_id 3 for calling the PrevalenceSampling obj's underlying member method code with example usage: obj.transform(X, y, s) and returns: final_X,  final_y,  final_s