SVD, pseudoinverse en PCA: SVD, pseudoinverse en PCA in Python
Pseudoinverse
Python heeft de functie pinv
aan boord in het numpy.linalg
pakket om numeriek de pseudoinverse van een matrix te bepalen.
Voorbeeld 1: lineaire regressie Eerst rekenen we het voorbeeld uit de lestekst na:
>>> import numpy as np
>>> import numpy.linalg as la
>>> A = np.array([[1,1],[1,2],[1,3]]); print(A) # matrix A voor regressielijn
[[1 1]
[1 2]
[1 3]]
>>> b = np.array([2,2,4]); print(b) # gegevensvector
[2 2 4]
>>> Ainv = la.pinv(A); print(np.round(Ainv, 4)) # pseudoinverse
[[ 1.3333 0.3333 -0.6667]
[-0.5 0. 0.5 ]]
>>> print(np.round(Ainv @ b, 4)) # coëfficiënten regressielijn
[0.6667 1. ]
Hier staat de uitkomst: .
We kunnen het resultaat ook via de singulierewaardenontbinding berekenen.
>>> U, S, Vt = la.svd(A, full_matrices=False) # SVD van A
>>> print(U) # matrix U in SVD
[[-0.32310986 0.85377594]
[-0.54750702 0.18321952]
[-0.77190419 -0.4873369 ]]
>>> print(np.diag(S)) # diagonaalmatrix met singuliere waarden
[[4.07914333 0. ]
[0. 0.60049122]]
>>> print(Vt) # getransponeerde van matrix V in SVD
[[-0.40266324 -0.91534819]
[ 0.91534819 -0.40266324]]
>>> print(U @ np.diag(S) @ Vt) # check van SVD berekening
[[1., 1.],
[1., 2.],
[1., 3.]])
>>> Splus = la.inv(np.diag(S)); print(Splus)
[[0.24514951, 0. ]
[0. , 1.66530329]
>>> Ainv = Vt.transpose() @ Splus @ U.transpose()
>>> print(np.round(Ainv, 4))
[[ 1.3333 0.3333 -0.6667]
[-0.5 0. 0.5 ]]
>>> print(np.round(Ainv @ b, 4)) # coëfficiënten regressielijn
[0.6667 1. ]
Voorbeeld 2: kwadratische regressie Het tweede voorbeeld betreft een gegevensverzameling die we construeren door ruis aan de parabool toe te voegen. We zoeken daarna de best bij de gegevens passende parabool. In onze dataset wordt deze bij benadering .
>>> import numpy as np
>>> import numpy.linalg as la
>>> import matplotlib.pyplot as plt
>>> x = np.arange(0, 4, 0.5)
>>> y = 1 - 2*x +1/2*x**2
>>> y = y + 0.1*max(y)*(2*np.random.randint(2, size=m) - np.ones(m))
>>> A = np.vstack((np.ones(m), x, x**2)).transpose()
>>> pinvA = la.pinv(A)
>>> c = pinvA @ y; print(c)
[ 0.975 -1.93571429 0.48571429]
>>> xx = np.linspace(-0.1,4.1,50)
>>> yy = c[0] + c[1]*xx + c[2]*xx**2
>>> plt.plot(x, y, 'bo')
>>> plt.plot(xx, yy, 'g-')
>>> plt.axis([-0.1, 4.1, -1.1, 1.1])
>>> plt.show()
Ontgrendel volledige toegang