私はRからPythonに来て、Pythonを使用してRで行うことに慣れている多くのことを再現しようとしています。Rの行列ライブラリにはnearPD()
、指定された行列に最も近い正の半確定(PSD)行列を見つけるという非常に気の利いた関数があります。Python / Numpyに慣れていないので、何かをコーディングすることはできますが、何かがすでに存在している場合でも、車輪の再発明にそれほど興奮することはありません。Pythonの既存の実装に関するヒントはありますか?
質問する
15108 次
4 に答える
34
必要な行列を返すライブラリはないと思いますが、Higham(2000)の近東正の半確定行列アルゴリズムの「ただの楽しみ」コーディングを次に示します。
import numpy as np,numpy.linalg
def _getAplus(A):
eigval, eigvec = np.linalg.eig(A)
Q = np.matrix(eigvec)
xdiag = np.matrix(np.diag(np.maximum(eigval, 0)))
return Q*xdiag*Q.T
def _getPs(A, W=None):
W05 = np.matrix(W**.5)
return W05.I * _getAplus(W05 * A * W05) * W05.I
def _getPu(A, W=None):
Aret = np.array(A.copy())
Aret[W > 0] = np.array(W)[W > 0]
return np.matrix(Aret)
def nearPD(A, nit=10):
n = A.shape[0]
W = np.identity(n)
# W is the matrix used for the norm (assumed to be Identity matrix here)
# the algorithm should work for any diagonal W
deltaS = 0
Yk = A.copy()
for k in range(nit):
Rk = Yk - deltaS
Xk = _getPs(Rk, W=W)
deltaS = Xk - Rk
Yk = _getPu(Xk, W=W)
return Yk
紙の例でテストすると、正解が返されます
print nearPD(np.matrix([[2,-1,0,0],[-1,2,-1,0],[0,-1,2,-1],[0,0,-1,2]]),nit=10)
[[ 1. -0.80842467 0.19157533 0.10677227]
[-0.80842467 1. -0.65626745 0.19157533]
[ 0.19157533 -0.65626745 1. -0.80842467]
[ 0.10677227 0.19157533 -0.80842467 1. ]]
于 2012-06-07T21:40:03.380 に答える
3
これはおそらく、相関行列と共分散行列の両方を考慮する DomPazz answer のばかげた拡張です。また、多数の行列を扱っている場合は早期終了します。
def near_psd(x, epsilon=0):
'''
Calculates the nearest postive semi-definite matrix for a correlation/covariance matrix
Parameters
----------
x : array_like
Covariance/correlation matrix
epsilon : float
Eigenvalue limit (usually set to zero to ensure positive definiteness)
Returns
-------
near_cov : array_like
closest positive definite covariance/correlation matrix
Notes
-----
Document source
http://www.quarchome.org/correlationmatrix.pdf
'''
if min(np.linalg.eigvals(x)) > epsilon:
return x
# Removing scaling factor of covariance matrix
n = x.shape[0]
var_list = np.array([np.sqrt(x[i,i]) for i in xrange(n)])
y = np.array([[x[i, j]/(var_list[i]*var_list[j]) for i in xrange(n)] for j in xrange(n)])
# getting the nearest correlation matrix
eigval, eigvec = np.linalg.eig(y)
val = np.matrix(np.maximum(eigval, epsilon))
vec = np.matrix(eigvec)
T = 1/(np.multiply(vec, vec) * val.T)
T = np.matrix(np.sqrt(np.diag(np.array(T).reshape((n)) )))
B = T * vec * np.diag(np.array(np.sqrt(val)).reshape((n)))
near_corr = B*B.T
# returning the scaling factors
near_cov = np.array([[near_corr[i, j]*(var_list[i]*var_list[j]) for i in xrange(n)] for j in xrange(n)])
return near_cov
于 2016-07-25T12:50:54.197 に答える