code: def _calculate_woe(
      self, X: pd.DataFrame, y: pd.Series, variable: Union[str, int]
  ):
      total_pos = y.sum()
      inverse_y = y.ne(1).copy()
      total_neg = inverse_y.sum()
  
      pos = y.groupby(X[variable]).sum() / total_pos
      neg = inverse_y.groupby(X[variable]).sum() / total_neg
  
      if not (pos[:] == 0).sum() == 0 or not (neg[:] == 0).sum() == 0:
          raise ValueError(
              "The proportion of one of the classes for a category in "
              "variable {} is zero, and log of zero is not defined".format(
                  variable
              )
          )
  
      woe = np.log(pos / neg)
      return pos, neg, woe
  
imports: from typing import List, Union
  import numpy
  import pandas
  from feature_engine._docstrings.fit_attributes import _feature_names_in_docstring, _n_features_in_docstring, _variables_attribute_docstring
  from feature_engine._docstrings.init_parameters import _ignore_format_docstring, _unseen_docstring, _variables_categorical_docstring
  from feature_engine._docstrings.methods import _fit_transform_docstring, _inverse_transform_docstring, _transform_encoders_docstring
  from feature_engine._docstrings.substitute import Substitution
  from feature_engine.dataframe_checks import check_X_y
  from feature_engine.encoding._helper_functions import check_parameter_unseen
  from feature_engine.encoding.base_encoder import CategoricalInitMixin, CategoricalMethodsMixin
  from feature_engine.tags import _return_tags
label_desc: Use image node_id 2 for calling the WoE obj's underlying member method code with example usage: obj._calculate_woe(X, y, variable) and returns: pos,  neg,  woe