質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
R

R言語は、「S言語」をオープンソースとして実装なおした、統計解析向けのプログラミング言語です。 計算がとても速くグラフィックも充実しているため、数値計算に向いています。 文法的には、統計解析部分はS言語を参考にしており、データ処理部分はSchemeの影響を受けています。 世界中の専門家が開発に関わり、日々新しい手法やアルゴリズムが追加されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

統計

統計は、集団現象を数量で把握することです。また、調査で得られた性質や傾向を数量的に表したデータのことをいいます。

Q&A

解決済

1回答

4356閲覧

statsmodelsによる主成分分析での主成分負荷量の算出の方法

waku_nagoya

総合スコア200

R

R言語は、「S言語」をオープンソースとして実装なおした、統計解析向けのプログラミング言語です。 計算がとても速くグラフィックも充実しているため、数値計算に向いています。 文法的には、統計解析部分はS言語を参考にしており、データ処理部分はSchemeの影響を受けています。 世界中の専門家が開発に関わり、日々新しい手法やアルゴリズムが追加されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

統計

統計は、集団現象を数量で把握することです。また、調査で得られた性質や傾向を数量的に表したデータのことをいいます。

1グッド

0クリップ

投稿2019/06/20 01:39

実行環境

Mac OSX Mojave
jupyter notebook
Python 3.6.8
statsmodels 0.9.0
R 3.6.0

参考図書

オーム社 入門統計学
ファーストブック 多変量解析がわかる

分からないこと・やりたいこと

Python の statsmodels.multivariate.pca.PCA を使って主成分分析をしたときに、主成分負荷量を算出したいのですが、固有ベクトルと主成分負荷量の意味がこんがらがってしまっており、正しい結果を出力するにはどうすればいいのか分からなくなってきました。

参考図書『多変量解析がわかる』P.78には、

p=ax+by+cu+dv+ew
ただし、a^2+b^2+c^2+d^2+e^2=1

合成変量pが最大の分散値を持つとき、そのpを主成分と呼びます。このときの定数a,b,・・・,eの値を主成分負荷量と呼びます。この主成分pを用いてデータを分析するのが主成分分析です。

と書かれています。
そのため、主成分負荷量は、主成分の式の各係数を二乗した合計値は1になるものと思っていました。

知りたいこと

  1. 主成分負荷量とは、上記のように各係数を二乗した合計値は1になるものなのでしょうか。それとも、それは固有ベクトルなのでしょうか。
  2. statsmodels.multivariate.pca.PCA を使って主成分負荷量を出力する方法を知りたいです。

試したこと・参考にしたこと・そしてよく分からなくなったこと

ファーストブック 多変量解析がわかる 3-2 にある主成分分析の例題をもとに実施

出席番号数学 x理科 y社会 u英語 v国語 w
171648310071
23448675768
35859788766
44151706072
56956748166
664658210071
7164563759
85959785962
95754847372
104654714362
112349643370
123948712966
134655684261
145256826760
153953785272
162343633559
173745673970
185251746569
196356799170
203949736460

この表を元に主成分分析をする。

python

1import numpy as np 2from statsmodels.multivariate.pca import PCA 3 4data = np.array([ 5 [71,34,58,41,69,64,16,59,57,46,23,39,46,52,39,23,37,52,63,39], 6 [64,48,59,51,56,65,45,59,54,54,49,48,55,56,53,43,45,51,56,49], 7 [83,67,78,70,74,82,63,78,84,71,64,71,68,82,78,63,67,74,79,73], 8 [100,57,87,60,81,100,7,59,73,43,33,29,42,67,52,35,39,65,91,64], 9 [71,68,66,72,66,71,59,62,72,62,70,66,61,60,72,59,70,69,70,60] 10]) 11 12ret = PCA(data.T, ncomp=1, standardize=False, normalize=False) 13 14print("主成分", 100 - ret.factors) 15print("主成分負荷量", ret.coeff*-1)
主成分 [[149.96661766] [ 90.07331542] [130.6235937 ] [ 97.38181772] [129.76064147] [146.50319377] [ 37.90790262] [107.65862887] [119.26918818] [ 85.78744696] [ 64.52332319] [ 69.9967705 ] [ 84.47561479] [110.96612123] [ 91.68946286] [ 64.18121726] [ 76.26684286] [107.50284536] [136.34679483] [ 99.11866074]] 主成分負荷量 [[0.491513 0.1730531 0.19588597 0.82781535 0.06941201]]

