1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

探索的因子分析(EFA)から確認的因子分析(CFA)へ:Pythonとsemopyで実践

Posted at

user:

semopyで潜在変数を扱う方法を教えてください。

assistant:

semopy で潜在変数(latent variable)を扱うには、モデル記述(model specification)に 測定モデル(measurement model) を含める必要があります。これは、「観測変数(指標変数)」が「潜在変数」をどのように測定しているかを記述する部分です。


🔶 1. 基本的な構文:潜在変数の記述

semopy では、=~ 演算子を使って潜在変数を定義します:

潜在変数名 =~ 指標変数1 + 指標変数2 + ...

例えば:

# 潜在変数F1は x1, x2, x3 によって測定される
F1 =~ x1 + x2 + x3

また、潜在変数間や観測変数との回帰関係も次のように書きます:

# 潜在変数F2はF1に影響を受ける
F2 ~ F1

# 観測変数yはF2とF1に影響を受ける
y ~ F1 + F2

🔶 2. 実装例:潜在変数を含むモデル

🔹ステップ1:必要なパッケージをインポート

import pandas as pd
from semopy import Model

🔹ステップ2:モデル記述(measurement + structural)

model_desc = """
# 潜在変数の定義(測定モデル)
F1 =~ x1 + x2 + x3
F2 =~ x4 + x5 + x6

# 潜在変数間の因果関係(構造モデル)
F2 ~ F1
"""

🔹ステップ3:データの準備

例として、ダミーデータを用意します:

import numpy as np

np.random.seed(42)
n = 200
x1 = np.random.normal(size=n)
x2 = x1 + np.random.normal(size=n)
x3 = x1 + np.random.normal(size=n)
x4 = x1 + np.random.normal(size=n)
x5 = x4 + np.random.normal(size=n)
x6 = x4 + np.random.normal(size=n)

data = pd.DataFrame({'x1': x1, 'x2': x2, 'x3': x3,
                     'x4': x4, 'x5': x5, 'x6': x6})

🔹ステップ4:モデルの作成とフィッティング

model = Model(model_desc)
model.fit(data)

🔹ステップ5:結果の確認

from semopy import inspect

# パラメータ推定結果
estimates = inspect(model)
print(estimates)

# 適合度指標
print(model.calc_stats())

🔶 3. 補足:識別のための制約

潜在変数モデルでは、識別性のために 各潜在変数につき1つの係数を固定(通常は1)する必要があります。semopy は自動でこれを処理してくれますが、以下のように明示的に指定することもできます:

F1 =~ 1*x1 + x2 + x3

🔶 4. 可視化(パス図の描画)

from semopy import plot_model
import matplotlib.pyplot as plt

fig = plot_model(model, plot_covs=True)
plt.show()

✅ まとめ

要素 semopyでの記法
潜在変数の定義 L1 =~ x1 + x2 + x3
潜在変数の回帰 L2 ~ L1
潜在変数 ↔ 観測変数 y ~ L1 + L2
モデルの構築 model = Model(model_desc)
推定 model.fit(data)

必要であれば、複数因子モデル(CFA)、交差負荷(cross-loading)、モデル制約、分散共分散の指定方法なども解説できます。ご希望があればお知らせください!

user:

潜在変数の個数について、ルールや経験則などはありますか?

assistant:

潜在変数(latent variables)の個数に関する明確な絶対的ルールはありませんが、識別性・解釈性・データ特性の観点から、以下のような理論的原則・経験則・実践的な注意点があります。


✅ 1. 識別可能性(Identifiability)に関するルール

SEMでは**モデルが識別可能(identifiable)**でないと、パラメータを一意に推定できません。識別性には以下のようなルールがあります。

🔹 潜在変数ごとに3つ以上の指標変数があるのが望ましい

  • 経験則: 潜在変数あたり最低 3つ以上の観測変数(指標変数)を割り当てると、モデルが識別されやすい。
  • 理由:測定方程式の数が、未知パラメータの数を上回る必要があるため。
潜在変数の数 望ましい指標変数の数(目安)
1 3 以上
2 各3個以上
3 各3個以上

※ ただし、2つでも識別可能な場合はありますが、理論的に根拠が弱くなる(推定が不安定になりがち)。


✅ 2. 自由度(degrees of freedom)とモデル識別性の関係

  • 自由度(df) = 観測可能な情報量 − 推定するパラメータ数
  • 自由度が 0以上 でなければモデルは**過識別(just-identified)または過少識別(under-identified)**になります。

