📊

コレスポンデンス分析について

はじめに

はじめまして、株式会社D2C(以下D2C)で内定者アルバイトをしている正木です。
今回はマーケティングでよく用いられる、コレスポンデンス分析についての調査を行いました。
分析はPythonを用いています。

コレスポンデンス分析とは

近年、アンケートデータや購買データ、顧客属性データなど、大量のカテゴリデータを扱う機会が増加しています。しかし、これらのデータをクロス集計表で眺めるだけでは、データ内の複雑な関係性を把握するのは困難です。特に、カテゴリ同士の関連性を視覚的に理解するには、さらに踏み込んだ分析が必要です。
その課題を解決する手法としてコレスポンデンス分析があります。この手法は、データ内の「関連性が強い」カテゴリ同士を近くに、「関連性が弱い」カテゴリ同士を遠くに配置することで、直感的にデータ構造を理解できるようする手法です。
コレスポンデンス分析は、手法の概念が主成分分析に似ており、カテゴリデータを対象とする点が特徴的です。
カテゴリデータを対象にしたい場合、これらの手法は非常に強力であり、カテゴリ同士の関係性を視覚化し、主成分分析と同様に意思決定をサポートする重要な役割を果たします。

たとえば、「年代」と「携帯契約プラン」といったカテゴリ同士の関連性を調べる際、以下のようなクロス集計表を用います。


表1 年代と携帯の契約プランのクロス集計表(数値はダミー)
このクロス集計表は、データ同士の単純な対応関係を示していますが、情報量が多い場合は全体像を把握しにくくなります。
そこで、コレスポンデンス分析を適用すると、以下のようにデータを可視化できます。

図1 コレスポンデンス分析:年代(行)と契約プラン
この図では、各カテゴリ(例:年代や契約プラン)の配置が関連性を反映しています。同じ方向に近いカテゴリほど関係が強いことを意味し、反対方向に遠いカテゴリほど関係が弱いことを示します。
たとえば、この図を見れば「特定の年代がどの契約プランを好んでいるか」を視覚的に把握でき、「年代ごとにどのプランの広告を打てばよいのか」というアクションにつながります。

本記事では、コレスポンデンス分析の基本的な仕組みや活用方法と、データを用いた例を通じて、分析結果の解釈方法や具体的な活用イメージを共有することを目的とします。

また、カテゴリデータを扱う際、この手法がどのように役立つのかを具体的に示し、読者が自分のデータ分析に応用するためのヒントを得ることを目指します。

コレスポンデンス分析の仕組み

この章ではコレスポンデンス分析がどのようにしてカテゴリデータの特徴を捉えているのかを説明します。(少し理論的なお話)

参考文献はこちらです。

https://www.wordminer.org/wp-content/uploads/2013/04/8_0.pdf

https://yanbow221.hatenablog.com/entry/2018/07/18/212604

基本的には、

1.クロス集計データを基本の行列に直す
2. 固有値問題を解くことで、軸を求める

というステップに分かれます。

クロス集計表(分割表)

対応分析法の出発点は、クロス集計表(分割表)です。これは、行と列のカテゴリ間の頻度や相対度数を示す表であり、次の形式で表されます:

