「カテゴリカル変数の相関係数」をご存知ですか?
統計学には様々な分析手法がありますが、変数間の相関関係の強さを定量的に測るための「相関係数(ピアソンの積率相関係数)」は非常に有名でよく使われています。
通常、連続変数(量的変数)間の相関関係を定量評価するために使われる相関係数ですが、カテゴリカル変数(質的変数)に対して使える相関係数も存在します。
私が所属する株式会社 GA technologies ではマンションの設備の充実度のスコアリングといったことも行っており、マンションの設備データは「宅配ボックスの有無」「インターネット対応かどうか」「浴室のタイプ("3 点ユニットバス", "2 点ユニットバス", "独立洗面台")」など様々なカテゴリカル変数が含まれています。本記事でご紹介する「カテゴリカル変数の相関係数」は私自身も業務で使用しており、個人的に興味深い手法だと思うのでご紹介します。
(※なおタイトルでは「カテゴリカル変数」と書いておりますが、今回はそのうち順序尺度のものだけを対象にしております。名義尺度の場合はクラメールの V (Cramer's V) のような相関係数に近い指標が存在しますが、今回は割愛します)
❓️ カテゴリカル変数とは / 順序尺度とは
カテゴリカル変数は例えば曜日や性別などのカテゴリを表す変数のことを指しますが、そのなかでも名義尺度と順序尺度の 2 種類が存在します。
名義尺度(nominal scale) は各カテゴリ間に順序性がないカテゴリカル変数のことで、例えば次のようなものがあります。
- 性別:男性、女性、その他
- 血液型:A 型、B 型、O 型、AB 型
- 都道府県:東京都、大阪府、…
順序尺度(ordinal scale) はカテゴリ間に順序性が考えられるカテゴリカル変数で、次のようなものがあります。
- 満足度:不満、普通、満足
- 教育水準:中卒、高卒、大卒、大学院卒
- 痛みの程度:軽い、中程度、重い
順序尺度であれば大小関係を反映した数値を割り振ることができます。例えば「あてはまらない」「どちらでもない」「あてはまる」の 3 つの値をとる変数なら、それぞれ
🔢 順序尺度の相関係数
💡 前提となる考え方
順序尺度の相関係数には、データの生成過程として 「観測値の背後には連続的な値を取る潜在変数が存在していて、ある閾値によって離散化されてカテゴリカル変数になった値だけ観測できている」 と仮定をおくタイプの相関係数があります。本記事ではこのタイプの代表的な相関係数をご紹介していきます。
ただその前に、「潜在変数を仮定する」という考え方がやや分かりにくいかと思いますので、少し具体的な例を挙げてみます。
例 1:テストの設問
例えば統計学のテストにおける、ある設問のデータをとったとします。解答データは「正答」と「誤答」の 2 カテゴリをもつカテゴリカル変数と捉えることができて、名義尺度としても順序尺度としても捉えられますが、順序尺度として捉えて 観測値の背後には「統計学への理解度」という連続変数
というように仮定する、ということです。
例 2:満足度のアンケート
別の例としては、あるサービスの満足度をアンケートで調査し、選択肢として「不満」「普通」「満足」を選ぶような設問にしていたとします。観測できるのは「不満」「普通」「満足」の選択肢だけですが、 ユーザーの心のなかには潜在的な(データとして観測できない)「満足度」
と仮定する、といった具合です。
以下ではこのような仮定をおくタイプの相関係数の代表的な手法を 2 つご紹介します。
⚒️ ポリコリック相関係数
ポリコリック相関(polychoric correlation)係数 は 2 つのカテゴリカル変数
前述のように、観測されたカテゴリカル変数
というふうに仮定(モデリング)します。
(ただし、両端の閾値 は
そして、この連続型確率変数
そしてこの 2 変量標準正規分布の尤度関数
より具体的にどういう推定をするのかについても記載しておきます。
(飛ばして次の節に進んでいただいても構いません。興味のある方のみご覧いただければと思います)。
(参考)推定の詳細
最尤推定するために、カテゴリカル変数
ポリコリック相関係数の対数尤度関数
となります。ここで
この時点で対数尤度関数の引数は
のように推定できますので、残る変数は
を解くことで相関係数を求めることができます。
🛠️ ポリシリアル相関係数
ポリシリアル相関(polyserial correlation)係数 は連続変数
という同時分布に従うと考えて尤度関数を構築し、最尤推定法で相関係数
(参考)推定の詳細
連続変数を
カテゴリカル変数
ここで、連続変数
さて、尤度関数を求めていきたいわけですが、
のように同時確率密度
となります。ここで
となります。ここで
になります。
上記のようにが求められる
というふうに構築し、
📃 どういうときに使われている手法なのか?
「ポリコリック相関係数・ポリシリアル相関係数はどういった分野で使われているの?初めて聞いたよ?」と思う方もいらっしゃるかもしれません。
これまで順序尺度の例として「アンケート」や「試験の設問」を挙げましたが、まさにそういうデータを使う分野、例えば 心理学 や 教育学 や マーケティング などで用いられることが多いです。また、データ分析の手法としては 因子分析 や 項目反応理論 (の分析の前段階での項目分析)において用いられることが多いです。
例えば因子分析では分散共分散行列や相関行列を説明するような線形モデルを組んでいくことになりますので、カテゴリカルデータに対して因子分析を適用する場合、ポリコリック相関係数やポリシリアル相関係数を用いて相関行列を算出してから因子分析モデルを当てはめるという分析方法があります。具体的な分析手順についてはこちらの記事をご参照ください。
また項目反応理論(TOEIC や PISA のスコア算出など、スコアリングに広く使われている分析手法)においては、分析手順のうち「項目(テストやアンケートの設問)」がもつ統計的な性質を確認する作業においてカテゴリカル変数に対する相関係数が使われることがあります。例えばあるテストの設問に対して回答者が正答しているかどうか(項目反応)とテスト全体の得点との相関を調べて「この設問は測りたいスコア(能力値)に対して有効な設問になっていそうか」を検討する際に使われます。詳しくは次の記事や 加藤ほか(2023) などの書籍をご参照ください。
⚠️ ピアソンの積率相関係数を使うことによるバイアス
もしかしたら 「そんな特殊な相関係数をわざわざ使わなくても、順序尺度を数値に変換して普通の相関係数(ピアソンの積率相関係数)を使えばよいのでは?」 と思われるかもしれません。確かに、マニアックな相関係数を覚えて使い分けるのは少し手間がかかります。しかし、データによっては ピアソンの積率相関係数は大きなバイアスを含んだ推定値を出す ことがあります。
数値的に実験してみましょう。
🧪 実験 1
相関係数
Python では ordinalcorr パッケージを使うことでポリコリック相関係数やポリシリアル相関係数を簡単に実行できますので、それを使用します。
その結果が次の図になります。左の列の散布図が乱数生成データで、真ん中の列が片方の変数だけ離散化してポリシリアル相関係数とピアソンの積率相関係数とを比較した図、右の列が両方の変数を離散化してポリコリック相関係数と他の相関係数を比較したものになります。横軸の「カテゴリ数」は離散化する際にいくつのカテゴリへ離散化するかを意味します。
真の相関
(参考)実験に使用したコードはこちら
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib_fontja
from scipy.stats import multivariate_normal, pearsonr, spearmanr, kendalltau
from ordinalcorr import polychoric, polyserial
def gen_bivariate_normal(rho=0.5, size=1000, seed=0):
# 2変量標準正規分布によるデータ生成
mean = [0, 0]
std = [1, 1]
cov = rho * std[0] * std[1]
Cov = np.array([[std[0] ** 2, cov], [cov, std[1] ** 2]])
X = multivariate_normal.rvs(mean=mean, cov=Cov, size=size, random_state=seed)
df = pd.DataFrame(X, columns=["x", "y"])
return df
def plot_data(ax, continuous_data, rho, n):
sns.scatterplot(data=continuous_data, x="x", y="y", ax=ax)
ax.set(title=f"2変量標準正規分布に従うデータ(ρ={rho}, n={n})")
def plot_polyserial(ax, continuous_data, rho):
# 離散化のカテゴリ数を変えつつ相関係数を算出
results = []
for k in range(2, 11):
x = continuous_data["x"]
y, _ = pd.cut(continuous_data["y"], bins=k).factorize(sort=True)
results += [
dict(method="Pearson", value=pearsonr(x, y).statistic, k=k),
dict(method="Polyserial", value=polyserial(x, y), k=k),
]
results = pd.DataFrame(results)
# データをグラフにplot
sns.lineplot(x="k", y="value", data=results, hue="method", marker="o", ax=ax)
ax.axhline(rho, label=f"真値 (ρ={rho})", color="black")
ax.set(
xlabel="カテゴリ数",
ylabel=r"推定された相関係数 $\hat{\rho}$",
title="連続変数xと離散化されたyの相関係数"
)
ax.legend()
def plot_polychoric(ax, continuous_data, rho):
# 離散化のカテゴリ数を変えつつ相関係数を算出
results = []
for k in range(2, 11):
x, _ = pd.cut(continuous_data["x"], bins=k).factorize(sort=True)
y, _ = pd.cut(continuous_data["y"], bins=k).factorize(sort=True)
results += [
dict(method="Pearson", value=pearsonr(x, y).statistic, k=k),
dict(method="Polychoric", value=polychoric(x, y), k=k),
dict(method="Spearman", value=spearmanr(x, y).statistic, k=k),
dict(method="Kendall", value=kendalltau(x, y).statistic, k=k),
]
results = pd.DataFrame(results)
# データをグラフにplot
sns.lineplot(x="k", y="value", data=results, hue="method", marker="o", ax=ax)
ax.axhline(rho, label=f"真値 (ρ={rho})", color="black")
ax.set(
xlabel="カテゴリ数",
ylabel=r"推定された相関係数 $\hat{\rho}$",
title="離散化された x, y の相関係数"
)
ax.legend()
# 実験
n = 1000
fig, axes = plt.subplots(figsize=[12, 9], nrows=3, ncols=3, tight_layout=True)
rhos = [-0.5, 0, 0.5]
for i, rho in enumerate(rhos):
continuous_data = gen_bivariate_normal(rho=rho, size=n)
plot_data(axes[i, 0], continuous_data, rho, n)
plot_polyserial(axes[i, 1], continuous_data, rho)
plot_polychoric(axes[i, 2], continuous_data, rho)
🧪 実験 2
上記の実験では 1 つの分布に対して 1 つのデータセットを乱数で生成して推定値を算出していたので、たまたま推定誤差が出た可能性もあります。そこで疑似乱数のシードを変えて何個もデータセットを作成して何回も相関係数を推定するシミュレーションを行ってみました。その結果、推定値の分布は次の図のようになりました。
真の相関係数が-0.5 や 0.5 のとき、ピアソンの積率相関係数は真の相関係数(黒い破線)から少しズレたところに推定値が集中しています。たまたまではなく、推定値が平均的に真の値からズレている、つまり ピアソンの積率相関係数による推定値はバイアスをもっている ことがわかります。
他方でポリコリック相関係数やポリシリアル相関係数の推定値は平均的に真の相関係数に一致する推定値となっており、バイアスがないことがわかります。
(参考)実験に使用したコードはこちら
※実験 1 のコードで定義した関数は省略しています。
def calc_polychoric(continuous_data, k):
x, _ = pd.cut(continuous_data["x"], bins=k).factorize(sort=True)
y, _ = pd.cut(continuous_data["y"], bins=k).factorize(sort=True)
results = pd.DataFrame([
dict(method="Pearson", value=pearsonr(x, y).statistic, k=k),
dict(method="Polychoric", value=polychoric(x, y), k=k),
])
return results
def calc_polyserial(continuous_data, k):
x = continuous_data["x"]
y, _ = pd.cut(continuous_data["y"], bins=k).factorize(sort=True)
results = pd.DataFrame([
dict(method="Pearson", value=pearsonr(x, y).statistic, k=k),
dict(method="Polyserial", value=polyserial(x, y), k=k),
])
return results
import seaborn as sns
n = 1000
n_trials = 1000
rhos = [-0.5, 0.0, 0.5]
nrows = len(rhos)
k = 2
ncols = 2
fig, axes = plt.subplots(figsize=[ncols * 4, nrows * 3], nrows=nrows, ncols=ncols, tight_layout=True)
for i, rho in enumerate(rhos):
# データ生成 & 推定
polychoric_estimates = []
polyserial_estimates = []
for seed in range(n_trials):
continuous_data = gen_bivariate_normal(rho=rho, size=n, seed=seed)
polychoric_estimates.append(calc_polychoric(continuous_data, k))
polyserial_estimates.append(calc_polyserial(continuous_data, k))
polychoric_estimates = pd.concat(polychoric_estimates, ignore_index=True)
polyserial_estimates = pd.concat(polyserial_estimates, ignore_index=True)
# plot
j = 0
sns.histplot(data=polyserial_estimates, x="value", hue="method", bins=30, kde=True, stat="density", ax=axes[i, j], alpha=0.5)
axes[i, j].set(
title=f"連続変数xと離散変数yの相関係数の標本分布\n(真のρ={rho}, カテゴリ数={k})",
xlabel=r"推定値$\hat{\rho}$",
)
axes[i, j].axvline(rho, color="black", linestyle="--")
j = 1
sns.histplot(data=polychoric_estimates, x="value", hue="method", bins=30, kde=True, stat="density", ax=axes[i, j], alpha=0.5)
axes[i, j].set(
title=f"離散変数x, yの相関係数の標本分布\n(真のρ={rho}, カテゴリ数={k})",
xlabel=r"推定値$\hat{\rho}$",
)
axes[i, j].axvline(rho, color="black", linestyle="--")
💀 相関の希薄化
ところで、前述の実験ではピアソンの積率相関係数がバイアスのある推定値を返すときは常にゼロに近づく方向にバイアスがありました。これは偶然ではなく、相関の強さを過小評価する方向にバイアスがあることは 相関の希薄化(attenuation of correlation) として知られています。
データの測定誤差よる相関の希薄化の問題を最初に発見したのは Spearman (1904) で、観測される相関
連続変数を離散化してカテゴリカル変数にすることは測定の粒度を粗くすることに相当するため、測定誤差が増える(=信頼性が下がる)問題の一種となります。
ただし、離散化による誤差はまったくのランダムではなく系統性をもつため、どういう分布をどう区切って離散化するかによって希薄化の強さは変わってきます。
例えば Peters & Van Voorhis (1940) は相関係数が
になる、つまり真の相関係数の約 0.8 倍へと過小評価する問題があることを報告しています。
過去には上記例の「
✅️ まとめ
順序尺度のカテゴリカル変数の相関係数を求めるとき、 ピアソンの積率相関係数を使うとバイアスを含んだ推定値が出てくることがあります (相関の希薄化の問題)。
そういった状況では、 ポリシリアル相関係数やポリコリック相関係数といった手法を使うことで、よりバイアスの少ない推定値を得ることができます。
もしカテゴリカル変数の相関を分析する場合はこれらの手法を採用することを検討されてみてはいかがでしょうか。
📖 参考文献
- Bedrick, E. J. (1995). A note on the attenuation of correlation. British Journal of Mathematical and Statistical Psychology, 48(2), 271–280.
- Cohen, J. (1983). The cost of dichotomization. Applied psychological measurement, 7(3), 249-253.
- Drasgow, F. (1986). Polychoric and polyserial correlations. In S. Kotz & N. Johnson (Eds.), The Encyclopedia of Statistics.
- Muchinsky, P. M. (1996). The Correction for Attenuation. Educational and Psychological Measurement, 56(1), 63–75.
- Peters, C. C., & Van Voorhis, W. R. (1940). Statistical procedures and their mathematical bases. McGraw-Hill.
- Spearman, C. (1904). The proof and measurement of association between two things. American Journal of Psychology, 15, 72–101.
- 加藤健太郎、山田剛史 & 川端一光 (2014)『R による項目反応理論』、オーム社。
- 小杉考司(2013)「順序尺度の相関係数(ポリコリック相関係数)について」。
- 豊田秀樹(1998)『共分散構造分析[入門編]』、朝倉書店。
株式会社 GA technologies は今回ご紹介したような技術も活用しつつ、アナログな業界をテクノロジーで前進させていく会社です。公式 note や AISC(研究開発組織)の note もぜひご覧ください。
Discussion