🔹 モデルの自由度計算(ざっくり)

df = 観測変数の共分散数 − 推定パラメータ数
  • 観測変数が p 個あると、共分散の数は p(p+1)/2
  • 潜在変数が増えるとパラメータも増えるため、十分な観測変数が必要

✅ 3. サンプルサイズとのバランス

🔹 経験則:パラメータ数に対して 10倍以上のサンプル数

  • 推定するパラメータが k 個 → データ数(n)は 10k 程度あると安定
  • 特に潜在変数モデルではサンプルサイズが小さいと収束しないことも多い

✅ 4. 解釈性と理論的妥当性

🔹 潜在変数の数は理論仮説に基づいて設定すべき

  • 単に因子数が多いモデルは適合度が良くなりがち(過剰適合)
  • 「このデータには何個の因子が妥当か?」は、探索的因子分析(EFA)などで判断

✅ 5. 実践的なアプローチ

アプローチ 内容
CFA(確認的因子分析) 理論に基づいて因子数を決める(例:F1, F2)
EFA(探索的因子分析) データから潜在因子の数を探索(基準:固有値 > 1, Screeプロット)
モデル比較(AIC/BIC) 潜在変数の数を変えてモデル比較して選ぶ

✅ 経験則まとめ

項目 経験則・ガイドライン
潜在変数あたりの指標数 最低3つ以上が望ましい
潜在変数の数 理論またはEFAの結果に基づく
モデルの自由度 0以上(正の自由度が望ましい)
パラメータ数とサンプル数 サンプル数はパラメータ数の10倍以上
モデル選択 理論 + 統計指標(CFI, RMSEA, AICなど)で判断

ご要望に応じて提供可能な追加情報

  • 潜在変数の数をEFAで探索するコード(Python)
  • 潜在変数ごとの信頼性(Cronbach’s α)のチェック方法
  • semopyによるモデル選択のAIC/BIC比較コード例

ご希望があれば、お知らせください。

user:

潜在変数の数をEFAで探索するコード(Python)を書いてください。

assistant:

Pythonで探索的因子分析(EFA)を用いて潜在変数の数を探索するコードを以下に示します。
主に以下の2つの目的を果たします:

  1. 潜在因子の「妥当な個数」を固有値やスクリープロットから判断
  2. 各変数と因子の関連(factor loadings)を可視化

✅ 使うライブラリ

  • factor_analyzer:EFAやKMO検定、Bartlett検定を実行可能
  • matplotlib / seaborn:可視化

まずライブラリをインストールしていない場合:

pip install factor_analyzer matplotlib seaborn

✅ コード:潜在因子数の探索(EFA)

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from factor_analyzer import FactorAnalyzer, calculate_kmo, calculate_bartlett_sphericity

# --------------------------
# 1. データの読み込み・準備
# --------------------------

# 仮のデータ:10変数、300サンプル
np.random.seed(42)
df = pd.DataFrame(np.random.normal(size=(300, 10)),
                  columns=[f'X{i}' for i in range(1, 11)])

# --------------------------
# 2. KMO検定とBartlett検定(EFAの適性チェック)
# --------------------------
kmo_all, kmo_model = calculate_kmo(df)
chi_square_value, p_value = calculate_bartlett_sphericity(df)

print(f"KMO: {kmo_model:.3f}(0.6以上なら適性あり)")
print(f"Bartlett’s test p-value: {p_value:.5f}(0.05未満なら因子分析に適)")

# --------------------------
# 3. 固有値の計算と Scree プロット
# --------------------------
fa = FactorAnalyzer(rotation=None)
fa.fit(df)

ev, v = fa.get_eigenvalues()

# Scree plot
plt.figure(figsize=(8, 4))
plt.plot(range(1, len(ev)+1), ev, 'o-', label='固有値')
plt.axhline(1, color='red', linestyle='--', label='固有値=1のカットオフ')
plt.title('スクリープロット(Scree Plot)')
plt.xlabel('因子数')
plt.ylabel('固有値')
plt.xticks(range(1, len(ev)+1))
plt.grid(True)
plt.legend()
plt.show()

# --------------------------
# 4. 因子数を決めて再実行(ここでは因子3つと仮定)
# --------------------------
n_factors = 3
fa = FactorAnalyzer(n_factors=n_factors, rotation='varimax')
fa.fit(df)

