web-dev-qa-db-ja.com

sklearn.decomposition.PCAで、components_が否定的なのはなぜですか?

私はAbdi&Williams- Principal Component Analysis (2010)に従い、 numpy.linalg.svd を使用してSVDを通じて主成分を構築しようとしています。

Sklearnを使用して適合PCAから components_ 属性を表示すると、手動で計算したものとまったく同じ大きさですが、some(すべてではない)は反対の符号です。これは何が原因ですか?

更新:以下の私の(部分的な)回答には、いくつかの追加情報が含まれています。

次の例のデータを見てください。

from pandas_datareader.data import DataReader as dr
import numpy as np
from sklearn.decomposition import PCA
from sklearn.preprocessing import scale

# sample data - shape (20, 3), each column standardized to N~(0,1)
rates = scale(dr(['DGS5', 'DGS10', 'DGS30'], 'fred', 
           start='2017-01-01', end='2017-02-01').pct_change().dropna())

# with sklearn PCA:
pca = PCA().fit(rates)
print(pca.components_)
[[-0.58365629 -0.58614003 -0.56194768]
 [-0.43328092 -0.36048659  0.82602486]
 [-0.68674084  0.72559581 -0.04356302]]

# compare to the manual method via SVD:
u, s, Vh = np.linalg.svd(np.asmatrix(rates), full_matrices=False)
print(Vh)
[[ 0.58365629  0.58614003  0.56194768]
 [ 0.43328092  0.36048659 -0.82602486]
 [-0.68674084  0.72559581 -0.04356302]]

# odd: some, but not all signs reversed
print(np.isclose(Vh, -1 * pca.components_))
[[ True  True  True]
 [ True  True  True]
 [False False False]]
14
Brad Solomon

答えでわかったように、特異値分解(SVD)の結果は、特異ベクトルの点で一意ではありません。実際、XのSVDが\ sum_1 ^ r\s_i u_i v_i ^\topの場合: enter image description here

s_iを降順で並べると、u_1とv_1の符号(つまり、「フリップ」)を変更できることがわかります。マイナス記号はキャンセルされるので、式は保持されます。

これは、SVDが一意であることを示しています左右の特異ベクトルのペアの符号が変わるまで

PCAはXの単なるSVD(またはX ^\top Xの固有値分解)であるため、実行されるたびに同じXで異なる結果を返さないという保証はありません。当然のことながら、scikit学習の実装ではこれを回避する必要があります。絶対値のu_iの最大係数が正であることを(任意)課すことにより、返される(UとVに格納される)特異ベクトルが常に同じであることを保証します。 。

ご覧のように ソース :最初にlinalg.svd()を使用してUとVを計算します。次に、各ベクトルu_i(つまり、Uの行)について、絶対値の最大要素が正の場合、何もしません。それ以外の場合は、u_iを-u_iに、対応する左特異ベクトルv_iを-v_iに変更します。前述のように、マイナス記号がキャンセルされるため、これはSVDの式を変更しません。ただし、標識の不確定要素が削除されているため、この処理の後に返されるUとVが常に同じであることが保証されています。

7
P. Camilleri

少し掘り下げた後、私はこれに関する私の混乱のすべてではなく一部を片付けました。この問題は、stats.stackexchange here でカバーされています。数学的な答えは、「PCAは単純な数学的変換です。コンポーネントの符号を変更しても、最初のコンポーネントに含まれている分散は変更しません。」 ただし、この場合(sklearn.PCAを使用)、あいまいさの原因はより具体的です:ソース内( 行391PCAの場合:

U, S, V = linalg.svd(X, full_matrices=False)
# flip eigenvectors' sign to enforce deterministic output
U, V = svd_flip(U, V)

components_ = V

svd_flipが順番に定義されます here 。しかし、なぜ deterministic 出力を保証するためにサインが反転されているのか、私にはわかりません。 (U、S、Vはこの時点ですでに見つかりました...)。したがって、sklearnの実装は正しくありますが、それほど直感的ではないと思います。ベータ(係数)の概念に精通している金融関係者は誰でも、最初の主成分が広範な市場指数に類似している可能性が高いことを知っています。問題は、sklearnを実装すると、その最初の主成分に強い負の負荷がかかることです。

私の解決策は、svd_flipを実装していない version と言っています。 svd_solverのようなsklearnパラメータがないという点で非常に重要ですが、この目的に特化したメソッドがいくつかあります。

2
Brad Solomon

ここで3次元のPCAを使用すると、基本的に反復的に次のことがわかります。1)最大分散が保存されている1D投影軸2)1)に垂直な最大分散保存軸。 3番目の軸は自動的に最初の2つに垂直な軸になります。

Components_は、説明された分散に従ってリストされます。したがって、最初のものは最も多くの差異を説明します。 PCA操作の定義により、最初のステップでプロジェクション用のベクトルを見つけようとしているときに、保存される分散が最大になることに注意してください。ベクトルの符号は重要ではありません。Mをデータ行列にします(この場合) (20,3)の形をしています。データが投影されるときに、v1を最大分散を維持するためのベクトルとします。 v1ではなく-v1を選択すると、同じ分散が得られます。 (これを確認できます)。次に、2番目のベクトルを選択するとき、v2をv1に垂直で、最大分散を維持するものとします。この場合も、v2ではなく-v2を選択すると、同じ量の分散が保持されます。次に、v3を-v3またはv3として選択できます。ここで重要なのは、v1、v2、v3がデータMの正規直交基底を構成することだけです。符号は、アルゴリズムがPCA演算の根底にある固有ベクトル問題をどのように解決するかに依存します。固有値分解またはSVDソリューションでは、符号が異なる場合があります。

2
Ufuk Can Bicici

これは、数学の部分ではなく、目的を気にする人のための短い通知です。

一部のコンポーネントでは符号が逆になっていますが、これは問題と見なされるべきではありません。実際、私たちが(少なくとも私の理解では)気にしているのは、軸の方向です。コンポーネントは、最終的には、pcaを使用して入力データを変換した後にこれらの軸を識別するベクトルです。したがって、各コンポーネントがどの方向を指しているかに関係なく、データが存在する新しい軸は同じになります。

0
mrt