表2 項目i×jのクロス集計表F(出典:https://www.wordminer.org/wp-content/uploads/2013/04/8_0.pdf )
ここで:
f_{ij}: 行カテゴリ i と列カテゴリ j の間の頻度
n,m:行・列カテゴリの数

相対頻度行列の計算

クロス集計表の各要素を全体の合計で割ることで、カテゴリ間の確率的な関係性を表す同時確率分布が得られます。同時確率分布P_{IJ}は次のように定義されます:

P_{IJ}={p_{ij}}(i∈I,j∈J)

ここで:

  • p_{ij}: 行カテゴリ i と列カテゴリ j の同時確率
  • I, J: 行と列のカテゴリ集合

同時確率 p_{ij}は、観測頻度 f_{ij}を全体の合計 N で割ることで計算されます:

p_{ij}= \frac{f_{ij}}{N}, \quad N =f_{++}= \sum_{i=1}^m \sum_{j=1}^n f_{ij}

行カテゴリ iの周辺確率 p_{i+}は、行 iに属するすべての列の確率の合計として計算されます:

p_{i+}=\frac{f_{i+}}{N}
f_{i+} = \sum_{j=1}^n f_{ij}


表3 確率行列P_{IJ}(出典:https://www.wordminer.org/wp-content/uploads/2013/04/8_0.pdf

行と列のプロファイル

コレスポンデンス分析において、プロファイル(profile)はデータの特性を捉えるための重要な概念です。プロファイルとは、クロス集計表の行や列の「相対比率のパターン」を指します。この比率の情報を基に、カテゴリ間の関係性を解析していくのがコレスポンデンス分析の基本的なアプローチです。

プロファイルは、クロス集計表の行や列の頻度データをその行や列の合計で割ることで求められます。これにより、各カテゴリが他のカテゴリとどのように関連しているかを比率として示します。

  • 行プロファイル:
    行カテゴリごとに、その列カテゴリとの関連性を相対比率で表します。計算式は以下の通りです:
q_{ij}= \frac{p_{ij}}{p_{i+}}

ここで、
q_{ij}: 行カテゴリ i の列カテゴリ j に対するプロファイル
p_{ij}: クロス表の度数データ
p_{i+}: 行カテゴリ i の合計

  • 列プロファイル:
    列カテゴリごとに、その行カテゴリとの関連性を示します。
q_{ij}^∗=\frac{p_{ij}}{p_{+j}}

p_{+j}: 列カテゴリ j の合計

図2 プロファイルのイメージ(出典:https://www.wordminer.org/wp-content/uploads/2013/04/8_0.pdf

基本データ行列の生成

次に、比率のデータからカテゴリ間の関係性を解析するために、基本のデータ行列を生成します。この行列は、以下のような要素 x_{ij}を持ちます。

行列要素の定義:

各要素 x_{ij} は、行カテゴリ iと列カテゴリ jのデータの「中心化」された形で定義されます:

x_{ij} = \frac{p_{ij}}{p_{i+}\sqrt{p_{+j}}}=\frac{q_{ij}}{\sqrt{p_{+j}}}

または:

x_{ij}^∗ = \frac{p_{ij}}{p_{+j}\sqrt{p_{i+}}}=\frac{q_{ij}^*}{\sqrt{p_{i+}}}

ここで:

p_{i+}: 行カテゴリ i の周辺確率
p_{+j}: 列カテゴリ j の周辺確率
p_{i+}: 行カテゴリ i の合計
p_{+j}: 列カテゴリ j の合計

行列形式への変換:

上記の要素 x_{ij}を用いて、次のような m×n行列 Xを構築します:

X = (x_{ij}) \quad (i \in I, j \in J)
X^* = (x_{ij}^*) \quad (i \in I, j \in J)

この行列が、対応分析における「基本のデータ行列」となります。

軸を求める

やりたいことは、基本のデータ行列から2次元プロットでデータをまとめることでした。

コレスポンデンス分析では、クロス集計表から生成した基本データ行列を使って、カテゴリ同士の関係性をわかりやすく整理します。この整理の過程で、データの「主要な特徴」を抽出するには、これらの行列について分散共分散行列を求め、それぞれ固有値問題を解き、固有値と固有ベクトルを求めます。

XX^* に対して、以下のように操作を加えると、それぞれの分散共分散行列が得られます。

V=X^tP_IX
V^*=X^{*t}P_JX^*

これらの行列についてそれぞれ固有値問題を解けば、固有値と固有ベクトルが求まります。

行カテゴリ方向:

V= U \Lambda U^\top

列カテゴリ方向:

V^*=U^* \Lambda^* U^{*\top}

これはまさに主成分分析です。つまりコレスポンデンス分析は、行方向と列方向のそれぞれに対して主成分分析を行っていることになります。ここで、固有値行列\Lambda\Lambda^*の非ゼロ成分は一致することに注意します。

また、分析結果の評価指標では、主成分分析と同様に寄与率を用います。

寄与率は、各固有値がデータ全体の分散にどれだけ寄与しているかを示します。第 k 成分の寄与率 v_k は次の式で計算されます:

v_k=\frac{λ_k}{\sum_{k=1}^{K} \lambda_k}×100

ここで:

\lambda_k: 第 k 成分の固有値。
\sum_{k=1}^{K} \lambda_k: 全固有値の総和。

寄与率が高い成分ほど、データ全体の特徴をよく表していると解釈されます。

図3に、ここまでの手順イメージを載せます。

VV^*の両方でそれぞれ固有値分解を行い、得た2次元プロットを二つ用意して重ねるイメージです。

図3 コレスポンデンス分析のイメージ

実験と考察

では、実際にデータを用いてコレスポンデンス分析を実装してみましょう。

今回の分析では、肥満者を対象にし、年代ごとにどのような生活習慣が特徴的であるかを調べます。肥満に関連するカテゴリ(例: 高カロリー食品の消費、アルコール消費など)と年代の関係性を視覚化してみましょう。

データはUCI Machine Learning Repositoryに公開されている「Estimation of obesity levels based on eating habits and physical condition」を使用します。https://archive.ics.uci.edu/dataset/544/estimation+of+obesity+levels+based+on+eating+habits+and+physical+condition

今回の分析では、以下のように効いていそうな変数を選び、クロス集計表を作成しました。

NObeyesdad が以下の肥満カテゴリに該当するデータを対象とします。

  • 'Overweight Level I',
  • 'Overweight Level II',
  • 'Obesity_Type_I',
  • 'Obesity_Type_II',
  • 'Obesity_Type_III'

Age_Group:年代

以下の変数を生活習慣のカテゴリとして列に採用しました:

  • FAVC_yes: 高カロリー食品(摂取)
    • 説明: 高カロリー食品を摂取するかどうか。
  • CALC_no: アルコール消費(なし)
    • 説明: アルコールを消費しないかどうか。
  • CALC_yes: アルコール消費(あり)
    • 説明: アルコールを消費するかどうか。
  • SMOKE_yes: タバコ(あり)
    • 説明: タバコを吸うかどうか。
  • Gender_Male: 男性
    • 説明: 性別が男性であるかどうか。
  • Gender_Female: 女性
    • 説明: 性別が女性であるかどうか。
  • Automobile: 自動車
    • 説明: 移動手段として自動車を使用するかどうか。
  • TUE_0: テクノロジー使用時間(0)
    • 説明: テクノロジー機器の使用時間が0であるかどうか。
  • TUE_non_0: テクノロジー使用時間(0以外)
    • 説明: テクノロジー機器の使用時間が0以外であるかどうか。


表4 クロス集計表:年代(行)と肥満理由

では、以下のコードでコレスポンデンス分析を実行してみます。mcaというライブラリを用います。

#ライブラリのインポート
import pandas as pd
import mca
import matplotlib.pyplot as plt
import japanize_matplotlib

#クロス集計表の準備済みデータを適用
df = cross_table

#コレスポンデンス分析
ncol = df.shape[1]  # 列数
mca_ben = mca.MCA(df, benzecri=False, TOL=1e-8)

#Rowsのスコア(座標)を書き出す
result_row = pd.DataFrame(mca_ben.fs_r(N=2))
result_row.index = list(df.index)

#Columnsのスコア(座標)を書き出す
result_col = pd.DataFrame(mca_ben.fs_c(N=2))
result_col.index = list(df.columns)

cnt_column = len(df.columns)
cnt_index = len(df.index)

#可視化
plt.rcParams["figure.figsize"] = [7, 7]
fig, ax = plt.subplots()

#表側をプロット
result_row.plot(0, 1, kind='scatter', ax=ax, color='#FFA500', s=50, marker='o', label='年代')
for k, v in result_row.iterrows():
    ax.annotate(k, v)

#表頭をプロット
result_col.plot(0, 1, kind='scatter', ax=ax, color='C0', s=50, marker='x', label='特徴')
for k, v in result_col.iterrows():
    ax.annotate(k, v)

#軸線の描画
plt.axhline(0, color='gray', linestyle='--', linewidth=0.5)
plt.axvline(0, color='gray', linestyle='--', linewidth=0.5)

#ラベル設定
plt.xlabel('軸1')
plt.ylabel('軸2')
plt.legend()
plt.title("肥満の人の年代と特徴")
plt.show()


図4 コレスポンデンス分析:年代(行)と肥満理由
また、寄与率は以下のようになりました。

# 固有値(eigenvalue)と寄与率(explained variance of eigen vectors)
eigenvalues = mca_ben.L
explained_variance = mca_ben.expl_var(greenacre=False, N=len(eigenvalues))

# データフレームの作成
data = {
    'value': pd.Series(eigenvalues),
    'ratio': pd.Series(explained_variance)
}
columns = ['value', 'ratio']
table2 = pd.DataFrame(data=data, columns=columns).fillna(0)
table2.index += 1
table2.loc['Σ'] = table2.sum()
table2.index.name = 'Factor'

# 固有値と寄与率の確認
print("固有値と寄与率:")
print(table2)

# 寄与率のプロット
plt.figure(figsize=(8, 6))
plt.bar(table2.index[:-1], table2['ratio'][:-1], color='skyblue', edgecolor='black', alpha=0.8)  # 合計を除外
plt.xlabel('因子', fontsize=14)
plt.ylabel('寄与率', fontsize=14)
plt.title('寄与率のプロット', fontsize=16)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.show()


図5 因子と寄与率
2軸までで90%以上の情報を含んでいます。

今回のコレスポンデンス分析から、年代別に肥満に関連する生活習慣の特徴を視覚的に把握することができました。主な考察は以下の通りです。

  • 「20歳以下」&「20代前半」
    • 「男性」よりも「女性」との関連が強いです。さらに「高カロリー食品(接種)」との関連も強く、大学生や新社会人などの食生活が影響しているかもしれません。
  • 「20代後半」
    -「アルコール消費(あり)」との関連が強く見られます。付き合いが増えることでアルコールの摂取が増え、肥満の要因になっていそうです。
  • 「30代」
    • どの特徴に対しても関連がある、関連がないとは言えなさそうです。ほかの年代に比べて、全体的に肥満の理由にこれといった決め手がないかもしれません。
  • 「40代以上」
    • 「テクノロジー使用時間(0)」との関連が見られます。
  • その他
    • 「アルコール消費(なし)」はどの年代からも離れており、やはりある程度アルコール摂取は肥満に関係していそうです。

まとめと感想

コレスポンデンス分析は、カテゴリデータの関連性を視覚的に理解するための強力な手法であり、特にクロス集計表から得られる情報を効率的に整理する際に有用です。主成分分析に似たアプローチということもあり、直感的にも理解しやすかったです。

しかし、この手法にはいくつかの注意点もあります。特に、行成分スコアと列成分スコアを同じ空間にマッピングすることは、数学的な正当性よりも解釈のしやすさに基づくものです。そのため、常識と乖離した解釈結果が得られる場合もあります。

また、ソフトウェアごとにアルゴリズムが異なるため、同じデータセットでも得られるマップが異なる可能性があります。

コレスポンデンス分析はカテゴリデータを量的に解釈できる需要のある手法ですが、分析の際には手法の特徴を理解したうえで使うべきかもしれません。

今後は大量なデータから特徴を見つけ出す手法についてより調べていきたいと思います。

参考文献

執筆にあたって、以下の文献を参考にさせていただきました。

コンテンツ制作者様、改めてありがとうございました。

https://www.wordminer.org/wp-content/uploads/2013/04/8_0.pdf

https://yanbow221.hatenablog.com/entry/2018/07/18/212604

https://smart-hint.com/python/mca/

https://corvus-window.com/python_correspondence-analysis/

https://thinknote.blogspot.com/2018/12/pythonmca.html

https://freeasy24.research-plus.net/blog/c185

D2C m-tech

Discussion