# 因子負荷量(Factor Loadings)
loadings = pd.DataFrame(fa.loadings_,
                        index=df.columns,
                        columns=[f'Factor{i+1}' for i in range(n_factors)])
print("\n因子負荷量(Factor Loadings):")
print(loadings.round(2))

# Heatmap で視覚化
plt.figure(figsize=(8, 6))
sns.heatmap(loadings, annot=True, cmap='coolwarm', center=0)
plt.title("因子負荷量のヒートマップ")
plt.show()

✅ 出力される情報

出力項目 説明
KMO値 0.6以上ならEFAに適している
Bartlett検定のp値 0.05未満なら因子分析に適
スクリープロット 因子数の候補を視覚的に確認できる
因子負荷量 どの変数がどの因子と強く関係しているかを表す

✅ よくある判断基準

  • 固有値 > 1 の因子数を採用(Kaiser基準)
  • **スクリープロットの肘(elbow)**の位置で因子数を決定
  • 因子負荷量が0.3未満の変数は因子とあまり関係しない

ご希望であれば、このEFAの結果を基にして semopy のモデル記述に自動変換するコードも提供可能です。必要があればお知らせください。

user:

ありがとうございます。でもちょっと待ってください。「因子数を決めて再実行(ここでは因子3つと仮定)」とありますが、因子の数を決めるのは、スクリープロットを使って、固有値=1のカットオフを切る直前の因子の数を見る、という理解で正しいでしょうか?(もしそうだとすると今回は因子数は5のようです)

assistant:

はい、ご理解はほぼ正確です。詳しく説明すると、以下のような判断基準になります。


✅ 因子数を決める方法の原則

Kaiser基準(固有値 > 1)

  • 各因子の**固有値(eigenvalue)**が 1を超えるかどうかを見ます。
  • 固有値が1未満の因子は、その因子が説明できる分散が「平均的な1変数の分散未満」であるため、有用とは見なされないことが多い。
  • したがって、「固有値 > 1」な因子の個数 = 採用する因子数の候補になります。

👉 今回のスクリープロットで「固有値 > 1」の因子が 5個あったのなら、因子数は5が妥当な候補です。


スクリープロットの「肘(elbow)」の位置

  • 因子の数が増えるにつれて固有値が急激に減少し、ある点から**減少が緩やかになる部分(=「肘」)**があります。
  • この肘の前の因子数が、情報量が豊かで本質的な因子であると解釈します。
  • これは視覚的・主観的な判断が入るため、Kaiser基準と併用します。

✅ 判断例:どちらを優先するべきか?

状況 取るべき判断
固有値 > 1 が 5個 & 肘も5個目付近 因子数 = 5でOK
固有値 > 1 が10個 だが肘は3個目付近 因子数 = 3に絞ってもよい(過剰適合を避ける)
肘が不明瞭、固有値もなだらかに減少 → 両基準を参考に モデル比較で選択(AIC/BIC)

✅ あなたのケース(5因子が該当)なら…

はい、おっしゃる通り:

「固有値=1のカットオフを切る直前の因子の数(=固有値>1の個数)」を見る → 今回は5個 → 因子数=5

この解釈で問題ありません。


✅ 次のステップ

上記を踏まえて、以下のようにコード中の因子数を 5 に変更してください:

n_factors = 5  # ← スクリープロットで固有値>1の因子数に変更
fa = FactorAnalyzer(n_factors=n_factors, rotation='varimax')
fa.fit(df)

✅ 補足:因子数の判断に使える追加指標

  • 並列分析(Parallel Analysis):実データとランダムデータの固有値を比較して因子数を決める(より堅牢)
  • モデル適合度(BIC/AIC、RMSEA):複数の因子数でEFAを実行し、比較して選ぶ

並列分析や自動選択をPythonでやるコードも必要であれば提供します。お気軽にどうぞ。

こちらこそ、丁寧にご確認いただきありがとうございます。
以下に、潜在変数(因子)の数を AIC/BIC で比較して最適な数を探索する Python コードを提示します。


✅ 概要

  • factor_analyzer を使って、因子数を 1~max_factors の範囲で変化させて探索。
  • 各因子数に対して 対数尤度(log-likelihood) を計算し、そこから AIC / BIC を求めて比較。
  • 最小の AIC / BIC を与える因子数を選択。

✅ コード:因子数を AIC / BIC で探索

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from factor_analyzer import FactorAnalyzer
from scipy.stats import chi2

