code: def relative_chi_squared(
      row,
      hist_name: str = "histogram",
      suffix_mean: str = "_mean",
      suffix_cov: str = "_cov",
      suffix_binning: str = "_binning",
  ):
      """Calculate chi squared of normalized histogram with pre-calculated mean normalized histogram
  
      :param pd.Series row: row to apply chi_squared function to.
      :param str hist_name: name of column to extract histograms from. default is 'histogram' (optional)
      :param str suffix_mean: suffix of mean. mean column = hist_name + suffix_mean (optional)
      :param str suffix_std: suffix of std. std column = hist_name + suffix_std (optional)
      :param str suffix_binning: suffix of binning. binning column = hist_name + suffix_binning (optional)
      """
      x = {
          "chi2": np.nan,
          "naive_pvalue": np.nan,
          "naive_zscore": np.nan,
          "max_res": np.nan,
      }
  
      required = [
          hist_name,
          hist_name + suffix_mean,
          hist_name + suffix_cov,
          hist_name + suffix_binning,
      ]
      if not all(r in row for r in required):
          return pd.Series(x)
  
      hist = row[hist_name]
      norm_mean = row[hist_name + suffix_mean]
      cov = row[hist_name + suffix_cov]
      binning = row[hist_name + suffix_binning]
  
      # basic checks
      if not isinstance(hist, COMMON_HIST_TYPES):
          return pd.Series(x)
      if any(ho is None for ho in [norm_mean, cov, binning]):
          return pd.Series(x)
      if len(cov.shape) != 2 or len(norm_mean.shape) != 1:
          return pd.Series(x)
  
      variance = np.diagonal(cov)
  
      # get entries as numpy arrays
      if hist.n_dim == 1:
          entries = (
              hist.bin_entries(xvalues=binning)
              if is_numeric(hist)
              else hist.bin_entries(labels=binning)
          )
      else:
          assert len(binning) == 2
          entries = set_2dgrid(hist, [binning[0], binning[1]])
          entries = entries.flatten()
  
      # calculation of mean normalized histogram and its covariance matrix of input histogram
      single_norm, _ = probability_distribution_mean_covariance(
          [entries]
      )
  
      if (
          np.linalg.cond(cov) < 0.1 / np.finfo(cov.dtype).eps
          and np.abs(np.linalg.det(cov)) > np.finfo(cov.dtype).eps
      ):
          # check if covariance matrix is invertible
          # see: https://stackoverflow.com/questions/13249108/efficient-pythonic-check-for-singular-matrix
          # We try to use the precision matrix (inverse covariance matrix) for the chi-squared calculation
          pm = linalg.inv(cov)
          chi_squared = np.dot(
              (norm_mean - single_norm),
              np.dot(pm, (norm_mean - single_norm)),
          )
          if chi_squared <= 0:
              chi_squared = np.finfo(float).eps
      else:
          # If a covariance matrix is singular we fall back on using variances
          chi_squared = np.sum(
              (norm_mean - single_norm) ** 2
              / (variance + np.finfo(float).eps)
          )
  
      # pvalue and zvalue based on naive number of degrees of freedom
      ndof = len(entries) - 1
      p_value = stats.chi2.sf(chi_squared, ndof)
      z_score = -stats.norm.ppf(p_value)
      # scenario where pvalue is too small to evaluate Z
      # use Chernoff approximation for p-value upper bound
      # see: https://en.wikipedia.org/wiki/Chi-squared_distribution
      if p_value == 0:
          z = chi_squared / ndof
          u = -np.log(2 * np.pi) - ndof * np.log(z) + ndof * (z - 1)
          z_score = np.sqrt(u - np.log(u))
  
      max_resid = np.max(
          np.abs(
              (norm_mean - single_norm)
              / np.sqrt(variance + np.finfo(float).eps)
          )
      )
  
      x["chi2"] = chi_squared
      x["naive_pvalue"] = p_value
      x["naive_zscore"] = z_score
      x["max_res"] = max_resid
      return pd.Series(x)
  
imports: import numpy
  import pandas
  from numpy.lib.stride_tricks import as_strided
  from scipy import linalg, stats
  from scipy.stats import linregress, norm
  from popmon.analysis.hist_numpy import check_similar_hists, get_consistent_numpy_2dgrids, get_consistent_numpy_entries, set_2dgrid
  from popmon.hist.hist_utils import COMMON_HIST_TYPES, is_numeric
  from popmon.stats.numpy import probability_distribution_mean_covariance
label_desc: Use image node_id 18 for calling a global function with example usage: relative_chi_squared(row, hist_name, suffix_mean, suffix_cov, suffix_binning) and returns: pd, pd, pd, pd, pd