はちみつブログ

趣味や生活の話を好きなタイミングで書いていきたいと思います。

バリマックス回転とプロマックス回転について

以前の因子分析関連では、主成分分析との関係を扱ったが、今回は回転へ行きたいと思う。

とはいえ、回転について、自分ならではで語ることあるか…というと、いろいろな他の方の解説で参考になるものも多く、自分ならではみたいな説明は難しいな、と正直感じた。

とりあえず、PythonとRで動かしつつ、有名かつ初心者がまず扱うならバリマックス回転とプロマックス回転くらいのはずなので、それらの簡単な紹介かな、と思っている。

まずは動かしてみる

PythonとRで、バリマックス回転とプロマックス回転を、実行してみて結果を比較してみようと思う。

Python

まずはバリマックス回転。

from factor_analyzer import FactorAnalyzer
import pandas as pd

# データの読み込み
df = pd.read_csv('../../01_factor-analysis/data/factor_analysis_test_data.csv', index_col=0)

# 因子分析を設定、因子数を2、バリマックス回転で
fa_varimax = FactorAnalyzer(n_factors=2, rotation="varimax")

# データフレーム df に適用
fa_varimax.fit(df)

# 因子負荷量を取得
fa_varimax.loadings_

結果は以下。

第1因子 第2因子
英語 0.154 0.580
国語 -0.072 0.852
算数 0.941 0.009
理科 0.908 -0.0005
社会 -0.110 0.808

次にプロマックス回転。ライブラリは共通なので、読み込みのコードは省略。DataFrameも同じものを利用。

# 因子分析を設定、因子数を2、プロマックス回転で
fa_promax = FactorAnalyzer(n_factors=2, rotation="promax")

# データフレーム df に適用
fa_promax.fit(df)

# 因子負荷量を取得
fa_promax.loadings_

結果は以下。

第1因子 第2因子
英語 0.149 0.578
国語 -0.080 0.853
算数 0.941 0.004
理科 0.908 -0.012
社会 -0.117 0.810

今回についてはデータを作った時にそもそも独立した因子で作ったからだと思うが、バリマックス回転もプロマックス回転も結果は似たような数値。

どちらにせよ、1つ目の因子が算数と理科に関する理系の因子で、2つ目の因子が国語、社会に関する文系の因子であることはわかる。元のデータとしては、ちょっとずつ関係するように作ったつもりだが、今回のデータがそうなのかもだが文系の因子に英語は影響しているようだ。

R

まずはバリマックス回転。

install.packages("psych")
library(psych)

# データの読み込み
dat <- read.csv("../../01_factor-analysis/data/factor_analysis_test_data.csv", row.names = 1, header = TRUE, stringsAsFactors = FALSE)

# 因子分析 因子数2、バリマックス回転
varimax_result <- fa(dat, nfactors = 2, rotate = "varimax")

# 結果の表示
print(varimax_result$loadings)

結果は以下。

第1因子 第2因子
英語 0.154 0.580
国語 0.852
算数 0.941
理科 0.908
社会 -0.110 0.808

次にプロマックス回転。ライブラリ・データは共通なので同じものを利用。

# 因子分析 因子数2、プロマックス回転
promax_result <- fa(dat, nfactors = 2, rotate = "promax")

# 結果の表示
print(promax_result$loadings)

結果は以下。

第1因子 第2因子
英語 0.149 0.578
国語 0.853
算数 0.941
理科 0.908
社会 -0.117 0.810

おそらく、Rの場合一定の値以下の因子については表示せず空欄なのだろう。なんとなくだが、表示のオプションがありそうな…理解していないのでわからないが笑

結果は、PythonとRで完全に一致として差し支えないのではないかと思う。(あとあと、Python側が同じ結果を目指していることも理解した。)

リマックス回転

リマックス回転によらずだが、回転で目指すのは因子の「単純」構造。単純構造とは何かというと、因子負荷量の絶対値が1(に近い値)か0(に近い値)にはっきり分かれること。

以前の結果のコピペにはなるが、回転無しの結果は以下の通りで、第1因子も第2因子も総合力ぽくなってしまい、結果の解釈が難しい。

第1因子 第2因子
英語 -0.213 0.561
国語 -0.556 0.650
算数 0.759 0.557
理科 0.738 0.530
社会 -0.561 0.592

特に第2因子が総合力。第1因子はまあ理系因子っぽいちゃあ理系因子っぽいのだが。これが強いと、どんどん文系科目の点数が下がり、それを第2因子でカバーみたいなイメージになってしまう。元のデータの作り方とは全然一致しない。

一方で、バリマックス回転した結果を再掲すると以下の通りで、第1因子が理系力、第2因子が文系力と解釈しやすいのではないかと思う。英語が若干文系っぽく見えているのは、全く意図していないが…笑

第1因子 第2因子
英語 0.154 0.580
国語 0.852
算数 0.941
理科 0.908
社会 -0.110 0.808