それからこの主成分負荷量は、それぞれ二乗して合計すると1となりました。

python

1sum(ret.coeff[0]**2)
1.0000000000000002

オーム社 入門統計学 の例題 14章 を元に主成分分析を実施

ところが、別の参考書『オーム社 入門統計学』の例題 14章をやったときに分からなくなりました。

集落番号農家数の増減率農家人口増減率農業就業人口率農業従事者率男子農業就業人口率農業就業人口のうち生産年齢人口率60歳未満男子農業専従者率農業従事者のうちの基幹的農業従事者率兼業従事者率
114.3-9.750.073.138.523.10.047.438.5
2-14.3-21.755.677.862.530.00.050.038.9
3-17.6-22.760.089.150.048.510.251.040.0
4-8.33.858.776.144.451.98.657.132.6
5-3.4-10.661.985.666.738.36.056.637.1
60.0-7.563.687.960.047.613.837.936.4
7-20.0-38.245.288.138.152.60.027.052.4
8-15.0-8.345.277.439.342.92.145.837.1
90.0-21.461.971.463.630.80.073.328.6
10-11.1-16.754.279.235.77.70.057.933.3
11-20.0-18.042.277.845.536.88.648.655.6
12-7.7-24.057.981.655.027.33.264.534.2
13-11.8-28.464.792.250.045.52.155.337.3
140.015.444.492.638.541.70.024.059.3
15-33.3-51.342.189.522.225.00.035.352.6

データは、14-1.xlsxより

この表を元に主成分分析を実施しました。

python

1import pandas as pd 2from statsmodels.multivariate.pca import PCA 3 4df = pd.read_excel('14-1.xlsx') 5df = df.set_index("集落番号") 6 7ret = PCA(df, ncomp=2, standardize=False, normalize=False) 8 9display(ret.factors) 10display(ret.coeff)

出力結果

集落番号comp_0comp_1
1-9.5887845.633295
2-5.765015-9.884144
31.972712-2.103843
4-17.52846814.211070
5-21.2261520.077743
6-12.98154516.437488
735.1920344.361661
83.7991288.998005
9-29.143404-21.182749
10-2.305750-16.643283
1112.6972442.040215
12-12.495731-18.045632
13-1.230358-9.314251
148.32740745.738271
1550.276684-20.323845

|農家数の増減率|農家人口増減率|農業就業人口率|農業従事者率|男子農業就業人口率|農業就業人口のうち生産年齢人口率|60歳未満男子農業専従者率|農業従事者のうちの基幹的農業従事者率|兼業従事者率|
|------------|-----------|---|----|----|----|----|----|
|comp_0|-0.398821|-0.432523|-0.295694|0.163024|-0.457945|0.021984|-0.059636|-0.454728|0.345431|
|comp_1|0.226974|0.697246|-0.116084|0.110778|-0.082904|0.378380|0.065972|-0.478187|0.231353|

この出力結果のうち comp_0 を二乗して合計してみると

python

1rint(sum(np.array(ret.coeff.T['comp_0'])**2))
1.0000000000000004

正しい結果となっているようですが、
参考図書の解答結果と異なるのです。

参考図書の解答結果は、エクセル統計2010で算出したとのことですが、次のような結果となっていました。

主成分負荷量

変数第1主成分第2主成分
農家数の増減率0.610.05
農家人口増減率0.330.35
農業就業人口率0.830.28
農業従事者率-0.510.58
男子農業就業人口率0.780.31
農業就業人口のうち生産年齢人口率-0.080.85
60歳未満男子農業専従者率0.290.73
農業従事者のうちの基幹的農業従事者率0.82-0.37
兼業従事者率-0.890.20

