code: def multivariate_logrank_test(
      event_durations,
      groups,
      event_observed=None,
      weights=None,
      t_0=-1,
      weightings=None,
      **kwargs,
  ) -> StatisticalResult:  # pylint: disable=too-many-locals
      r"""
      This test is a generalization of the logrank_test: it can deal with n>2 populations (and should
      be equal when n=2):
  
      .. math::
          \begin{align}
           & H_0: h_1(t) = h_2(t) = h_3(t) = ... = h_n(t) \\
           & H_A: \text{there exist at least one group that differs from the other.}
          \end{align}
  
  
      Parameters
      ----------
  
      event_durations: iterable
          a (n,) list-like representing the (possibly partial) durations of all individuals
  
      groups: iterable
          a (n,) list-like of unique group labels for each individual.
  
      event_observed: iterable, optional
          a (n,) list-like of event_observed events: 1 if observed death, 0 if censored. Defaults to all observed.
  
      weights: iterable, optional
          case-weights
  
      t_0: float, optional (default=-1)
          The final time period under observation, and subjects who experience the event after this time are set to be censored.
          Specify -1 to use all time.
  
      weightings: str, optional
          apply a weighted logrank test: options are "wilcoxon" for Wilcoxon (also known as Breslow), "tarone-ware"
          for Tarone-Ware, "peto" for Peto test and "fleming-harrington" for Fleming-Harrington test.
          These are useful for testing for early or late differences in the survival curve. For the Fleming-Harrington
          test, keyword arguments p and q must also be provided with non-negative values.
  
          Weightings are applied at the ith ordered failure time, :math:`t_{i}`, according to:
              Wilcoxon: :math:`n_i`
              Tarone-Ware: :math:`\sqrt{n_i}`
              Peto: :math:`\bar{S}(t_i)`
              Fleming-Harrington: :math:`\hat{S}(t_i)^p \times (1 - \hat{S}(t_i))^q`
  
              where :math:`n_i` is the number at risk just prior to time :math:`t_{i}`, :math:`\bar{S}(t_i)` is
              Peto-Peto's modified survival estimate and :math:`\hat{S}(t_i)` is the left-continuous
              Kaplan-Meier survival estimate at time :math:`t_{i}`.
  
      kwargs:
          add keywords and meta-data to the experiment summary.
  
  
      Returns
      -------
  
      StatisticalResult
         a StatisticalResult object with properties ``p_value``, ``summary``, ``test_statistic``, ``print_summary``
  
      Examples
      --------
  
      .. code:: python
  
          df = pd.DataFrame({
             'durations': [5, 3, 9, 8, 7, 4, 4, 3, 2, 5, 6, 7],
             'events': [1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0],
             'groups': [0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2]
          })
          result = multivariate_logrank_test(df['durations'], df['groups'], df['events'])
          result.test_statistic
          result.p_value
          result.print_summary()
  
  
          # numpy example
          G = [0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2]
          T = [5, 3, 9, 8, 7, 4, 4, 3, 2, 5, 6, 7]
          E = [1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0]
          result = multivariate_logrank_test(T, G, E)
          result.test_statistic
  
  
      See Also
      --------
      pairwise_logrank_test
      logrank_test
      """
      kwargs.setdefault("test_name", "multivariate_logrank_test")
  
      event_durations, groups = np.asarray(event_durations), np.asarray(
          groups
      )
  
      if event_observed is None:
          event_observed = np.ones((event_durations.shape[0], 1))
      else:
          event_observed = np.asarray(event_observed)
  
      n = np.max(event_durations.shape)
      assert (
          n
          == np.max(event_durations.shape)
          == np.max(event_observed.shape)
      ), "inputs must be of the same length."
      groups, event_durations, event_observed = map(
          lambda x: pd.Series(np.asarray(x).reshape(n)),
          [groups, event_durations, event_observed],
      )
  
      # censor all subjects that are beyond the specified t_0, see #1300
      if int(t_0) != -1:
          event_observed[event_durations > t_0] = 0
  
      unique_groups, rm, obs, _ = group_survival_table_from_events(
          groups, event_durations, event_observed, weights=weights
      )
      n_groups = unique_groups.shape[0]
  
      # compute the factors needed
      n_ij = rm.sum(0).values - rm.cumsum(0).shift(1).fillna(0)
      d_i = obs.sum(1)
      n_i = rm.values.sum() - rm.sum(1).cumsum().shift(1).fillna(0)
      ev_i = n_ij.mul(d_i / n_i, axis="index")
  
      # compute weightings for log-rank alternatives
      if weightings is None:
          w_i = np.ones(d_i.shape[0])
      elif weightings == "wilcoxon":
          kwargs["test_name"] = kwargs["test_name"].replace(
              "logrank", "Wilcoxon"
          )
          w_i = n_i
      elif weightings == "tarone-ware":
          kwargs["test_name"] = kwargs["test_name"].replace(
              "logrank", "Tarone-Ware"
          )
          w_i = np.sqrt(n_i)
      elif weightings == "peto":
          kwargs["test_name"] = kwargs["test_name"].replace(
              "logrank", "Peto"
          )
          w_i = np.cumprod(
              1.0 - (ev_i.sum(1)) / (n_i + 1)
          )  # Peto-Peto's modified survival estimates.
      elif weightings == "fleming-harrington":
          if "p" in kwargs:
              p = kwargs["p"]
              if p < 0:
                  raise ValueError("p must be non-negative.")
          else:
              raise ValueError(
                  "Must provide keyword argument p for Flemington-Harrington test statistic"
              )
          if "q" in kwargs:
              q = kwargs["q"]
              if q < 0:
                  raise ValueError("q must be non-negative.")
          else:
              raise ValueError(
                  "Must provide keyword argument q for Flemington-Harrington test statistic"
              )
          kwargs["test_name"] = kwargs["test_name"].replace(
              "logrank", "Flemington-Harrington"
          )
          kmf = KaplanMeierFitter().fit(
              event_durations, event_observed=event_observed
          )
          s = kmf.survival_function_.to_numpy().flatten()[
              :-1
          ]  # Left-continuous Kaplan-Meier survival estimate.
          w_i = np.power(s, p) * np.power(1.0 - s, q)
      else:
          raise ValueError("Invalid value for weightings.")
  
      # apply weights to observed and expected
      N_j = obs.mul(w_i, axis=0).sum(0).values
      ev = ev_i.mul(w_i, axis=0).sum(0)
  
      # vector of observed minus expected
      Z_j = N_j - ev
  
      assert (
          abs(Z_j.sum()) < 10e-8
      ), "Sum is not zero."  # this should move to a test eventually.
  
      # compute covariance matrix
      factor = (
          (((n_i - d_i) / (n_i - 1)).replace([np.inf, np.nan], 1))
          * d_i
          / n_i**2
      )
      n_ij["_"] = n_i.values
      V_ = (
          (n_ij.mul(w_i, axis=0))
          .mul(np.sqrt(factor), axis="index")
          .fillna(0)
      )  # weighted V_
      V = -np.dot(V_.T, V_)
      ix = np.arange(n_groups)
      V[ix, ix] = V[ix, ix] - V[-1, ix]
      V = V[:-1, :-1]
  
      # take the first n-1 groups
      U = (
          Z_j.iloc[:-1] @ np.linalg.pinv(V[:-1, :-1]) @ Z_j.iloc[:-1]
      )  # Z.T*inv(V)*Z
  
      # compute the p-values and tests
      p_value = _chisq_test_p_value(U, n_groups - 1)
      return StatisticalResult(
          p_value,
          U,
          t_0=t_0,
          null_distribution="chi squared",
          degrees_of_freedom=n_groups - 1,
          **kwargs,
      )
  
imports: from itertools import combinations
  import warnings
  import numpy
  from scipy import stats
  import pandas
  from lifelines import utils
  from lifelines.utils import group_survival_table_from_events, string_rjustify, format_p_value, format_floats, interpolate_at_times_and_return_pandas, _expected_value_of_survival_up_to_t, _expected_value_of_survival_squared_up_to_t
  from lifelines import KaplanMeierFitter
label_desc: Use image node_id 7 for calling a global function with example usage: multivariate_logrank_test(event_durations, groups, event_observed, weights, t_0, weightings) and returns: StatisticalResult