code: def normality(
      data, dv=None, group=None, method="shapiro", alpha=0.05
  ):
      """Univariate normality test.
  
      Parameters
      ----------
      data : :py:class:`pandas.DataFrame`, series, list or 1D np.array
          Iterable. Can be either a single list, 1D numpy array,
          or a wide- or long-format pandas dataframe.
      dv : str
          Dependent variable (only when ``data`` is a long-format dataframe).
      group : str
          Grouping variable (only when ``data`` is a long-format dataframe).
      method : str
          Normality test. `'shapiro'` (default) performs the Shapiro-Wilk test
          using :py:func:`scipy.stats.shapiro`, `'normaltest'` performs the
          omnibus test of normality using :py:func:`scipy.stats.normaltest`, `'jarque_bera'` performs
          the Jarque-Bera test using :py:func:`scipy.stats.jarque_bera`.
          The Omnibus and Jarque-Bera tests are more suitable than the Shapiro test for
          large samples.
      alpha : float
          Significance level.
  
      Returns
      -------
      stats : :py:class:`pandas.DataFrame`
  
          * ``'W'``: Test statistic.
          * ``'pval'``: p-value.
          * ``'normal'``: True if ``data`` is normally distributed.
  
      See Also
      --------
      homoscedasticity : Test equality of variance.
      sphericity : Mauchly's test for sphericity.
  
      Notes
      -----
      The Shapiro-Wilk test calculates a :math:`W` statistic that tests whether a
      random sample :math:`x_1, x_2, ..., x_n` comes from a normal distribution.
  
      The :math:`W` statistic is calculated as follows:
  
      .. math::
  
          W = \\frac{(\\sum_{i=1}^n a_i x_{i})^2}
          {\\sum_{i=1}^n (x_i - \\overline{x})^2}
  
      where the :math:`x_i` are the ordered sample values (in ascending
      order) and the :math:`a_i` are constants generated from the means,
      variances and covariances of the order statistics of a sample of size
      :math:`n` from a standard normal distribution. Specifically:
  
      .. math:: (a_1, ..., a_n) = \\frac{m^TV^{-1}}{(m^TV^{-1}V^{-1}m)^{1/2}}
  
      with :math:`m = (m_1, ..., m_n)^T` and :math:`(m_1, ..., m_n)` are the
      expected values of the order statistics of independent and identically
      distributed random variables sampled from the standard normal distribution,
      and :math:`V` is the covariance matrix of those order statistics.
  
      The null-hypothesis of this test is that the population is normally
      distributed. Thus, if the p-value is less than the
      chosen alpha level (typically set at 0.05), then the null hypothesis is
      rejected and there is evidence that the data tested are not normally
      distributed.
  
      The result of the Shapiro-Wilk test should be interpreted with caution in
      the case of large sample sizes. Indeed, quoting from
      `Wikipedia <https://en.wikipedia.org/wiki/Shapiro%E2%80%93Wilk_test>`_:
  
          *"Like most statistical significance tests, if the sample size is
          sufficiently large this test may detect even trivial departures from
          the null hypothesis (i.e., although there may be some statistically
          significant effect, it may be too small to be of any practical
          significance); thus, additional investigation of the effect size is
          typically advisable, e.g., a Q–Q plot in this case."*
  
      Note that missing values are automatically removed (casewise deletion).
  
      References
      ----------
      * Shapiro, S. S., & Wilk, M. B. (1965). An analysis of variance test
        for normality (complete samples). Biometrika, 52(3/4), 591-611.
  
      * https://www.itl.nist.gov/div898/handbook/prc/section2/prc213.htm
  
      Examples
      --------
      1. Shapiro-Wilk test on a 1D array.
  
      >>> import numpy as np
      >>> import pingouin as pg
      >>> np.random.seed(123)
      >>> x = np.random.normal(size=100)
      >>> pg.normality(x)
               W      pval  normal
      0  0.98414  0.274886    True
  
      2. Omnibus test on a wide-format dataframe with missing values
  
      >>> data = pg.read_dataset('mediation')
      >>> data.loc[1, 'X'] = np.nan
      >>> pg.normality(data, method='normaltest').round(3)
                  W   pval  normal
      X       1.792  0.408    True
      M       0.492  0.782    True
      Y       0.349  0.840    True
      Mbin  839.716  0.000   False
      Ybin  814.468  0.000   False
      W1     24.816  0.000   False
      W2     43.400  0.000   False
  
      3. Pandas Series
  
      >>> pg.normality(data['X'], method='normaltest')
                W      pval  normal
      X  1.791839  0.408232    True
  
      4. Long-format dataframe
  
      >>> data = pg.read_dataset('rm_anova2')
      >>> pg.normality(data, dv='Performance', group='Time')
                   W      pval  normal
      Time
      Pre   0.967718  0.478773    True
      Post  0.940728  0.095157    True
  
      5. Same but using the Jarque-Bera test
  
      >>> pg.normality(data, dv='Performance', group='Time', method="jarque_bera")
                   W      pval  normal
      Time
      Pre   0.304021  0.858979    True
      Post  1.265656  0.531088    True
      """
      assert isinstance(
          data, (pd.DataFrame, pd.Series, list, np.ndarray)
      )
      assert method in ["shapiro", "normaltest", "jarque_bera"]
      if isinstance(data, pd.Series):
          data = data.to_frame()
      col_names = ["W", "pval"]
      func = getattr(scipy.stats, method)
      if isinstance(data, (list, np.ndarray)):
          data = np.asarray(data)
          assert data.ndim == 1, "Data must be 1D."
          assert data.size > 3, "Data must have more than 3 samples."
          data = remove_na(data)
          stats = pd.DataFrame(func(data)).T
          stats.columns = col_names
          stats["normal"] = np.where(stats["pval"] > alpha, True, False)
      else:
          # Data is a Pandas DataFrame
          if dv is None and group is None:
              # Wide-format
              # Get numeric data only
              numdata = data._get_numeric_data()
              stats = numdata.apply(
                  lambda x: func(x.dropna()),
                  result_type="expand",
                  axis=0,
              ).T
              stats.columns = col_names
              stats["normal"] = np.where(
                  stats["pval"] > alpha, True, False
              )
          else:
              # Long-format
              stats = pd.DataFrame([])
              assert group in data.columns
              assert dv in data.columns
              grp = data.groupby(group, observed=True, sort=False)
              cols = grp.groups.keys()
              for idx, tmp in grp:
                  if tmp[dv].count() <= 3:
                      warnings.warn(
                          f"Group {idx} has less than 4 valid samples. Returning NaN."
                      )
                      st_grp = pd.DataFrame(
                          {
                              "W": np.nan,
                              "pval": np.nan,
                              "normal": False,
                          },
                          index=[idx],
                      )
                  else:
                      st_grp = normality(
                          tmp[dv].to_numpy(), method=method, alpha=alpha
                      )
                  stats = pd.concat(
                      [stats, st_grp], axis=0, ignore_index=True
                  )
              stats.index = cols
              stats.index.name = group
      return _postprocess_dataframe(stats)
  
file_path: pingouin/pingouin/distribution.py
imports: import warnings
  import scipy.stats
  import numpy
  import pandas
  from collections import namedtuple
  from pingouin.utils import _flatten_list
  from pingouin.utils import remove_na, _postprocess_dataframe
label_desc: Use image node_id 2 for calling a global function with example usage: normality(data, dv, group, method, alpha) and returns: _postprocess_dataframe