class_docstr: Huber's proposal 2 for estimating location and scale jointly.
  
  Parameters
  ----------
  c : float, optional
      Threshold used in threshold for chi=psi**2.  Default value is 1.5.
  tol : float, optional
      Tolerance for convergence.  Default value is 1e-08.
  maxiter : int, optional0
      Maximum number of iterations.  Default value is 30.
  norm : statsmodels.robust.norms.RobustNorm, optional
      A robust norm used in M estimator of location. If None,
      the location estimator defaults to a one-step
      fixed point version of the M-estimator using Huber's T.
  
  call
      Return joint estimates of Huber's scale and location.
  
  Examples
  --------
  >>> import numpy as np
  >>> import statsmodels.api as sm
  >>> chem_data = np.array([2.20, 2.20, 2.4, 2.4, 2.5, 2.7, 2.8, 2.9, 3.03,
  ...        3.03, 3.10, 3.37, 3.4, 3.4, 3.4, 3.5, 3.6, 3.7, 3.7, 3.7, 3.7,
  ...        3.77, 5.28, 28.95])
  >>> sm.robust.scale.huber(chem_data)
  (array(3.2054980819923693), array(0.67365260010478967))
class_docstr_tok: ["Huber","'s","proposal","2","for","estimating","location","and","scale","jointly",".","Parameters","--","--","--","--","--","c",":","float",",","optional","Threshold","used","in","threshold","for","chi=psi","*","*","2",".","Default","value","is","1.5.","tol",":","float",",","optional","Tolerance","for","convergence",".","Default","value","is","1e-08",".","maxiter",":","int",",","optional0","Maximum","number","of","iterations",".","Default","value","is","30.","norm",":","statsmodels.robust.norms.RobustNorm",",","optional","A","robust","norm","used","in","M","estimator","of","location",".","If","None",",","the","location","estimator","defaults","to","a","one-step","fixed","point","version","of","the","M-estimator","using","Huber","'s","T.","call","Return","joint","estimates","of","Huber","'s","scale","and","location",".","Examples","--","--","--","--",">",">",">","import","numpy","as","np",">",">",">","import","statsmodels.api","as","sm",">",">",">","chem_data","=","np.array","(","[","2.20",",","2.20",",","2.4",",","2.4",",","2.5",",","2.7",",","2.8",",","2.9",",","3.03",",","...","3.03",",","3.10",",","3.37",",","3.4",",","3.4",",","3.4",",","3.5",",","3.6",",","3.7",",","3.7",",","3.7",",","3.7",",","...","3.77",",","5.28",",","28.95","]",")",">",">",">","sm.robust.scale.huber","(","chem_data",")","(","array","(","3.2054980819923693",")",",","array","(","0.67365260010478967",")",")"]
docstr: Estimate scale and location simultaneously with the following
  pseudo_loop:
  
  while not_converged:
      mu, scale = estimate_location(a, scale, mu), estimate_scale(a, scale, mu)
  
  where estimate_location is an M-estimator and estimate_scale implements
  the check used in Section 5.5 of Venables & Ripley
docstr_tok: ["Estimate","scale","and","location","simultaneously","with","the","following","pseudo_loop",":","while","not_converged",":","mu",",","scale","=","estimate_location","(","a",",","scale",",","mu",")",",","estimate_scale","(","a",",","scale",",","mu",")","where","estimate_location","is","an","M-estimator","and","estimate_scale","implements","the","check","used","in","Section","5.5","of","Venables","&","Ripley"]
code: def _estimate_both(self, a, scale, mu, axis, est_mu, n):
      """
      Estimate scale and location simultaneously with the following
      pseudo_loop:
  
      while not_converged:
          mu, scale = estimate_location(a, scale, mu), estimate_scale(a, scale, mu)
  
      where estimate_location is an M-estimator and estimate_scale implements
      the check used in Section 5.5 of Venables & Ripley
      """  # noqa:E501
      for _ in range(self.maxiter):
          # Estimate the mean along a given axis
          if est_mu:
              if self.norm is None:
                  # This is a one-step fixed-point estimator
                  # if self.norm == norms.HuberT
                  # It should be faster than using norms.HuberT
                  nmu = (
                      np.clip(
                          a, mu - self.c * scale, mu + self.c * scale
                      ).sum(axis)
                      / a.shape[axis]
                  )
              else:
                  nmu = norms.estimate_location(
                      a,
                      scale,
                      self.norm,
                      axis,
                      mu,
                      self.maxiter,
                      self.tol,
                  )
          else:
              # Effectively, do nothing
              nmu = mu.squeeze()
          nmu = tools.unsqueeze(nmu, axis, a.shape)
  
          subset = np.less_equal(np.abs((a - mu) / scale), self.c)
          card = subset.sum(axis)
  
          scale_num = np.sum(subset * (a - nmu) ** 2, axis)
          scale_denom = (
              n * self.gamma - (a.shape[axis] - card) * self.c**2
          )
          nscale = np.sqrt(scale_num / scale_denom)
          nscale = tools.unsqueeze(nscale, axis, a.shape)
  
          test1 = np.all(
              np.less_equal(np.abs(scale - nscale), nscale * self.tol)
          )
          test2 = np.all(
              np.less_equal(np.abs(mu - nmu), nscale * self.tol)
          )
          if not (test1 and test2):
              mu = nmu
              scale = nscale
          else:
              return nmu.squeeze(), nscale.squeeze()
      raise ValueError(
          "joint estimation of location and scale failed "
          "to converge in %d iterations" % self.maxiter
      )
  
file_path: statsmodels/statsmodels/robust/scale.py
imports: import numpy
  from scipy.stats import norm
  from statsmodels.tools import tools
  from statsmodels.tools.validation import array_like, float_like
  from .None import norms
  from ._qn import _qn
label_desc: Use image node_id 3 for calling the Huber obj's underlying member method code with example usage: obj._estimate_both(a, scale, mu, axis, est_mu, n) and returns: nmu,  nscale