code: def cochran(data=None, dv=None, within=None, subject=None):
      """Cochran Q test. A special case of the Friedman test when the dependent
      variable is binary.
  
      Parameters
      ----------
      data : :py:class:`pandas.DataFrame`
          DataFrame. Both wide and long-format dataframe are supported for this test.
      dv : string
          Name of column containing the dependent variable (only required if ``data`` is in
          long format).
      within : string
          Name of column containing the within-subject factor (only required if ``data`` is in
          long format). Two or more within-factor are not currently supported.
      subject : string
          Name of column containing the subject/rater identifier (only required if ``data`` is in
          long format).
  
      Returns
      -------
      stats : :py:class:`pandas.DataFrame`
  
          * ``'Q'``: The Cochran Q statistic
          * ``'p-unc'``: Uncorrected p-value
          * ``'dof'``: degrees of freedom
  
      Notes
      -----
      The Cochran Q test [1]_ is a non-parametric test for ANOVA with repeated
      measures where the dependent variable is binary.
  
      The Q statistics is defined as:
  
      .. math:: Q = \\frac{(r-1)(r\\sum_j^rx_j^2-N^2)}{rN-\\sum_i^nx_i^2}
  
      where :math:`N` is the total sum of all observations, :math:`j=1,...,r`
      where :math:`r` is the number of repeated measures, :math:`i=1,...,n` where
      :math:`n` is the number of observations per condition.
  
      The p-value is then approximated using a chi-square distribution with
      :math:`r-1` degrees of freedom:
  
      .. math:: Q \\sim \\chi^2(r-1)
  
      Data are expected to be in long-format. Missing values are automatically removed using a
      strict listwise approach (= complete-case analysis). In other words, any subject with one or
      more missing value(s) is completely removed from the dataframe prior to running the
      test.
  
      References
      ----------
      .. [1] Cochran, W.G., 1950. The comparison of percentages in matched
         samples. Biometrika 37, 256–266.
         https://doi.org/10.1093/biomet/37.3-4.256
  
      Examples
      --------
      Compute the Cochran Q test for repeated measurements.
  
      >>> from pingouin import cochran, read_dataset
      >>> df = read_dataset('cochran')
      >>> cochran(data=df, dv='Energetic', within='Time', subject='Subject')
              Source  dof         Q     p-unc
      cochran   Time    2  6.705882  0.034981
  
      Same but using a wide-format dataframe
  
      >>> df_wide = df.pivot_table(index="Subject", columns="Time", values="Energetic")
      >>> cochran(df_wide)
               Source  dof         Q     p-unc
      cochran  Within    2  6.705882  0.034981
      """
      # Convert from wide to long-format, if needed
      if all([v is None for v in [dv, within, subject]]):
          assert isinstance(data, pd.DataFrame)
          data = (
              data._get_numeric_data().dropna()
          )  # Listwise deletion of missing values
          assert (
              data.shape[0] > 2
          ), "Data must have at least 3 non-missing rows."
          assert (
              data.shape[1] > 1
          ), "Data must contain at least two columns."
          data["Subj"] = np.arange(data.shape[0])
          data = data.melt(
              id_vars="Subj", var_name="Within", value_name="DV"
          )
          subject, within, dv = "Subj", "Within", "DV"
  
      # Check data
      data = _check_dataframe(
          dv=dv,
          within=within,
          data=data,
          subject=subject,
          effects="within",
      )
      assert (
          not data[within].isnull().any()
      ), "Cannot have missing values in `within`."
      assert (
          not data[subject].isnull().any()
      ), "Cannot have missing values in `subject`."
  
      # Pivot and melt the table. This has several effects:
      # 1) Force missing values to be explicit (a NaN cell is created)
      # 2) Automatic collapsing to the mean if multiple within factors are present
      # 3) If using dropna, remove rows with missing values (listwise deletion).
      # The latter is the same behavior as JASP (= strict complete-case analysis).
      data_piv = data.pivot_table(
          index=subject, columns=within, values=dv, observed=True
      )
      data_piv = data_piv.dropna()
      data = data_piv.melt(
          ignore_index=False, value_name=dv
      ).reset_index()
  
      # Groupby and extract size
      grp = data.groupby(within, observed=True)[dv]
      grp_s = data.groupby(subject, observed=True)[dv]
      k = data[within].nunique()
      dof = k - 1
      # n = grp.count().unique()[0]
  
      # Q statistic and p-value
      q = (
          dof * (k * np.sum(grp.sum() ** 2) - grp.sum().sum() ** 2)
      ) / (k * grp.sum().sum() - np.sum(grp_s.sum() ** 2))
      p_unc = scipy.stats.chi2.sf(q, dof)
  
      # Create output dataframe
      stats = pd.DataFrame(
          {"Source": within, "dof": dof, "Q": q, "p-unc": p_unc},
          index=["cochran"],
      )
      return _postprocess_dataframe(stats)
  
file_path: pingouin/pingouin/nonparametric.py
imports: import scipy
  import numpy
  import pandas
  from pingouin import remove_na, _check_dataframe, _postprocess_dataframe
label_desc: Use image node_id 7 for calling a global function with example usage: cochran(data, dv, within, subject) and returns: _postprocess_dataframe