# 仮データ:300サンプル×10変数
np.random.seed(42)
df = pd.DataFrame(np.random.normal(size=(300, 10)),
                  columns=[f"X{i}" for i in range(1, 11)])

# 対象データ
X = df.values
n_obs, n_vars = X.shape
max_factors = 8  # 探索する最大因子数

results = []

for n_factors in range(1, max_factors + 1):
    fa = FactorAnalyzer(n_factors=n_factors, rotation=None, method='ml')  # 最尤法
    fa.fit(X)
    
    # モデル情報
    dof = fa.get_dof()
    ll = fa.get_loglike()
    
    # パラメータ数:因子負荷量 + 固有分散
    n_params = n_factors * n_vars - n_factors * (n_factors - 1) // 2 + n_vars

    # AIC / BIC 計算
    aic = -2 * ll + 2 * n_params
    bic = -2 * ll + np.log(n_obs) * n_params

    results.append({
        "n_factors": n_factors,
        "loglike": ll,
        "aic": aic,
        "bic": bic,
        "dof": dof
    })

# DataFrame 化
result_df = pd.DataFrame(results)

# 最適因子数の表示
best_aic = result_df.loc[result_df['aic'].idxmin()]
best_bic = result_df.loc[result_df['bic'].idxmin()]

print("最小AIC:", best_aic)
print("最小BIC:", best_bic)

# -----------------------------
# グラフで可視化
# -----------------------------
plt.figure(figsize=(10, 5))
plt.plot(result_df["n_factors"], result_df["aic"], label="AIC", marker="o")
plt.plot(result_df["n_factors"], result_df["bic"], label="BIC", marker="s")
plt.xlabel("因子数")
plt.ylabel("情報量基準(小さいほど良い)")
plt.title("因子数ごとの AIC / BIC")
plt.xticks(range(1, max_factors + 1))
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

✅ 出力されるもの

  • result_df: 各因子数に対する log-likelihood, AIC, BIC, 自由度
  • 最小の AIC / BIC を与える因子数(通常これが「妥当な潜在因子の数」とされます)
  • AIC / BIC を比較するグラフ

✅ 解釈のポイント

指標 解釈
AIC モデルの予測性能を重視。過剰適合のリスクあり。小さいほど良い。
BIC モデルのシンプルさを重視。より厳格な基準。小さいほど良い。
結論の例 AIC: 因子数 = 5、BIC: 因子数 = 3 → BICを優先して3因子にする判断もあり

✅ 備考

  • FactorAnalyzermethod='ml' を使うと対数尤度が計算できるため、AIC/BIC が使えます。
  • rotation=None にしないと正確な尤度にならない場合があるので注意。

ご希望があれば、この結果を semopy に自動で変換する補助コードも提供します!

user:

ありがとうございます。次のエラーを解決してください。

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-505159930> in <cell line: 0>()
     22 
     23     # モデル情報
---> 24     dof = fa.get_dof()
     25     ll = fa.get_loglike()
     26 

AttributeError: 'FactorAnalyzer' object has no attribute 'get_dof'

assistant:

ありがとうございます。AttributeError: 'FactorAnalyzer' object has no attribute 'get_dof' というエラーは、factor_analyzer パッケージの FactorAnalyzer クラスには get_dof() メソッドが存在しないために発生します。


✅ 解決方法

方法1:get_dof() を使わずに AIC/BIC を計算する

幸い、AIC/BIC を計算するためには「対数尤度(loglike)」と「パラメータ数(k)」だけあれば十分です。get_dof() は不要なので、コードから削除して問題ありません。


✅ 修正済みコード(エラー回避版)

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from factor_analyzer import FactorAnalyzer

# 仮データ:300サンプル×10変数
np.random.seed(42)
df = pd.DataFrame(np.random.normal(size=(300, 10)),
                  columns=[f"X{i}" for i in range(1, 11)])

# 対象データ
X = df.values
n_obs, n_vars = X.shape
max_factors = 8  # 探索する最大因子数

results = []

for n_factors in range(1, max_factors + 1):
    fa = FactorAnalyzer(n_factors=n_factors, rotation=None, method='ml')  # 最尤法
    fa.fit(X)
    
    # 対数尤度の取得
    ll = fa.loglike_

    # パラメータ数(参考値)
    n_params = n_factors * n_vars - n_factors * (n_factors - 1) // 2 + n_vars

    # AIC / BIC 計算
    aic = -2 * ll + 2 * n_params
    bic = -2 * ll + np.log(n_obs) * n_params

    results.append({
        "n_factors": n_factors,
        "loglike": ll,
        "aic": aic,
        "bic": bic
    })

