Repository: statsmodels/statsmodels

Issue:
BUG: issue with how mad handles non-callable center arguments
#### Describe the bug

The center argument in the mad function is supposed to set the location estimate around which the mad will be computed. If center is not callable, the the function sets center to 0, and ignores the input, but the documentation states that center can also be a float. This is what the docs say mad should return: median(abs(a - center))/c. This was already mentioned in #6969. One solution is to change the docs, and add an assert that center is callable. Another possibility is to fix the line that sets center to zero if center is not callable, assert that center is float in that case and use the passed value in the computation. Either way, I'd be happy to write a PR fixing it.

#### Code Sample, a copy-pastable example if possible


```python
import numpy as np
from statsmodels.robust.scale import mad
a = np.array([0, 1, 2])

mad(a, center=-10) #1.482602218505602
mad(a, center=0) #1.482602218505602
np.median(np.abs(a - (-10))) / .6745 #16.30837657524092, this is the right answer for mad(a, center=-10)
```
<details>

**Note**: As you can see, there are many issues on our GitHub tracker, so it is very possible that your issue has been posted before. Please check first before submitting so that we do not have to handle and close duplicates.

**Note**: Please be sure you are using the latest released version of `statsmodels`, or a recent build of `master`. If your problem has been fixed in an unreleased version, you might be able to use `master` until a new release occurs. 

**Note**: If you are using a released version, have you verified that the bug exists in the master branch of this repository? It helps the limited resources if we know problems exist in the current master so that they do not need to check whether the code sample produces a bug in the next release.

</details>


If the issue has not been resolved, please file it in the issue tracker.

#### Expected Output

The output of mad(a, center=center) should be equal to np.median(np.abs(a - center)) / .6745.
#### Output of ``import statsmodels.api as sm; sm.show_versions()``

<details>

INSTALLED VERSIONS
------------------
Python: 3.8.2.final.0
OS: Linux 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8

statsmodels
===========

Installed: v0.12.0rc0+31.g1e6b7c6ef (/home/esmucler/Packages/statsmodels/statsmodels)

Required Dependencies
=====================
cython: 0.29.21 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/Cython)
numpy: 1.19.1 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/numpy)
scipy: 1.5.2 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/scipy)
pandas: 1.1.0 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/pandas)
    dateutil: 2.8.1 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/dateutil)
patsy: 0.5.1 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/patsy)

Optional Dependencies
=====================
matplotlib: 3.3.1 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/matplotlib)
    backend: agg 
cvxopt: Not installed
joblib: Not installed

Developer Tools
================
IPython: 7.17.0 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/IPython)
    jinja2: 2.11.2 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/jinja2)
sphinx: 3.2.1 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/sphinx)
    pygments: 2.6.1 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/pygments)
pytest: 6.0.1 (/home/esmucler/Packages/statsmodels/venv/lib/python3.8/site-packages/pytest)
virtualenv: Not installed

</details>



Discussion:
The code is a bug and should use the user provided center if it is not callable.

It should be possible to quickfix this, so it can still go into 0.12 before Friday
@bashtage 

Resolving patch:
diff --git a/statsmodels/robust/scale.py b/statsmodels/robust/scale.py
--- a/statsmodels/robust/scale.py
+++ b/statsmodels/robust/scale.py
@@ -45,10 +45,12 @@ def mad(a, c=Gaussian.ppf(3/4.), axis=0, center=np.median):
     """
     a = array_like(a, 'a', ndim=None)
     c = float_like(c, 'c')
-    if callable(center) and a.size:
+    if not a.size:
+        center = 0.0
+    elif callable(center):
         center = np.apply_over_axes(center, a, axis)
     else:
-        center = 0.0
+        center = float_like(center, "center")
 
     return np.median((np.abs(a-center)) / c, axis=axis)
 


Test patch:
diff --git a/statsmodels/robust/tests/test_scale.py b/statsmodels/robust/tests/test_scale.py
--- a/statsmodels/robust/tests/test_scale.py
+++ b/statsmodels/robust/tests/test_scale.py
@@ -5,6 +5,7 @@
 import numpy as np
 from numpy.random import standard_normal
 from numpy.testing import assert_almost_equal, assert_equal
+from scipy.stats import norm as Gaussian
 import pytest
 # Example from Section 5.5, Venables & Ripley (2002)
 
@@ -81,6 +82,12 @@ def test_mad_empty(self):
     def test_mad_center(self):
         n = scale.mad(self.X, center=0)
         assert_equal(n.shape, (10,))
+        with pytest.raises(TypeError):
+            scale.mad(self.X, center=None)
+        assert_almost_equal(scale.mad(self.X, center=1),
+                            np.median(np.abs(self.X - 1),
+                                      axis=0)/Gaussian.ppf(3/4.),
+                            DECIMAL)
 
 
 class TestMadAxes(object):