2024-10-02 22:15:59 +04:00

150 lines
4.3 KiB
Python

"""
Created on Wed May 16 22:21:26 2018
Author: Josef Perktold
License: BSD-3
"""
import numpy as np
from numpy.testing import assert_allclose, assert_equal
import statsmodels.base._penalties as smpen
from statsmodels.tools.numdiff import approx_fprime, approx_hess
class CheckPenalty:
def test_symmetry(self):
pen = self.pen
x = self.params
p = np.array([pen.func(np.atleast_1d(xi)) for xi in x])
assert_allclose(p, p[::-1], rtol=1e-10)
# func(0) should be 0
assert_allclose(pen.func(0 * np.atleast_1d(x[0])), 0, rtol=1e-10)
def test_derivatives(self):
pen = self.pen
x = self.params
ps = np.array([pen.deriv(np.atleast_1d(xi)) for xi in x])
psn = np.array([approx_fprime(np.atleast_1d(xi), pen.func) for xi in x])
assert_allclose(ps, psn, rtol=1e-7, atol=1e-8)
ph = np.array([pen.deriv2(np.atleast_1d(xi)) for xi in x])
phn = np.array([approx_hess(np.atleast_1d(xi), pen.func) for xi in x])
if ph.ndim == 2:
# SmoothedSCAD returns only diagonal if hessian if independent
# TODO should ww allow this also in L@?
ph = np.array([np.diag(phi) for phi in ph])
assert_allclose(ph, phn, rtol=1e-7, atol=1e-8)
class TestL2Constraints0(CheckPenalty):
@classmethod
def setup_class(cls):
x0 = np.linspace(-0.2, 0.2, 11)
cls.params = np.column_stack((x0, x0))
cls.pen = smpen.L2ConstraintsPenalty()
def test_equivalence(self):
# compare plain penalty with included weights or restriction
pen = self.pen
x = self.params
k = x.shape[1]
pen2 = smpen.L2ConstraintsPenalty(weights=np.ones(k))
pen3 = smpen.L2ConstraintsPenalty(restriction=np.eye(k))
f = pen.func(x.T)
d = pen.deriv(x.T)
d2 = np.array([pen.deriv2(np.atleast_1d(xi)) for xi in x])
for pen_ in [pen2, pen3]:
assert_allclose(pen_.func(x.T), f, rtol=1e-7, atol=1e-8)
assert_allclose(pen_.deriv(x.T), d, rtol=1e-7, atol=1e-8)
d2_ = np.array([pen.deriv2(np.atleast_1d(xi)) for xi in x])
assert_allclose(d2_, d2, rtol=1e-10, atol=1e-8)
class TestL2Constraints1(CheckPenalty):
@classmethod
def setup_class(cls):
x0 = np.linspace(-0.2, 0.2, 11)
cls.params = np.column_stack((x0, x0))
cls.pen = smpen.L2ConstraintsPenalty(restriction=[[1,0], [1, 1]])
def test_values(self):
pen = self.pen
x = self.params
r = pen.restriction
f = (r.dot(x.T)**2).sum(0)
assert_allclose(pen.func(x.T), f, rtol=1e-7, atol=1e-8)
class TestSmoothedSCAD(CheckPenalty):
@classmethod
def setup_class(cls):
x0 = np.linspace(-0.2, 0.2, 11)
cls.params = np.column_stack((x0, x0))
cls.pen = smpen.SCADSmoothed(tau=0.05, c0=0.05)
class TestPseudoHuber(CheckPenalty):
@classmethod
def setup_class(cls):
x0 = np.linspace(-0.2, 0.2, 11)
cls.params = np.column_stack((x0, x0))
cls.pen = smpen.PseudoHuber(0.1)
def test_backward_compatibility(self):
wts = [0.5]
pen = smpen.PseudoHuber(0.1, weights=wts)
assert_equal(pen.weights, wts)
def test_deprecated_priority(self):
weights = [1.0]
pen = smpen.PseudoHuber(0.1, weights=weights)
assert_equal(pen.weights, weights)
def test_weights_assignment(self):
weights = [1.0, 2.0]
pen = smpen.PseudoHuber(0.1, weights=weights)
assert_equal(pen.weights, weights)
class TestL2(CheckPenalty):
@classmethod
def setup_class(cls):
x0 = np.linspace(-0.2, 0.2, 11)
cls.params = np.column_stack((x0, x0))
cls.pen = smpen.L2()
def test_backward_compatibility(self):
wts = [0.5]
pen = smpen.L2(weights=wts)
assert_equal(pen.weights, wts)
def test_deprecated_priority(self):
weights = [1.0]
pen = smpen.L2(weights=weights)
assert_equal(pen.weights, weights)
def test_weights_assignment(self):
weights = [1.0, 2.0]
pen = smpen.L2(weights=weights)
assert_equal(pen.weights, weights)
class TestNonePenalty(CheckPenalty):
@classmethod
def setup_class(cls):
x0 = np.linspace(-0.2, 0.2, 11)
cls.params = np.column_stack((x0, x0))
cls.pen = smpen.NonePenalty()