# 結果の表示
result_df = pd.DataFrame(results)

best_aic = result_df.loc[result_df['aic'].idxmin()]
best_bic = result_df.loc[result_df['bic'].idxmin()]

print("最小AICの因子数:\n", best_aic)
print("最小BICの因子数:\n", best_bic)

# グラフ化
plt.figure(figsize=(10, 5))
plt.plot(result_df["n_factors"], result_df["aic"], label="AIC", marker="o")
plt.plot(result_df["n_factors"], result_df["bic"], label="BIC", marker="s")
plt.xlabel("因子数")
plt.ylabel("情報量基準(小さいほど良い)")
plt.title("因子数ごとの AIC / BIC")
plt.xticks(range(1, max_factors + 1))
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

✅ 補足

  • fa.loglike_factor_analyzer の最新バージョンで利用可能な属性です。もし loglike_ すら存在しない場合は pip install -U factor_analyzer でアップデートしてください。

✅ まとめ

  • get_dof() は存在しないため、削除してください。
  • fa.loglike_ を使って AIC / BIC を手計算することで問題なく探索できます。

必要であれば、この結果をもとに semopy のモデル式を自動生成するコードもお手伝いできます。どうしますか?

user:

この結果をもとに semopy のモデル式を自動生成するコードを書いてください。

assistant:

了解しました!
以下では、EFA(探索的因子分析)から得られた因子負荷行列をもとに、semopy 用のモデル式を自動生成するコードを示します。


✅ 目的

  • FactorAnalyzer で得られた因子負荷行列 loadings_ を使って、
  • 各因子を潜在変数(latent variable)とし、
  • semopy で使える モデル式(measurement model) を自動で作成します。

✅ 前提:EFA 実行コード(因子数は選択済み)

from factor_analyzer import FactorAnalyzer
import pandas as pd
import numpy as np

# データ読み込み
df = pd.read_csv("your_data.csv")  # または仮の df を使用
X = df.values
n_obs, n_vars = X.shape

# 因子数はEFA結果などから決定(例:3因子)
n_factors = 3

# 因子分析の実行
fa = FactorAnalyzer(n_factors=n_factors, rotation='varimax', method='ml')
fa.fit(X)

# 因子負荷行列の取得
loadings = pd.DataFrame(fa.loadings_, index=df.columns,
                        columns=[f"F{i+1}" for i in range(n_factors)])

✅ ステップ1:寄与が大きい観測変数のみを各因子に割り当てる

# 絶対値が閾値以上の観測変数を各因子に割り当て
threshold = 0.4  # 負荷量のしきい値(調整可)

measurement_dict = {f"F{i+1}": [] for i in range(n_factors)}

for var in loadings.index:
    # 一番強い因子だけに割り当てる(単純構造仮定)
    factor_idx = np.argmax(np.abs(loadings.loc[var].values))
    if abs(loadings.iloc[var, factor_idx]) >= threshold:
        factor_name = f"F{factor_idx + 1}"
        measurement_dict[factor_name].append(var)

✅ ステップ2:semopy 用のモデル式を生成

model_lines = []

for latent, indicators in measurement_dict.items():
    if indicators:
        line = f"{latent} =~ " + " + ".join(indicators)
        model_lines.append(line)

model_desc = "\n".join(model_lines)
print("生成された semopy モデル式:\n")
print(model_desc)

✅ 出力例(3因子モデル)

F1 =~ X1 + X2 + X5
F2 =~ X3 + X4 + X6
F3 =~ X7 + X8 + X9

これを semopy.Model(model_desc) に渡せばそのまま使えます。


✅ 最終的な使い方例(semopy)

from semopy import Model

model = Model(model_desc)
model.fit(df)
estimates = model.inspect()

✅ 注意点とアドバイス

  • 潜在変数どうしの構造(回帰関係)や共分散は明示的に指定していないため、測定モデル(CFA) に相当します。
  • 潜在変数間の関係もモデル化したい場合は、さらに手動で追記する必要があります(例:F1 ~ F2)。
  • threshold=0.4 は経験則ですが、0.3〜0.5 程度で調整して構造が安定するように工夫してください。