参考までに第1主成分の各値を二乗して合計してみました。

python

1t1 = np.array([0.61,0.33,0.83,-0.51,0.78,-0.08,0.29,0.82,-0.89]) 2print(sum(t1**2))
3.5934000000000004

値が1になりません。。。

この辺りからこんがらがってきました。
参考図書やソフトウェアによって主成分負荷量は異なってくるのか。
そしたら一体どれが正しいのか。

そこで、Rでも試してみました。
14-1.csv は先ほどの表から集落番号のみ削ったcsvです。

R

1> data = read.csv('14-1.csv') 2> pca = prcomp(data, scale=T) 3> pca$rotation[,1:2]
PC1 PC2 農家数の増減率 -0.32022098 0.03432674 農家人口増減率 -0.17526318 0.24398192 農業就業人口率 -0.44142820 0.19710407 農業従事者率 0.26724962 0.40110345 男子農業就業人口率 -0.41161307 0.21355265 農業就業人口のうち生産年齢人口率 0.04087309 0.59333011 X60歳未満男子農業専従者率 -0.15337729 0.50718952 農業従事者のうちの基幹的農業従事者率 -0.43172740 -0.25672953 兼業従事者率 0.46845603 0.13698137

この値は、固有ベクトルになるとRで主成分分析を説明してあるサイトにかかれていました。
また、この固有ベクトルから主成分負荷量を求めるには、固有値の正の平方根を掛け合わせれば良いとも。

R

1> t(t(pca$rotation)*pca$sdev)[,1:2]
PC1 PC2 農家数の増減率 -0.60524876 0.04945746 農家人口増減率 -0.33126443 0.35152552 農業就業人口率 -0.83434219 0.28398460 農業従事者率 0.50512775 0.57790386 男子農業就業人口率 -0.77798869 0.30768347 農業就業人口のうち生産年齢人口率 0.07725411 0.85486117 X60歳未満男子農業専従者率 -0.28989798 0.73075109 農業従事者のうちの基幹的農業従事者率 -0.81600673 -0.36989208 兼業従事者率 0.88542741 0.19736072

これによって得た値は、参考図書に掲載されているエクセル統計2010で算出した主計分負荷量とほぼ同じ値になりました。
(符号は違ったりしますが)

というわけで、pythonのstatsmodelsで同じことをやってみょうとしたのですが、

python

1import pandas as pd 2from statsmodels.multivariate.pca import PCA 3 4df = pd.read_excel('14-1.xlsx') 5df = df.set_index("集落番号") 6 7ret = PCA(df, ncomp=2, standardize=True, normalize=False) 8 9display(ret.coeff)

出力結果

|農家数の増減率|農家人口増減率|農業就業人口率|農業従事者率|男子農業就業人口率|農業就業人口のうち生産年齢人口率|60歳未満男子農業専従者率|農業従事者のうちの基幹的農業従事者率|兼業従事者率|
|------------|--|--|-|-|-|-|
|comp_0|-0.320221|-0.175263|-0.441428|0.267250|-0.411613|0.040873|-0.153377|-0.431727|0.468456|
|comp_1|0.034327|0.243982|0.197104|0.401103|0.213553|0.593330|0.507190|-0.256730|0.136981|

PCAのstandarizeをTrueに変えて、固有ベクトルの値を同じにすることができたのですが、
そのあとの固有値の正の平方根を掛け合わせることができません。(わかりません)

このように、参考図書によって違ってきたりするので、何が正しいことなのかよく分からなくなってしまいました。

どうかよろしくお願いします。

magichan👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まず、固有ベクトルは理屈の上では長さがいくつであってもいいのです。固有ベクトルですから。

実際は長さ不定、だと不便だし、数値的に計算するときも解が求まらなかったりします。なので、ノルムが1になるようにする、ということはよくやります。

ここでいうノルムは二乗和の平方根ですが、結果的に1になるように正規化されたのであればただの二乗和を計算しても1になります。