リマックス回転が提案された文献は H. F. Kaiser, “The Varimax Criterion for Analytic Rotation in Factor Analysis,” Psychometrika, vol. 23, no. 3, pp. 187–200, 1958. doi:10.1007/BF02289233 。1958年に提案された手法と考えるともうすぐ70年生きている方法なんだな。というかそれくらい昔に手計算でこれをやってたんだろうか…引用数は11588件(2025年9月現在Google Scholar)で思ったより少なく感じるが、もう手法が常識すぎて引用されないのかも。上記の論文ではバリマックス回転の提案ももちろんだが、単純構造についても提案したらしい。今度、細かくちゃんと読んでみたいと思う。Google Scholarで検索するといくつかオープンにアクセス可能なPDFがある。

で、バリマックス回転では単純構造を目指すために、因子負荷量の2乗の分散を最大化することを目指すようだ。元の因子負荷量は -1 から 1 の範囲でばらついていて、絶対値が 0 か 1 に近いものに分かれていない。そこで2乗することで、平均は真ん中としても0.5、この分散を最大化しようとすると絶対値が 0 に近いものか、 1 に近いものに分かれる、という狙いだろう。正確には「共通性」という数値で正規化した因子負荷量の2乗の分散を最大化する回転を探るようなのだが…まだ「共通性」という数値が語れるほど身についていないので、今後勉強していきたいと思う。

リマックス回転は直交回転なので、元々の初期解の因子の直交性は保たれる。イメージとしては決まった軸の交点についてロックしてクルクル回して2乗の分散が最大化するポイントを見つける動きだろう。実際には数値計算だが…

直交回転(と次の斜交回転)については、よく解説されていて、本当にいろいろな所でいろいろな方法で解説されているので、どれかはしっくりくるのではないかと思う。そのため、自分から新しい説明方法というのは思いついていない。自分はこの前に主成分分析をすごく考えていたせいもあるのか…全く直交に違和感がなく、しっくりきたというかどれも分からない説明には思わなかった。

プロマックス回転

次にプロマックス回転なのだが、今回例に使ったデータが因子的には恣意的に直交・独立しているために、ほぼバリマックス回転で因子が単純構造になって説明ができてしまっている。そのため…プロマックス回転の効果が分かりづらいが…斜交回転の最も有名な回転がプロマックス回転だ。

プロマックス回転が提案されたのは Hendrickson, Alan E., and Paul Owen White. "Promax: A quick method for rotation to oblique simple structure." British journal of statistical psychology 17.1 (1964): 65-70 。残念ながらGoogle Scholarで調べる限り、オープンアクセスなバージョンはなさそうだ。どれぐらいちゃんと読んでみるか悩ましいが、こういう状況が、被引用数が1415 (2025年9月現在Google Scholar)でかなり少なく感じる要因かもしれない。多くの方が計算方法を解説しているが、何かしらのRやPythonのライブラリ実装を元に解説しているのかも。まあ、実用上は使えれば問題ないと思うので。

動きとしては、まずバリマックス回転をする。さらにバリマックス回転の目的関数を何乗かして、その値を目指すように斜交回転するようだ。乗数は2〜4が多いようだ。今回利用したPythonfactor_analyzer の場合、 power という引数で指定ができ、2〜4で指定できるようだ。デフォルトは4とのことが、ドキュメントで確認できた。というか、ドキュメントをよく読むとこの回転周りはRの GPArotation を参考にしているとのこと。今回使ったライブラリなので、それはまあ結果が同じになるよな、というところ。

今回は計算用に作ったデータなので、理系力と文系力が独立した直交している因子なのだが、世の中の因子はそんなことはないだろう。例えば、学校教育ではいろいろな教科があり、記憶力や論理的思考力、計算力、文章構成力などいろいろな要素、まあつまり因子が計測・習熟できるよう設計されていると思う。ある程度は独立していそうなものをあげたつもりではあるが、計算力の根底には九九を覚えるなど、意外と記憶力も大事だったりするなど、完全に独立なものは世の中にはないような気もする。論理的思考力なんて、記憶力も計算力も、文章構成力も関係するだろう。となると、因子を直交したままとする直交回転の方が実は不自然で、斜交回転というものが出てきたというのも理解しやすい。発明されてからこちらも50年以上たっても大変よく使われているというところで、とても基本な方法なのだろう。

まとめ

いろいろ回転について語ってみたいと思ったものの、正直自分らしく語るほどの内容は…無かった笑 それだけ、世の中のいろいろな解説がわかりやすい、工夫されているのだなと思った。

少しでもという部分で原点の論文を紹介してみたものの、どちらかというと数値の結果として重要なのは、コンピュータで計算させる際の最適化手法だったりするのかもしれない。逆にいうと、数式としてはかなり本質をついているので、バリマックス回転・プロマックス回転は時代を超えて使われているんだろう。考えた人たちはすごいなぁ…

(追記)

今回の関連コードをGithubリポジトリに反映しました。

github.com

参考文献