Skip to content

Commit 1655aec

Browse files
committed
MAINT: remove functions duplicated from scipy
1 parent f49c692 commit 1655aec

File tree

2 files changed

+5
-220
lines changed

2 files changed

+5
-220
lines changed

statsmodels/tools/linalg.py

+5-196
Original file line numberDiff line numberDiff line change
@@ -1,201 +1,10 @@
1-
'''local, adjusted version from scipy.linalg.basic.py
2-
3-
4-
changes:
5-
The only changes are that additional results are returned
6-
7-
'''
1+
"""
2+
Linear Algebra solvers and other helpers
3+
"""
84
from __future__ import print_function
9-
from statsmodels.compat.python import lmap, range
5+
from statsmodels.compat.python import range
106
import numpy as np
11-
from scipy.linalg import svd as decomp_svd
12-
from scipy.linalg.lapack import get_lapack_funcs
13-
from numpy import asarray, zeros, sum, conjugate, dot, transpose
14-
import numpy
15-
from numpy import asarray_chkfinite, single
16-
from numpy.linalg import LinAlgError
17-
18-
19-
# Linear Least Squares
20-
21-
def lstsq(a, b, cond=None, overwrite_a=0, overwrite_b=0):
22-
"""Compute least-squares solution to equation :m:`a x = b`
23-
24-
Compute a vector x such that the 2-norm :m:`|b - a x|` is minimised.
25-
26-
Parameters
27-
----------
28-
a : array, shape (M, N)
29-
b : array, shape (M,) or (M, K)
30-
cond : float
31-
Cutoff for 'small' singular values; used to determine effective
32-
rank of a. Singular values smaller than rcond*largest_singular_value
33-
are considered zero.
34-
overwrite_a : boolean
35-
Discard data in a (may enhance performance)
36-
overwrite_b : boolean
37-
Discard data in b (may enhance performance)
38-
39-
Returns
40-
-------
41-
x : array, shape (N,) or (N, K) depending on shape of b
42-
Least-squares solution
43-
residues : array, shape () or (1,) or (K,)
44-
Sums of residues, squared 2-norm for each column in :m:`b - a x`
45-
If rank of matrix a is < N or > M this is an empty array.
46-
If b was 1-d, this is an (1,) shape array, otherwise the shape is (K,)
47-
rank : integer
48-
Effective rank of matrix a
49-
s : array, shape (min(M,N),)
50-
Singular values of a. The condition number of a is abs(s[0]/s[-1]).
51-
52-
Raises LinAlgError if computation does not converge
53-
54-
"""
55-
a1, b1 = lmap(asarray_chkfinite, (a, b))
56-
if a1.ndim != 2:
57-
raise ValueError('expected matrix')
58-
m, n = a1.shape
59-
if b1.ndim == 2:
60-
nrhs = b1.shape[1]
61-
else:
62-
nrhs = 1
63-
if m != b1.shape[0]:
64-
raise ValueError('incompatible dimensions')
65-
gelss, = get_lapack_funcs(('gelss',), (a1, b1))
66-
if n > m:
67-
# need to extend b matrix as it will be filled with
68-
# a larger solution matrix
69-
b2 = zeros((n, nrhs), dtype=gelss.dtype)
70-
if b1.ndim == 2:
71-
b2[:m, :] = b1
72-
else:
73-
b2[:m, 0] = b1
74-
b1 = b2
75-
overwrite_a = overwrite_a or (a1 is not a and not hasattr(a, '__array__'))
76-
overwrite_b = overwrite_b or (b1 is not b and not hasattr(b, '__array__'))
77-
78-
if gelss.module_name[:7] == 'flapack':
79-
80-
# get optimal work array
81-
work = gelss(a1, b1, lwork=-1)[4]
82-
lwork = work[0].real.astype(np.int)
83-
v, x, s, rank, work, info = gelss(
84-
a1, b1, cond=cond, lwork=lwork, overwrite_a=overwrite_a,
85-
overwrite_b=overwrite_b)
86-
87-
else:
88-
raise NotImplementedError('calling gelss from %s' %
89-
gelss.module_name)
90-
if info > 0:
91-
raise LinAlgError("SVD did not converge in Linear Least Squares")
92-
if info < 0:
93-
raise ValueError('illegal value in %-th argument of '
94-
'internal gelss' % -info)
95-
resids = asarray([], dtype=x.dtype)
96-
if n < m:
97-
x1 = x[:n]
98-
if rank == n:
99-
resids = sum(x[n:]**2, axis=0)
100-
x = x1
101-
return x, resids, rank, s
102-
103-
104-
def pinv(a, cond=None, rcond=None):
105-
"""Compute the (Moore-Penrose) pseudo-inverse of a matrix.
106-
107-
Calculate a generalized inverse of a matrix using a least-squares
108-
solver.
109-
110-
Parameters
111-
----------
112-
a : array, shape (M, N)
113-
Matrix to be pseudo-inverted
114-
cond, rcond : float
115-
Cutoff for 'small' singular values in the least-squares solver.
116-
Singular values smaller than rcond*largest_singular_value are
117-
considered zero.
118-
119-
Returns
120-
-------
121-
B : array, shape (N, M)
122-
123-
Raises LinAlgError if computation does not converge
124-
125-
Examples
126-
--------
127-
>>> from numpy import *
128-
>>> a = random.randn(9, 6)
129-
>>> B = linalg.pinv(a)
130-
>>> allclose(a, dot(a, dot(B, a)))
131-
True
132-
>>> allclose(B, dot(B, dot(a, B)))
133-
True
134-
135-
"""
136-
a = asarray_chkfinite(a)
137-
b = numpy.identity(a.shape[0], dtype=a.dtype)
138-
if rcond is not None:
139-
cond = rcond
140-
return lstsq(a, b, cond=cond)[0]
141-
142-
143-
eps = numpy.finfo(float).eps
144-
feps = numpy.finfo(single).eps
145-
146-
_array_precision = {'f': 0, 'd': 1, 'F': 0, 'D': 1}
147-
148-
149-
def pinv2(a, cond=None, rcond=None):
150-
"""Compute the (Moore-Penrose) pseudo-inverse of a matrix.
151-
152-
Calculate a generalized inverse of a matrix using its
153-
singular-value decomposition and including all 'large' singular
154-
values.
155-
156-
Parameters
157-
----------
158-
a : array, shape (M, N)
159-
Matrix to be pseudo-inverted
160-
cond, rcond : float or None
161-
Cutoff for 'small' singular values.
162-
Singular values smaller than rcond*largest_singular_value are
163-
considered zero.
164-
165-
If None or -1, suitable machine precision is used.
166-
167-
Returns
168-
-------
169-
B : array, shape (N, M)
170-
171-
Raises LinAlgError if SVD computation does not converge
172-
173-
Examples
174-
--------
175-
>>> from numpy import *
176-
>>> a = random.randn(9, 6)
177-
>>> B = linalg.pinv2(a)
178-
>>> allclose(a, dot(a, dot(B, a)))
179-
True
180-
>>> allclose(B, dot(B, dot(a, B)))
181-
True
182-
183-
"""
184-
a = asarray_chkfinite(a)
185-
u, s, vh = decomp_svd(a)
186-
t = u.dtype.char
187-
if rcond is not None:
188-
cond = rcond
189-
if cond in [None, -1]:
190-
cond = {0: feps*1e3, 1: eps*1e6}[_array_precision[t]]
191-
m, n = a.shape
192-
cutoff = cond*numpy.maximum.reduce(s)
193-
psigma = zeros((m, n), t)
194-
for i in range(len(s)):
195-
if s[i] > cutoff:
196-
psigma[i, i] = 1.0/conjugate(s[i])
197-
# XXX: use lapack/blas routines for dot
198-
return transpose(conjugate(dot(dot(u, psigma), vh)))
7+
from scipy.linalg import pinv, pinv2, lstsq # noqa:F421
1998

