docs: def predict(self,
                  data,
                  param_list=None,
                  return_long_probs=True,
                  choice_col=None,
                  num_draws=None,
                  seed=None):
          """
          Parameters
          ----------
          data : string or pandas dataframe.
              If string, data should be an absolute or relative path to a CSV
              file containing the long format data for this choice model. Note
              long format is has one row per available alternative for each
              observation. If pandas dataframe, the dataframe should be the long
              format data for the choice model. The data should include all of
              the same columns as the original data used to construct the choice
              model, with the sole exception of the "intercept" column. If needed
              the "intercept" column will be dynamically created.
          param_list : list, optional.
              Contains four elements, each being a numpy array or None. Either
              all of the arrays should be 1D or all of the arrays should be 2D.
              If 2D, the arrays should have the same number of columns. Each
              column should be a particular set of parameter values that one
              wants to predict with. The first element in the list should
              contain the index coefficients. The second element should contain
              the 'outside' intercept parameters if there are any, or None
              otherwise. The third element should contain the shape parameters
              if there are any or None otherwise. The fourth element should
              contain the nest coefficients if there are any or None otherwise.
              Default == None.
          return_long_probs : bool, optional.
              Indicates whether or not the long format probabilites (a 1D numpy
              array with one element per observation per available alternative)
              should be returned. Default == True.
          choice_col : str, optional.
              Denotes the column in `data` which contains a one if the
              alternative pertaining to the given row was the observed outcome
              for the observation pertaining to the given row and a zero
              otherwise. Default == None.
          num_draws : int, or None, optional.
              Should be greater than zero. Denotes the number of draws that we
              are making from each normal distribution. This kwarg is only used
              if self.model_type == "Mixed Logit Model". Default == None.
          seed : int, or None, optional.
              If an int is passed, it should be greater than zero. Denotes the
              value to be used in seeding the random generator used to generate
              the draws from the normal distribution. This kwarg is only used if
              self.model_type == "Mixed Logit Model". Default == None.
  
          Returns
          -------
          numpy array or tuple of two numpy arrays.
              If `choice_col` is passed AND `return_long_probs is True`, then the
              tuple `(chosen_probs, long_probs)` is returned. If
              `return_long_probs is True` and `chosen_row_to_obs is None`, then
              `long_probs` is returned. If `chosen_row_to_obs` is passed and
              `return_long_probs is False` then `chosen_probs` is returned.
  
              `chosen_probs` is a 1D numpy array of shape (num_observations,).
              Each element is the probability of the corresponding observation
              being associated with its realized outcome.
  
              `long_probs` is a 1D numpy array with one element per observation
              per available alternative for that observation. Each element is the
              probability of the corresponding observation being associated with
              that rows corresponding alternative.
  
              It is NOT valid to have `chosen_row_to_obs == None` and
              `return_long_probs == False`.
          """
          # Get the dataframe of observations we'll be predicting on
          dataframe = get_dataframe_from_data(data)
  
          # Determine the conditions under which we will add an intercept column
          # to our long format dataframe.
          add_intercept_to_dataframe(self.specification, dataframe)
  
          # Make sure the necessary columns are in the long format dataframe
          for column in [self.alt_id_col,
                         self.obs_id_col,
                         self.mixing_id_col]:
              if column is not None:
                  ensure_columns_are_in_dataframe([column], dataframe)
  
          # If param_list is passed, check the validity of its elements
          self.check_param_list_validity(param_list)
  
          # Check validity of the return_long_probs and choice_col kwargs
          check_for_choice_col_based_on_return_long_probs(return_long_probs,
                                                          choice_col)
  
          # Get the new column of alternative IDs and get the new design matrix
          new_alt_IDs = dataframe[self.alt_id_col].values
  
          new_design_res = create_design_matrix(dataframe,
                                                self.specification,
                                                self.alt_id_col,
                                                names=self.name_spec)
  
          new_design = new_design_res[0]
  
          # Get the new mappings between the alternatives and observations
          mapping_res = create_long_form_mappings(dataframe,
                                                  self.obs_id_col,
                                                  self.alt_id_col,
                                                  choice_col=choice_col,
                                                  nest_spec=self.nest_spec,
                                                  mix_id_col=self.mixing_id_col)
  
          new_rows_to_obs = mapping_res["rows_to_obs"]
          new_rows_to_alts = mapping_res["rows_to_alts"]
          new_chosen_to_obs = mapping_res["chosen_row_to_obs"]
          new_rows_to_nests = mapping_res["rows_to_nests"]
          new_rows_to_mixers = mapping_res["rows_to_mixers"]
  
          # Get the parameter arrays to be used in calculating the probabilities
          if param_list is None:
              new_index_coefs = self.coefs.values
              new_intercepts = (self.intercepts.values if self.intercepts
                                is not None else None)
              new_shape_params = (self.shapes.values if self.shapes
                                  is not None else None)
              new_nest_coefs = (self.nests.values if self.nests
                                is not None else None)
          else:
              new_index_coefs = param_list[0]
              new_intercepts = param_list[1]
              new_shape_params = param_list[2]
              new_nest_coefs = param_list[3]
  
          # Get the probability of each observation choosing each available
          # alternative
          if self.model_type == "Nested Logit Model":
              # Get the 'natural' nest coefficients for prediction
              new_natural_nests = naturalize_nest_coefs(new_nest_coefs)
              # Determine the return string for the nested logit model
              if return_long_probs:
                  return_string = "long_probs"
              else:
                  return_string = "chosen_probs"
              # This condition accounts for the fact that we have a different
              # functional interface for nested vs non-nested models
              return calc_nested_probs(new_natural_nests,
                                       new_index_coefs,
                                       new_design,
                                       new_rows_to_obs,
                                       new_rows_to_nests,
                                       chosen_row_to_obs=new_chosen_to_obs,
                                       return_type=return_string)
  
          elif self.model_type == "Mixed Logit Model":
              ##########
              # This condition accounts for the fact that Mixed Logit models have
              # a different functional interface than the standard logit-type
              # models.
              ##########
              # Get the draws for each random coefficient
              num_mixing_units = new_rows_to_mixers.shape[1]
              draw_list = mlc.get_normal_draws(num_mixing_units,
                                               num_draws,
                                               len(self.mixing_pos),
                                               seed=seed)
              # Calculate the 3D design matrix for the prediction.
              design_args = (new_design,
                             draw_list,
                             self.mixing_pos,
                             new_rows_to_mixers)
              new_design_3d = mlc.create_expanded_design_for_mixing(*design_args)
              # Calculate the desired probabilities for the mixed logit model.
              prob_args = (new_index_coefs,
                           new_design_3d,
                           new_alt_IDs,
                           new_rows_to_obs,
                           new_rows_to_alts,
                           self.utility_transform)
              prob_kwargs = {"intercept_params": new_intercepts,
                             "shape_params": new_shape_params,
                             "chosen_row_to_obs": new_chosen_to_obs,
                             "return_long_probs": return_long_probs}
              prob_array = calc_probabilities(*prob_args, **prob_kwargs)
              return prob_array.mean(axis=1)
  
          else:
              return calc_probabilities(new_index_coefs,
                                        new_design,
                                        new_alt_IDs,
                                        new_rows_to_obs,
                                        new_rows_to_alts,
                                        self.utility_transform,
                                        intercept_params=new_intercepts,
                                        shape_params=new_shape_params,
                                        chosen_row_to_obs=new_chosen_to_obs,
                                        return_long_probs=return_long_probs)