code: def welch_anova(data=None, dv=None, between=None):
      """One-way Welch ANOVA.
  
      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.
  
      Returns
      -------
      aov : :py:class:`pandas.DataFrame`
          ANOVA summary:
  
          * ``'Source'``: Factor names
          * ``'ddof1'``: Numerator degrees of freedom
          * ``'ddof2'``: Denominator degrees of freedom
          * ``'F'``: F-values
          * ``'p-unc'``: uncorrected p-values
          * ``'np2'``: Partial eta-squared
  
      See Also
      --------
      anova : One-way and N-way ANOVA
      rm_anova : One-way and two-way repeated measures ANOVA
      mixed_anova : Two way mixed ANOVA
      kruskal : Non-parametric one-way ANOVA
  
      Notes
      -----
      From Wikipedia:
  
      *It is named for its creator, Bernard Lewis Welch, and is an adaptation of
      Student's t-test, and is more reliable when the two samples have
      unequal variances and/or unequal sample sizes.*
  
      The classic ANOVA is very powerful when the groups are normally distributed
      and have equal variances. However, when the groups have unequal variances,
      it is best to use the Welch ANOVA that better controls for
      type I error (Liu 2015). The homogeneity of variances can be measured with
      the `homoscedasticity` function. The two other assumptions of
      normality and independance remain.
  
      The main idea of Welch ANOVA is to use a weight :math:`w_i` to reduce
      the effect of unequal variances. This weight is calculated using the sample
      size :math:`n_i` and variance :math:`s_i^2` of each group
      :math:`i=1,...,r`:
  
      .. math:: w_i = \\frac{n_i}{s_i^2}
  
      Using these weights, the adjusted grand mean of the data is:
  
      .. math::
  
          \\overline{Y}_{\\text{welch}} = \\frac{\\sum_{i=1}^r
          w_i\\overline{Y}_i}{\\sum w}
  
      where :math:`\\overline{Y}_i` is the mean of the :math:`i` group.
  
      The effect sums of squares is defined as:
  
      .. math::
  
          SS_{\\text{effect}} = \\sum_{i=1}^r w_i
          (\\overline{Y}_i - \\overline{Y}_{\\text{welch}})^2
  
      We then need to calculate a term lambda:
  
      .. math::
  
          \\Lambda = \\frac{3\\sum_{i=1}^r(\\frac{1}{n_i-1})
          (1 - \\frac{w_i}{\\sum w})^2}{r^2 - 1}
  
      from which the F-value can be calculated:
  
      .. math::
  
          F_{\\text{welch}} = \\frac{SS_{\\text{effect}} / (r-1)}
          {1 + \\frac{2\\Lambda(r-2)}{3}}
  
      and the p-value approximated using a F-distribution with
      :math:`(r-1, 1 / \\Lambda)` degrees of freedom.
  
      When the groups are balanced and have equal variances, the optimal post-hoc
      test is the Tukey-HSD test (:py:func:`pingouin.pairwise_tukey`).
      If the groups have unequal variances, the Games-Howell test is more
      adequate (:py:func:`pingouin.pairwise_gameshowell`).
  
      Results have been tested against R.
  
      References
      ----------
      .. [1] Liu, Hangcheng. "Comparing Welch's ANOVA, a Kruskal-Wallis test and
             traditional ANOVA in case of Heterogeneity of Variance." (2015).
  
      .. [2] Welch, Bernard Lewis. "On the comparison of several mean values:
             an alternative approach." Biometrika 38.3/4 (1951): 330-336.
  
      Examples
      --------
      1. One-way Welch ANOVA on the pain threshold dataset.
  
      >>> from pingouin import welch_anova, read_dataset
      >>> df = read_dataset('anova')
      >>> aov = welch_anova(dv='Pain threshold', between='Hair color', data=df)
      >>> aov
             Source  ddof1     ddof2         F     p-unc       np2
      0  Hair color      3  8.329841  5.890115  0.018813  0.575962
      """
      # Check data
      data = _check_dataframe(
          dv=dv, between=between, data=data, effects="between"
      )
  
      # Reset index (avoid duplicate axis error)
      data = data.reset_index(drop=True)
  
      # Number of groups
      r = data[between].nunique()
      ddof1 = r - 1
  
      # Compute weights and ajusted means
      grp = data.groupby(between, observed=True, group_keys=False)[dv]
      weights = grp.count() / grp.var(numeric_only=True)
      adj_grandmean = (
          weights * grp.mean(numeric_only=True)
      ).sum() / weights.sum()
  
      # Sums of squares (regular and adjusted)
      ss_res = grp.apply(lambda x: (x - x.mean()) ** 2).sum()
      ss_bet = (
          (
              grp.mean(numeric_only=True)
              - data[dv].mean(numeric_only=True)
          )
          ** 2
          * grp.count()
      ).sum()
      ss_betadj = np.sum(
          weights
          * np.square(grp.mean(numeric_only=True) - adj_grandmean)
      )
      ms_betadj = ss_betadj / ddof1
  
      # Calculate lambda, F-value, p-value and np2
      lamb = (
          3
          * np.sum(
              (1 / (grp.count() - 1))
              * (1 - (weights / weights.sum())) ** 2
          )
      ) / (r**2 - 1)
      ddof2 = 1 / lamb
      fval = ms_betadj / (1 + (2 * lamb * (r - 2)) / 3)
      pval = f.sf(fval, ddof1, ddof2)
      np2 = ss_bet / (ss_bet + ss_res)
  
      # Create output dataframe
      aov = pd.DataFrame(
          {
              "Source": between,
              "ddof1": ddof1,
              "ddof2": ddof2,
              "F": fval,
              "p-unc": pval,
              "np2": np2,
          },
          index=[0],
      )
      return _postprocess_dataframe(aov)
  
file_path: pingouin/pingouin/parametric.py
imports: import warnings
  from collections.abc import Iterable
  import numpy
  import pandas
  from scipy.stats import f
  import pandas_flavor
  from pingouin import _check_dataframe, remove_na, _flatten_list, bayesfactor_ttest, epsilon, sphericity, _postprocess_dataframe
label_desc: Use image node_id 7 for calling a global function with example usage: welch_anova(data, dv, between) and returns: _postprocess_dataframe