code: def cramers_v(
      dist1: Union[np.ndarray, pd.Series],
      dist2: Union[np.ndarray, pd.Series],
      balance_classes: bool = False,
      min_category_size_ratio: float = 0,
      max_num_categories: int = None,
      sort_by: str = "dist1",
      from_freqs: bool = False,
  ) -> float:
      """Calculate the Cramer's V statistic.
  
      For more on Cramer's V, see https://en.wikipedia.org/wiki/Cram%C3%A9r%27s_V
      Uses the Cramer's V bias correction, see http://stats.lse.ac.uk/bergsma/pdf/cramerV3.pdf
  
      Function is for categorical data only.
  
      Parameters
      ----------
      dist1 : Union[np.ndarray, pd.Series]
          array of numerical values.
      dist2 : Union[np.ndarray, pd.Series]
          array of numerical values to compare dist1 to.
      balance_classes : bool, default False
          whether to balance the classes of the distributions. Use this in case of extremely unbalanced classes.
      min_category_size_ratio: float, default 0.01
          minimum size ratio for categories. Categories with size ratio lower than this number are binned
          into an "Other" category.
      max_num_categories: int, default: None
          max number of allowed categories. If there are more categories than this number, categories are ordered by
          magnitude and all the smaller categories are binned into an "Other" category.
          If max_num_categories=None, there is no limit.
          > Note that if this parameter is used, the ordering of categories (and by extension, the decision which
          categories are kept by name and which are binned to the "Other" category) is done by default according to the
          values of dist1, which is treated as the "expected" distribution. This behavior can be changed by using the
          sort_by parameter.
      sort_by: str, default: 'dist1'
          Specify how categories should be sorted, affecting which categories will get into the "Other" category.
          Possible values:
          - 'dist1': Sort by the largest dist1 categories.
          - 'dist2': Sort by the largest dist2 categories.
          - 'difference': Sort by the largest difference between categories.
          > Note that this parameter has no effect if max_num_categories = None or there are not enough unique categories.
      from_freqs: bool, default: False
          Whether the data is already in the form of frequencies.
      Returns
      -------
      float
          the bias-corrected Cramer's V value of the 2 distributions.
  
      """
      # If balance_classes is True, min_category_size_ratio should not affect results:
      min_category_size_ratio = (
          min_category_size_ratio if balance_classes is False else 0
      )
  
      if from_freqs:
          dist1_counts, dist2_counts = dist1, dist2
      else:
          (
              dist1_counts,
              dist2_counts,
              cat_list,
          ) = preprocess_2_cat_cols_to_same_bins(
              dist1,
              dist2,
              min_category_size_ratio,
              max_num_categories,
              sort_by,
          )
          if (
              len(cat_list) == 1
          ):  # If the distributions have the same single value
              return 0
  
          if balance_classes is True:
              dist1_counts, dist2_counts = rebalance_distributions(
                  dist1_counts, dist2_counts
              )
          else:
              dist1_counts, dist2_counts = _balance_sizes_downsizing(
                  dist1_counts, dist2_counts
              )
      contingency_matrix = pd.DataFrame(
          [dist1_counts, dist2_counts], dtype=int
      )
  
      # filter all columns that have all 0 values
      contingency_matrix = contingency_matrix.loc[
          :, (contingency_matrix != 0).any(axis=0)
      ]
  
      # Based on https://en.wikipedia.org/wiki/Cram%C3%A9r%27s_V# bias correction method # noqa: SC100
      chi2 = chi2_contingency(contingency_matrix)[0]
      n = contingency_matrix.sum().sum()
      phi2 = chi2 / n
      r, k = contingency_matrix.shape
  
      phi2corr = max(0, phi2 - ((k - 1) * (r - 1)) / (n - 1))
      rcorr = r - ((r - 1) ** 2) / (n - 1)
      kcorr = k - ((k - 1) ** 2) / (n - 1)
      return np.sqrt(phi2corr / min((kcorr - 1), (rcorr - 1)))
  
imports: from numbers import Number
  from typing import Dict, Optional, Tuple, Union
  import numpy
  import pandas
  from plotly.graph_objs import Figure
  from plotly.subplots import make_subplots
  from scipy.stats import chi2_contingency, wasserstein_distance
  from deepchecks.core import ConditionCategory, ConditionResult
  from deepchecks.core.errors import DeepchecksValueError, NotEnoughSamplesError
  from deepchecks.utils.dict_funcs import get_dict_entry_by_value
  from deepchecks.utils.distribution.plot import CategoriesSortingKind, drift_score_bar_traces, feature_distribution_traces
  from deepchecks.utils.distribution.preprocessing import preprocess_2_cat_cols_to_same_bins
  from deepchecks.utils.plot import DEFAULT_DATASET_NAMES
  from deepchecks.utils.strings import format_number
label_desc: Use image node_id 4 for calling a global function with example usage: cramers_v(dist1, dist2, balance_classes, min_category_size_ratio, max_num_categories, sort_by, from_freqs) and returns: np, int