また、主成分負荷量は各変数と主成分の相関係数で、すべての変数に対して計算してノルムが1になる保証はどこにもありません。そう書いてあったなら本の間違いです(とはいえ、この説明もよく見るので、もしかしたらなにか根拠があってそう言っているのかもしれません。ただいずれにせよ、そう理解することはおすすめしません)。

計算方法については、こちらの10ページなどがわかりやすいかと思います。固有ベクトルに対応する固有値をかけるというのは、入力の標準化をした場合に使える便法です。

http://manabukano.brilliant-future.net/document/text-PCA.pdf

なお、主成分負荷量は知りたければ出しておいても良いんじゃないかな程度であって、固有ベクトルだけで解釈してもそんなに困ることはないと思います。状況によりけりですが……

sklearnでやる場合

素直に上の方法で計算可能です。

python

1import numpy as np 2from sklearn.decomposition import PCA as PCA 3from sklearn.preprocessing import StandardScaler 4 5data = np.array([ 6 [71,34,58,41,69,64,16,59,57,46,23,39,46,52,39,23,37,52,63,39], 7 [64,48,59,51,56,65,45,59,54,54,49,48,55,56,53,43,45,51,56,49], 8 [83,67,78,70,74,82,63,78,84,71,64,71,68,82,78,63,67,74,79,73], 9 [100,57,87,60,81,100,7,59,73,43,33,29,42,67,52,35,39,65,91,64], 10 [71,68,66,72,66,71,59,62,72,62,70,66,61,60,72,59,70,69,70,60] 11]) 12 13pca = PCA(n_components=1, svd_solver="full") 14X = pca.fit_transform(StandardScaler().fit_transform(data.T)) 15R = [] 16for row in data: 17 R.append(np.corrcoef(X.ravel(), row)[0,1]) 18print(np.array(R)) 19print(pca.components_[0]*np.sqrt(pca.explained_variance_[0])) 20""" => 21[-0.94621924 -0.91293882 -0.91759568 -0.94095263 -0.48408647] 22[-0.97080045 -0.93665547 -0.94143331 -0.96539702 -0.49666224] 23"""

少しずれますが、原因は究明していません(自由度の調整かなにかが怪しいような気がする。ただの浮動小数点数の誤差かもしれないけど)。

statsmodelsでやる場合

eigenvalsで取れるかなとも思ったけど、なんだか信じがたい数字が出たので保留。

投稿2019/06/22 05:53

hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

waku_nagoya

2019/06/22 09:16

ご解答ありがとうございます! 固有ベクトルさえあれば、主成分負荷量はどちらでも良い程度のものなのですね。 まずは教えていただいた内容を元にもう少し調べさせてください。
hayataka2049

2019/06/22 09:17

statsmodelsはあまり詳しくないんですが、整合性のある結果が出ない気がします。こっちでももう少し検討してみます。
waku_nagoya

2019/06/23 23:43

ありがとうございます。まずは、この手の話題を話せる人が身近にいないため、ご相談できて嬉しいです。 いただいたsklearnのソースを元に自分なりに落とし込んでみました。 sklearnだとcomponents_によって固有ベクトルとexplained_variance_で固有値が取得できるので、それを掛け合わせると求められるというわけですね。 私も調べていた時にこの方法はちらっと試してみたことがありました。 近い値はでるのですが、若干ずれるのでなんでだろうと思って、そのままにしておりました。 hayataka2049さんの相関係数の方法は、参考書の値とぴったり一致しました。 あと気になるのは、skleanだと機械学習からのアプローチになりますが、統計学からだと、statsmodelsやscipi.statsあたりから算出するといいのかなと思っていました。 とはいっても、両方とも、多変量解析になってくるとどうしても機能的に足りない部分がでてくるので、この辺りは別の方法に頼るしかないのか、それとも計算式を理解して、関数を作るしかないのかと悩んでいたりもしました。 statsmodelsのeigenvalsなど、確かに本当に合っているのか分からないような値、固有ベクトルがそのままでているのではないかという点もあって、どこまで使えるのかが怪しいです。 ソースは公開されているのですが、何分、計算式の方の知識が足りなくて解読できずにいました。。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問