code: def pairwise_tukey(
      data=None, dv=None, between=None, effsize="hedges"
  ):
      """Pairwise Tukey-HSD post-hoc test.
  
      Parameters
      ----------
      data : :py:class:`pandas.DataFrame`
          DataFrame. Note that this function can also directly be used as a Pandas method, in which
          case this argument is no longer needed.
      dv : string
          Name of column containing the dependent variable.
      between: string
          Name of column containing the between factor.
      effsize : string or None
          Effect size type. Available methods are:
  
          * ``'none'``: no effect size
          * ``'cohen'``: Unbiased Cohen d
          * ``'hedges'``: Hedges g
          * ``'r'``: Pearson correlation coefficient
          * ``'eta-square'``: Eta-square
          * ``'odds-ratio'``: Odds ratio
          * ``'AUC'``: Area Under the Curve
          * ``'CLES'``: Common Language Effect Size
  
      Returns
      -------
      stats : :py:class:`pandas.DataFrame`
  
          * ``'A'``: Name of first measurement
          * ``'B'``: Name of second measurement
          * ``'mean(A)'``: Mean of first measurement
          * ``'mean(B)'``: Mean of second measurement
          * ``'diff'``: Mean difference (= mean(A) - mean(B))
          * ``'se'``: Standard error
          * ``'T'``: T-values
          * ``'p-tukey'``: Tukey-HSD corrected p-values
          * ``'hedges'``: Hedges effect size (or any effect size defined in
            ``effsize``)
  
      See also
      --------
      pairwise_tests, pairwise_gameshowell
  
      Notes
      -----
      Tukey HSD post-hoc [1]_ is best for balanced one-way ANOVA.
  
      It has been proven to be conservative for one-way ANOVA with unequal sample sizes. However, it
      is not robust if the groups have unequal variances, in which case the Games-Howell test is
      more adequate. Tukey HSD is not valid for repeated measures ANOVA. Only one-way ANOVA design
      are supported.
  
      The T-values are defined as:
  
      .. math::
  
          t = \\frac{\\overline{x}_i - \\overline{x}_j}
          {\\sqrt{2 \\cdot \\text{MS}_w / n}}
  
      where :math:`\\overline{x}_i` and :math:`\\overline{x}_j` are the means of the first and
      second group, respectively, :math:`\\text{MS}_w` the mean squares of the error (computed using
      ANOVA) and :math:`n` the sample size.
  
      If the sample sizes are unequal, the Tukey-Kramer procedure is automatically used:
  
      .. math::
  
          t = \\frac{\\overline{x}_i - \\overline{x}_j}{\\sqrt{\\frac{MS_w}{n_i}
          + \\frac{\\text{MS}_w}{n_j}}}
  
      where :math:`n_i` and :math:`n_j` are the sample sizes of the first and second group,
      respectively.
  
      The p-values are then approximated using the Studentized range distribution
      :math:`Q(\\sqrt2|t_i|, r, N - r)` where :math:`r` is the total number of groups and
      :math:`N` is the total sample size.
  
      References
      ----------
      .. [1] Tukey, John W. "Comparing individual means in the analysis of
             variance." Biometrics (1949): 99-114.
  
      .. [2] Gleason, John R. "An accurate, non-iterative approximation for
             studentized range quantiles." Computational statistics & data
             analysis 31.2 (1999): 147-158.
  
      Examples
      --------
      Pairwise Tukey post-hocs on the Penguins dataset.
  
      >>> import pingouin as pg
      >>> df = pg.read_dataset('penguins')
      >>> df.pairwise_tukey(dv='body_mass_g', between='species').round(3)
                 A          B   mean(A)   mean(B)      diff      se       T  p-tukey  hedges
      0     Adelie  Chinstrap  3700.662  3733.088   -32.426  67.512  -0.480    0.881  -0.074
      1     Adelie     Gentoo  3700.662  5076.016 -1375.354  56.148 -24.495    0.000  -2.860
      2  Chinstrap     Gentoo  3733.088  5076.016 -1342.928  69.857 -19.224    0.000  -2.875
      """
      # First compute the ANOVA
      # For max precision, make sure rounding is disabled
      old_options = options.copy()
      options["round"] = None
      aov = anova(dv=dv, data=data, between=between, detailed=True)
      options.update(old_options)  # Restore original options
      df = aov.at[1, "DF"]
      ng = aov.at[0, "DF"] + 1
      grp = data.groupby(between, observed=True)[
          dv
      ]  # default is sort=True
      # Careful: pd.unique does NOT sort whereas numpy does
      # The line below should be equal to labels = np.unique(data[between])
      # However, this does not work if between is a Categorical column, because
      # Pandas applies a custom, not alphabetical, sorting.
      # See https://github.com/raphaelvallat/pingouin/issues/111
      labels = np.array(list(grp.groups.keys()))
      n = grp.count().to_numpy()
      gmeans = grp.mean(numeric_only=True).to_numpy()
      gvar = aov.at[1, "MS"] / n
  
      # Pairwise combinations
      g1, g2 = np.array(list(combinations(np.arange(ng), 2))).T
      mn = gmeans[g1] - gmeans[g2]
      se = np.sqrt(gvar[g1] + gvar[g2])
      tval = mn / se
  
      # Critical values and p-values
      # crit = studentized_range.ppf(1 - alpha, ng, df) / np.sqrt(2)
      pval = studentized_range.sf(np.sqrt(2) * np.abs(tval), ng, df)
      pval = np.clip(pval, 0, 1)
  
      # Uncorrected p-values
      # from scipy.stats import t
      # punc = t.sf(np.abs(tval), n[g1].size + n[g2].size - 2) * 2
  
      # Effect size
      # Method 1: Approximation
      # d = tval * np.sqrt(1 / n[g1] + 1 / n[g2])
      # ef = convert_effsize(d, "cohen", effsize, n[g1], n[g2])
      # Method 2: Exact
      ef = []
      for idx_a, idx_b in zip(g1, g2):
          ef.append(
              compute_effsize(
                  grp.get_group(labels[idx_a]),
                  grp.get_group(labels[idx_b]),
                  paired=False,
                  eftype=effsize,
              )
          )
  
      # Create dataframe
      stats = pd.DataFrame(
          {
              "A": labels[g1],
              "B": labels[g2],
              "mean(A)": gmeans[g1],
              "mean(B)": gmeans[g2],
              "diff": mn,
              "se": se,
              "T": tval,
              "p-tukey": pval,
              effsize: ef,
          }
      )
      return _postprocess_dataframe(stats)
  
file_path: pingouin/pingouin/pairwise.py
imports: import numpy
  import pandas
  import pandas_flavor
  from itertools import combinations, product
  from pingouin.config import options
  from pingouin.parametric import anova
  from pingouin.multicomp import multicomp
  from pingouin.effsize import compute_effsize
  from pingouin.utils import _check_dataframe, _flatten_list, _postprocess_dataframe
  from scipy.stats import studentized_range
  import warnings
label_desc: Use image node_id 4 for calling a global function with example usage: pairwise_tukey(data, dv, between, effsize) and returns: _postprocess_dataframe