docs: def undersampling(X, y, cost_mat=None, per=0.5):
      """Under-sampling.
  
      Parameters
      ----------
          X : array-like of shape = [n_samples, n_features]
              The input samples.
  
          y : array-like of shape = [n_samples]
              Ground truth (correct) labels.
  
          cost_mat : array-like of shape = [n_samples, 4], optional (default=None)
              Cost matrix of the classification problem
              Where the columns represents the costs of: false positives, false negatives,
              true positives and true negatives, for each example.
  
          per: float, optional (default = 0.5)
              Percentage of the minority class in the under-sampled data
      """
  
      n_samples = X.shape[0]
      #TODO: allow y different from (0, 1)
      num_y1 = y.sum()
      num_y0 = n_samples - num_y1
  
      filter_rand = np.random.rand(int(num_y1 + num_y0))
  
      #TODO: rewrite in a more readable way
      if num_y1 < num_y0:
          num_y0_new = num_y1 * 1.0 / per - num_y1
          num_y0_new_per = num_y0_new * 1.0 / num_y0
          filter_0 = np.logical_and(y == 0, filter_rand <= num_y0_new_per)
          filter_ = np.nonzero(np.logical_or(y == 1, filter_0))[0]
      else:
          num_y1_new = num_y0 * 1.0 / per - num_y0
          num_y1_new_per = num_y1_new * 1.0 / num_y1
          filter_1 = np.logical_and(y == 1, filter_rand <= num_y1_new_per)
          filter_ = np.nonzero(np.logical_or(y == 0, filter_1))[0]
  
      X_u = X[filter_, :]
      y_u = y[filter_]
  
      if not cost_mat is None:
          cost_mat_u = cost_mat[filter_, :]
          return X_u, y_u, cost_mat_u
      else:
          return X_u, y_u