2009

20110
def logdet_symm(m, check_symm=False):

statsmodels/tools/tests/test_linalg.py

-24
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,3 @@ def test_stationary_solve_2d():
2222
soln = np.linalg.solve(tmat, b)
2323
soln1 = linalg.stationary_solve(r, b)
2424
assert_allclose(soln, soln1, rtol=1e-5, atol=1e-5)
25-
26-
27-
def test_scipy_equivalence():
28-
# This test was moved from the __main__ section of tools.linalg
29-
# Note on Windows32:
30-
# linalg doesn't always produce the same results in each call
31-
import scipy.linalg
32-
a0 = np.random.randn(100, 10)
33-
b0 = a0.sum(1)[:, None] + np.random.randn(100, 3)
34-
35-
result = linalg.pinv(a0)
36-
expected = scipy.linalg.pinv(a0)
37-
assert_allclose(result, expected)
38-
39-
result = linalg.pinv2(a0)
40-
expected = scipy.linalg.pinv2(a0)
41-
assert_allclose(result, expected)
42-
43-
result = linalg.lstsq(a0, b0)
44-
expected = scipy.linalg.lstsq(a0, b0)
45-
assert_allclose(result[0], expected[0])
46-
assert_allclose(result[1], expected[1])
47-
assert_allclose(result[2], expected[2])
48-
assert_allclose(result[3], expected[3])

0 commit comments

Comments
 (0)