class_docstr: Analyses for a collection of 2x2 contingency tables.
  
  Such a collection may arise by stratifying a single 2x2 table with
  respect to another factor.  This class implements the
  'Cochran-Mantel-Haenszel' and 'Breslow-Day' procedures for
  analyzing collections of 2x2 contingency tables.
  
  Parameters
  ----------
  tables : list or ndarray
      Either a list containing several 2x2 contingency tables, or
      a 2x2xk ndarray in which each slice along the third axis is a
      2x2 contingency table.
  
  Notes
  -----
  This results are based on a sampling model in which the units are
  independent both within and between strata.
class_docstr_tok: ["Analyses","for","a","collection","of","2x2","contingency","tables",".","Such","a","collection","may","arise","by","stratifying","a","single","2x2","table","with","respect","to","another","factor",".","This","class","implements","the","'Cochran-Mantel-Haenszel","'","and","'Breslow-Day","'","procedures","for","analyzing","collections","of","2x2","contingency","tables",".","Parameters","--","--","--","--","--","tables",":","list","or","ndarray","Either","a","list","containing","several","2x2","contingency","tables",",","or","a","2x2xk","ndarray","in","which","each","slice","along","the","third","axis","is","a","2x2","contingency","table",".","Notes","--","--","-","This","results","are","based","on","a","sampling","model","in","which","the","units","are","independent","both","within","and","between","strata","."]
code: def __init__(self, tables, shift_zeros=False):
      if isinstance(tables, np.ndarray):
          sp = tables.shape
          if (len(sp) != 3) or (sp[0] != 2) or (sp[1] != 2):
              raise ValueError("If an ndarray, argument must be 2x2xn")
          table = tables * 1.0  # use atleast float dtype
      else:
          if any([np.asarray(x).shape != (2, 2) for x in tables]):
              m = "If `tables` is a list, all of its elements should be 2x2"
              raise ValueError(m)
  
          # Create a data cube
          table = np.dstack(tables).astype(np.float64)
  
      if shift_zeros:
          zx = (table == 0).sum(0).sum(0)
          ix = np.flatnonzero(zx > 0)
          if len(ix) > 0:
              table = table.copy()
              table[:, :, ix] += 0.5
  
      self.table = table
  
      self._cache = {}
  
      # Quantities to precompute.  Table entries are [[a, b], [c,
      # d]], 'ad' is 'a * d', 'apb' is 'a + b', 'dma' is 'd - a',
      # etc.
      self._apb = table[0, 0, :] + table[0, 1, :]
      self._apc = table[0, 0, :] + table[1, 0, :]
      self._bpd = table[0, 1, :] + table[1, 1, :]
      self._cpd = table[1, 0, :] + table[1, 1, :]
      self._ad = table[0, 0, :] * table[1, 1, :]
      self._bc = table[0, 1, :] * table[1, 0, :]
      self._apd = table[0, 0, :] + table[1, 1, :]
      self._dma = table[1, 1, :] - table[0, 0, :]
      self._n = table.sum(0).sum(0)
  
imports: import warnings
  import numpy
  import pandas
  from scipy import stats
  from statsmodels import iolib
  from statsmodels.tools import sm_exceptions
  from statsmodels.tools.decorators import cache_readonly
label_desc: Use image node_id 1 to create a new StratifiedTable object  with example: obj = StratifiedTable(tables, shift_zeros)