blob: b21c50ad99fba43fe5a50d5408e72d028c62eba3 [file] [log] [blame]
Austin Schuh9049e202022-02-20 17:34:16 -08001Huber fitting
2=============
3
4*Huber fitting* or the *robust least-squares problem* performs linear regression under the assumption that there are outliers in the data.
5The fitting problem is written as
6
7.. math::
8 \begin{array}{ll}
9 \mbox{minimize} & \sum_{i=1}^{m} \phi_{\rm hub}(a_i^T x - b_i),
10 \end{array}
11
12with the Huber penalty function :math:`\phi_{\rm hub}:\mathbf{R}\to\mathbf{R}` defined as
13
14.. math::
15 \phi_{\rm hub}(u) =
16 \begin{cases}
17 u^2 & |u| \le 1 \\
18 (2|u| - 1) & |u| > 1
19 \end{cases}
20
21The problem has the following equivalent form (see `here <https://doi.org/10.1109/34.877518>`_ for more details)
22
23.. math::
24 \begin{array}{ll}
25 \mbox{minimize} & u^T u + 2\,\boldsymbol{1}^T (r+s) \\
26 \mbox{subject to} & Ax - b - u = r - s \\
27 & r \ge 0 \\
28 & s \ge 0
29 \end{array}
30
31
32
33Python
34------
35
36.. code:: python
37
38 import osqp
39 import numpy as np
40 import scipy as sp
41 from scipy import sparse
42
43 # Generate problem data
44 sp.random.seed(1)
45 n = 10
46 m = 100
47 Ad = sparse.random(m, n, density=0.5, format='csc')
48 x_true = np.random.randn(n) / np.sqrt(n)
49 ind95 = (np.random.rand(m) < 0.95).astype(float)
50 b = Ad.dot(x_true) + np.multiply(0.5*np.random.randn(m), ind95) \
51 + np.multiply(10.*np.random.rand(m), 1. - ind95)
52
53 # OSQP data
54 Im = sparse.eye(m)
55 P = sparse.block_diag([sparse.csc_matrix((n, n)), 2*Im,
56 sparse.csc_matrix((2*m, 2*m))],
57 format='csc')
58 q = np.append(np.zeros(m+n), 2*np.ones(2*m))
59 A = sparse.bmat([[Ad, -Im, -Im, Im],
60 [None, None, Im, None],
61 [None, None, None, Im]], format='csc')
62 l = np.hstack([b, np.zeros(2*m)])
63 u = np.hstack([b, np.inf*np.ones(2*m)])
64
65 # Create an OSQP object
66 prob = osqp.OSQP()
67
68 # Setup workspace
69 prob.setup(P, q, A, l, u)
70
71 # Solve problem
72 res = prob.solve()
73
74
75
76Matlab
77------
78
79.. code:: matlab
80
81 % Generate problem data
82 rng(1)
83 n = 10;
84 m = 100;
85 Ad = sprandn(m, n, 0.5);
86 x_true = randn(n, 1) / sqrt(n);
87 ind95 = rand(m, 1) > 0.95;
88 b = Ad*x_true + 10*rand(m, 1).*ind95 + 0.5*randn(m, 1).*(1-ind95);
89
90 % OSQP data
91 Im = speye(m);
92 Om = sparse(m, m);
93 Omn = sparse(m, n);
94 P = blkdiag(sparse(n, n), 2*Im, sparse(2*m, 2*m));
95 q = [zeros(m + n, 1); 2*ones(2*m, 1)];
96 A = [Ad, -Im, -Im, Im;
97 Omn, Om, Im, Om;
98 Omn, Om, Om, Im];
99 l = [b; zeros(2*m, 1)];
100 u = [b; inf*ones(2*m, 1)];
101
102 % Create an OSQP object
103 prob = osqp;
104
105 % Setup workspace
106 prob.setup(P, q, A, l, u);
107
108 % Solve problem
109 res = prob.solve();
110
111
112
113CVXPY
114-----
115
116.. code:: python
117
118 from cvxpy import *
119 import numpy as np
120 import scipy as sp
121 from scipy import sparse
122
123 # Generate problem data
124 sp.random.seed(1)
125 n = 10
126 m = 100
127 A = sparse.random(m, n, density=0.5, format='csc')
128 x_true = np.random.randn(n) / np.sqrt(n)
129 ind95 = (np.random.rand(m) < 0.95).astype(float)
130 b = A.dot(x_true) + np.multiply(0.5*np.random.randn(m), ind95) \
131 + np.multiply(10.*np.random.rand(m), 1. - ind95)
132
133 # Define problem
134 x = Variable(n)
135 objective = sum(huber(A*x - b))
136
137 # Solve with OSQP
138 Problem(Minimize(objective)).solve(solver=OSQP)
139
140
141
142YALMIP
143------
144
145.. code:: matlab
146
147 % Generate problem data
148 rng(1)
149 n = 10;
150 m = 100;
151 A = sprandn(m, n, 0.5);
152 x_true = randn(n, 1) / sqrt(n);
153 ind95 = rand(m, 1) > 0.95;
154 b = A*x_true + 10*rand(m, 1).*ind95 + 0.5*randn(m, 1).*(1-ind95);
155
156 % Define problem
157 x = sdpvar(n, 1);
158 objective = huber(A*x - b);
159
160 % Solve with OSQP
161 options = sdpsettings('solver', 'osqp');
162 optimize([], objective, options);