必要であれば、モデル式を .lavaan 形式で保存したり、グラフで測定モデルを図示するコードもご提供できます。希望があればお知らせください。

user:

ありがとうございます。ところで semopy で時系列を扱うことはできますか?

assistant:

いい質問です。結論から言うと:


semopy は時系列モデルを直接サポートしていません。


semopy は、**構造方程式モデリング(SEM)**のライブラリであり、基本的には クロスセクショナル(非時系列)データ を対象としています。


🔍 では、時系列を SEM 的に扱うには?

1. 手動でラグを作る(X_t, X_{t-1}

時系列データにラグを付けて、SEM に組み込むことはできます。
例えば:

Y_t ~ Y_t_1 + X_t_1
Y_t =~ y1_t + y2_t + y3_t
X_t =~ x1_t + x2_t

のように、ラグ付きの変数を明示的に作成すれば semopy でも扱えます
ただし、これは**「擬似的な時系列 SEM」**です。


2. 時系列に対応した SEM モデルを使うなら:

ライブラリ 説明
OpenMx(R) 時系列 SEM(状態空間表現含む)を本格的に扱える。
dynSEM(R) 動的 SEM に特化した R パッケージ。
lavaan + 自前ラグ処理(R) ラグ構造を含めたSEMモデルを構築可。
pymc3 / pymc(Python) 時系列×ベイズSEMの柔軟な構築が可能。
tensorflow_probability 状態空間モデルなどを組み合わせて独自に構築可能。

🔧 Python でどうしてもやりたい場合は?

✅ 方法1:ラグ付き SEM を semopy で構築

# データのラグを作る
df['X1_t-1'] = df['X1'].shift(1)
df['Y_t-1'] = df['Y'].shift(1)

# 欠損行を除く
df.dropna(inplace=True)

# モデル記述(例)
desc = """
Y_t ~ Y_t-1 + X1_t-1
Y_t =~ y1 + y2 + y3
X1_t =~ x1 + x2
"""

✅ 方法2:ベイズ SEM(PyMC)を使う

PyMC によって、時系列構造を SEM 的に柔軟に定義可能です。
例:状態空間モデルに潜在変数を組み込む形式など。


✅ 結論まとめ

項目 可否 説明
semopy で時系列を直接扱う 時系列構造は組み込みで非対応。
ラグ変数を手動で作る 疑似的に可能。
本格的な時系列 SEM(状態空間など) 🔄(R/ベイズ) OpenMx, dynSEM, PyMC, TFP 等が必要。

ご希望があれば、「semopy でラグ付き時系列 SEM を構築するテンプレートコード」や、
PyMC による動的 SEM(ベイズ時系列SEM)」のサンプルも提供できます。どうしますか?

user:

ありがとうございます。今日はこの辺で大丈夫です。ここまでの議論をブログにまとめたいのですが、タイトル案をいくつか考えていただけますか?

assistant:

こちらこそ、じっくり議論いただきありがとうございました!
以下、今日の内容(潜在変数、EFAによる因子数探索、semopy での応用、時系列への拡張可否など)を反映したブログタイトル案をいくつかご提案します。


💡 ブログタイトル案


📌 潜在変数・因子数探索に焦点を当てたもの

  • 「Python × SEM × 潜在変数:EFAで因子数を決め、semopy に落とし込むまで」
  • 「因子数はこう決める!スクリープロット・AIC/BICでEFAからSEMへ」
  • 「探索的因子分析(EFA)から確認的因子分析(CFA)へ:Pythonとsemopyで実践」

📌 時系列との関連や限界も含めたもの

  • 「semopyで潜在変数モデル:時系列はどう扱う?Pythonで考える応用例」
  • 「PythonのSEMライブラリで時系列と潜在変数を攻める:EFA・CFA・限界と工夫」

📌 実践ノウハウ的な切り口

  • 「因子数の決め方からsemopy実装まで:Pythonで始める潜在変数モデリング」
  • 「EFA・AIC・BIC・スクリープロット…SEMの因子数はこう決める!」

もしテーマや読者層(初心者向け/中級者向け/研究者向けなど)が決まっていれば、それに合わせたタイトルも練り直せますので、ぜひお知らせください!

また、ブログ本文の構成案や書き出しの例も必要であればお手伝いします。お気軽にどうぞ!

user:

「探索的因子分析(EFA)から確認的因子分析(CFA)へ:Pythonとsemopyで実践」で行きたいと思います。最後に、ここまでの詳しいまとめを書いてください。

assistant:

素晴らしいタイトルですね!
それでは 「探索的因子分析(EFA)から確認的因子分析(CFA)へ:Pythonとsemopyで実践」 の内容にふさわしい、今日の議論の詳細なまとめをお書きします。


探索的因子分析(EFA)から確認的因子分析(CFA)へ:Pythonとsemopyで実践

🌟 はじめに

潜在変数モデル(SEM)の実践では、まず 探索的因子分析(EFA) で因子数や変数と因子の関連を見極め、次に 確認的因子分析(CFA) で理論に基づく構造を評価する流れが一般的です。本記事では、Python でこの流れを実装する手順と注意点を整理しました。


🔹 EFAで因子数を探索する

✅ 方法

  • factor_analyzer ライブラリ を用いて探索的因子分析(EFA)を実施。
  • スクリープロット による視覚的判断、および
  • 固有値 > 1 の基準(Kaiser基準) による因子数候補の決定。

✅ 実装例

from factor_analyzer import FactorAnalyzer
import matplotlib.pyplot as plt

fa = FactorAnalyzer(rotation=None)
fa.fit(df)

ev, _ = fa.get_eigenvalues()

# スクリープロット
plt.plot(range(1, len(ev)+1), ev, 'o-')
plt.axhline(1, color='red', linestyle='--')
plt.xlabel('因子数')
plt.ylabel('固有値')
plt.show()

✅ 補足

  • 因子数の候補は「固有値が1を超える数」または「スクリープロットの肘の位置」で判断。
  • 並列分析や AIC/BIC に基づく選択も有用。

🔹 AIC / BIC に基づく因子数の最適化

✅ 実装のポイント

  • FactorAnalyzer(method='ml') で最尤法を使い、loglike_ 属性で対数尤度を取得。
  • AIC / BIC を手計算で求め、最小の因子数を選ぶ。

✅ 注意点

  • get_dof() のようなメソッドは存在せず、loglike_ とパラメータ数の計算のみで十分。
  • パラメータ数は「負荷量 + 固有分散」を基準にカウント。

🔹 semopy モデル式の自動生成

✅ 方法

  • EFA の因子負荷行列(fa.loadings_)から、高い負荷量の変数を各因子に割り当て。

  • 生成例:

    F1 =~ X1 + X2 + X5
    F2 =~ X3 + X4
    F3 =~ X6 + X7
    
  • これを semopy のモデル記述として利用可能。

✅ 実装例(抜粋)

model_lines = []
for latent, indicators in measurement_dict.items():
    if indicators:
        line = f"{latent} =~ " + " + ".join(indicators)
        model_lines.append(line)

model_desc = "\n".join(model_lines)

🔹 semopy の適用と限界

✅ CFA の実行

生成したモデル記述を semopy.Model に渡してフィッティング。

from semopy import Model
model = Model(model_desc)
model.fit(df)

✅ 時系列データへの適用

  • semopy は時系列専用の機能は持たない
  • ラグ変数を自分で作ることで、擬似的に時系列構造を SEM に組み込むことは可能
  • 本格的な時系列 SEM が必要なら PyMC や R の OpenMx などが推奨

🌟 まとめのまとめ

1️⃣ EFAで因子数を決める際はスクリープロットや固有値基準、AIC/BICを併用
2️⃣ semopyではEFA結果をCFAモデル記述に自動変換できる
3️⃣ 時系列構造は semopy では手動でラグ構造を組み込む必要がある
4️⃣ 本格的な時系列 SEM は他ライブラリ(PyMC、OpenMx等)が必要


✉️ 最後に

今回の実装例は、探索的な分析から確認的なモデリングへの橋渡しに役立つものです。
さらに深掘りとして、潜在変数間の構造パスの指定や、時系列 SEM のベイズ的実装なども次のテーマとしておすすめです。

必要なら、コードの全文まとめや図示例、R/Pythonでの比較記事の素材もお作りしますので、お気軽にリクエストください!

user:

ありがとうございました!

assistant:

こちらこそ、素晴らしいご質問とやりとりをありがとうございました!🌷
今日の議論がブログや分析に役立つことを願っています。

また何かあれば、いつでも気軽に声をかけてくださいね。
どうぞ素敵な執筆・分析時間をお過ごしください!📊✍😊

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?