このガイドは、Spearmanの順位相関係数、その数学的計算、そしてPythonの pandas
ライブラリを使った計算の紹介です。
この係数の基本的な理解を深めるために様々な例を作成し、ヒートマップを用いて相関行列を可視化する方法を紹介します。
スピアマン順位相関係数とは?
スピアマン順位相関はピアソン相関と密接な関係があり、どちらも2つの変数間の相関を示す-1
から1
までの境界値です。
代わりの相関係数についてもっと知りたい場合は、Pythonのピアソン相関係数ガイドをご覧ください。
ピアソン相関係数は生のデータ値を使って計算されますが、スピアマン相関は個々の値のランクから計算されます。
ピアソン相関係数が2つの変数の間の線形関係を測定するのに対し、スピアマン順位相関係数は一対の変数の間の単調な関係を測定します。
スピアマン相関を理解するためには、単調関数についての基本的な理解が必要です。
単調関数
単調増加、単調減少、非単調減少の関数がある。
単調増加関数では、Xが増加すると、Yも増加します(線形である必要はありません)。
単調減少関数では、一方の変数が増加すると、もう一方の変数が減少します(これも線形である必要はありません)。
非単調関数とは、一方の変数の値が増加すると、他方の変数の値が増加することもあれば、減少することもあるようなものです。
スピアマン順位相関係数は、2つの変数間の単調な関係を測定します。
その値は-1から+1までで、次のように解釈できる。
- +1: 完全に単調増加する関係
- 0.8:強い単調増加関係
- 0.2:弱い単調増加関係
- 0:非単調増加の関係
- 0.2:弱い単調減少の関係
- 0.8:強い単調減少の関係
- -1: 完全な単調減少の関係
数式表現
2つの確率変数XXXとYYYのnnn個のオブザベーションがあるとする.我々はまず、両変数のすべての値をそれぞれ XrXrX_r と YrYrY_r として順位付けする。
Spearman順位相関係数はrsrsr _sと表し、次式で計算される。
rs=ρXr,Yr=COV(Xr,Yr)STD(Xr)STD(Yr)=n∑xr∈Xr,yr∈Yrxryr-∑xr∈Xrxr∑yr∈Yryr√(n∑xr∈Xrxr2r-(∑yr∈Yryr)2)√(n∑yr∈Yryr2r-(∑yr∈Yryr)2)rs=ρXr.Xr=Xr(Yr)STD(Yr)=n∑yr(Xr)STD(Xr)Yr∈Yr)⇔Yr (Xr) Yr=COV(Xr,Yr)STD(Xr)STD(Yr)=n∑xr∈Xr,yr∈Yrxryr-∑xr∈Xrxr∑yr∈Yryr(n∑xr∈Xrxr2-(∑xr∈Xrxr)2)(n∑yr∈Yryr2-(∑Yr∈Yryr)2)であり、Yr=COV(Xr)STD{Yr}=Σxr{Xr{Xr{Yr(Yr)2(Σxr}2
r_s = rho_{X_r,Y_r} = frac{Text{COV}(X_r,Y_r)}{Text{STD}(X_r)text{STD}(Y_r)} = frac{numslimits_{x} in X_r ╱╱╱Y_r}= sum_{x} in Y_circuit_r (X_r) {X_r} (X_r){X_cove_r} {X_r} (Y_s) {X_r} {X_r y_r } x_r y_r – sumlimits_{x_rin X_r} x_r }sumlimits_{y_r} y_r}{big(nsumlimits {x_r} x_r^2 -) (sumlimits_{x_r} x_r)^2 ⑯⑭⑯⑯⑯⑯⑯⑯⑯⑯⑰ (nⅷ⑱ y_r^2) }} {Sqrt {Big(nsm_246D↩⑱Y_r} – (sumlimits_{y} Y_r) ^2 (Big) } } {Big
ここで、COV()
は共分散、STD()
は標準偏差を表しています。
この係数を計算するためのPythonの関数を見る前に、手で計算例をして式を理解し、その良さを知っておこう。
計算例
確率変数XXX とYYYのいくつかのオブザベーションが与えられたとする。
最初のステップは、XXXとYYYを対応するランクを表すXrXrX_rとYrYrY_rに変換することである。
また、いくつかの中間値も必要であり、以下に示す。
X=[−2−1012]TY=[41320]TXr=[12345]TYr=[52431]TX2r=[1491625]TY2r=[2541691]TXrYr=[5412125]TX=[−2−1012]TY=[41320]TXr=[12345]TYr=[52431]TXr2=[1491625]TYr2=[2541691]TXrYr=[5412125]TX
</mtd
=
</mtd
[の場合。
</mtd
-のように
2</mn
</mtd
-のように
1</mn
</mtd
0</mn
</mtd
1の場合
</mtd
2の場合
</mtd
]。
T
</msup
</mtd
</mtr
Yの場合
</mtd
=
</mtd
[の場合。
</mtd
4</mn
</mtd
1の場合
</mtd
3の場合
</mtd
2の場合
</mtd
0の場合
</mtd
]のようになります。
T
</msup
</mtd
</mtr
Xrの
</mtd
=
</mtd
[の場合。
</mtd
1
</mtd
2の場合
</mtd
3の場合
</mtd
4</mn
</mtd
5の場合
</mtd
]。
T
</msup
</mtd
</mtr
Yrの
</mtd
=
</mtd
[の場合。
</mtd
5
</mtd
2の場合
</mtd
4</mn
</mtd
3の場合
</mtd
1の場合
</mtd
]。
T
</msup
</mtd
</mtr
の
Xr2
</msubsup
</mtd
=
</mtd
[の場合。
</mtd
1
</mtd
4</mn
</mtd
9</mn
</mtd
16の場合
</mtd
25の場合
</mtd
]。
T
</msup
</mtd
</mtr
の
Yr2
</msubsup
</mtd
=
</mtd
[の場合。
</mtd
25
</mtd
4の場合
</mtd
16の場合
</mtd
9の場合
</mtd
1</mn
</mtd
]。
T
</msup
</mtd
</mtr
Xr
</msub
Yrの
</mtd
=
</mtd
[の場合。
</mtd
5
</mtd
4の場合
</mtd
12の場合
</mtd
12の場合
</mtd
5の場合
</mtd
]。
T
</msup
</mtd
</mtr
</math
先ほどの式でスピアマン相関を計算してみましょう。
rs=5∗38−(15)(15)√(5∗55−152)√(5∗55−152)=181532=−0.7rs=5∗38−(15)(15)(5∗55−152)(5∗55−152)=181532=−0.7の場合
rs
</msub
=5*38- ()
15)となります。
()となります。
15)となります。
</mrow
の場合
()
5*55-のようになります。
152</mn
</msup
).
()
5*55-のようになります。
152</mn
</msup
).
</msqrt
=の場合
181532
</mfrac
=-となります。
0.7</mn
すごい!(笑 しかし、これを手動で計算するのは時間がかかるので、コンピュータの最も良い使い方は、まあ、我々のために物事を計算することです。
Pandasの組み込み関数を使えば、スピアマンの相関を計算するのは本当に簡単でわかりやすい。
Pandasを用いたスピアマン順位相関係数の計算
Spearman を含む様々な相関係数は、Pandas ライブラリの corr()
メソッドで計算することができます。
入力引数として、 corr()
関数は相関を計算するために使用するメソッド(ここでは spearman
)を受け取ります。
このメソッドは、例えばサイズ mxn
の DataFrame
に対して呼ばれます。
ここで、各列は確率変数の値を表し、 m
は各変数の総標本数を表します。
n個の確率変数に対しては、
nxn個の正方行列
Rが返されます。
R(i,j) は、確率変数 i
と j
の間のスピアマン順位相関係数を表す。
変数とそれ自身の間の相関係数は 1 であるので、対角エントリの (i,i)
はすべて 1 に等しくなります。
R(i,j)={ri,j if i≠j1otherwiseR(i,j)={ri,j if i≠j1otherwiseR()
i,のように
j)となります。
=とする。
{rの場合。
i,の
j
</mrow
の
</mtd
もしなら
i≠の場合
j
</mtd
1
</mtd
そうでない場合。
</mtd
となります。
</mrow
</math
相関が対称であるように相関行列も対称であること、すなわちM(i,j)=M(j,i)
であることに注意してください。
前節の簡単な例で、Pandasの corr()
関数の使い方をみてみましょう。
import numpy as np
import pandas as pd
import seaborn as sns # For pairplots and heatmaps
import matplotlib.pyplot as plt
計算自体はPandasを使い、可視化はMatplotlibとSeabornを使い、データに対する追加の操作はNumpyを使って行います。
以下のコードは、データフレーム x_simple
に対してスピアマン相関行列を計算するものです。
対角線上にあるものに注意してください。
これは、ある変数とそれ自身の相関係数が当然ながら1であることを示します。
x_simple = pd.DataFrame([(-2,4),(-1,1),(0,3),(1,2),(2,0)],
columns=["X","Y"])
my_r = x_simple.corr(method="spearman")
print(my_r)
X Y
X 1.0 -0.7
Y -0.7 1.0
相関係数の可視化
強度が[-1, 1]という表のような構造であることから、相関係数を視覚化する自然で便利な方法は、ヒートマップです。
ヒートマップについてもっと詳しく知りたい方は、Pythonを使ったSeabornのヒートマップ究極ガイドを読んでみてください! Seabornのヒートマップについてもっと詳しく知りたい方は、Pythonを使ったSeabornのヒートマップ究極ガイドを読んでみてください。
をご覧ください。
ヒートマップはセルのグリッドで、各セルにはその値に応じて色が割り当てられています。
この視覚的な方法で相関行列を解釈することは、私たちにとって数値を解析するよりもずっと簡単なことなのです。
以前出力したような小さな表であれば、全く問題ありません。
しかし、たくさんの変数があると、何が起こっているのかを実際に解釈するのはずっと難しくなります。
相関係数を計算し、ヒートマップとして表示する display_correlation()
関数を定義してみましょう。
def display_correlation(df):
r = df.corr(method="spearman")
plt.figure(figsize=(10,6))
heatmap = sns.heatmap(df.corr(), vmin=-1,
vmax=1, annot=True)
plt.title("Spearman Correlation")
return(r)
Spearman の相関を可視化するために、 r_simple
DataFrame に対して display_correlation()
を呼び出してみましょう。
r_simple=display_correlation(x_simple)
合成例でスピアマンの相関係数を理解する
Spearman の相関係数を理解するために、より自然な例題に入る前に、この係数がどのように働くかを強調するいくつかの合成的な例題を作成してみましょう。
これらの例は、この係数がどのような関係において+1、-1、またはゼロに近いかを理解するのに役立ちます。
例を作成する前に、新しいヘルパー関数 plot_data_corr()
を作成します。
この関数は display_correlation()
を呼び出し、データを X
変数に対してプロットします。
def plot_data_corr(df,title,color="green"):
r = display_correlation(df)
fig, ax = plt.subplots(nrows=1, ncols=len(df.columns)-1,figsize=(14,3))
for i in range(1,len(df.columns)):
ax[i-1].scatter(df["X"],df.values[:,i],color=color)
ax[i-1].title.set_text(title[i] +'
r = ' +
"{:.2f}".format(r.values[0,i]))
ax[i-1].set(xlabel=df.columns[0],ylabel=df.columns[i])
fig.subplots_adjust(wspace=.7)
plt.show()
単調増加する関数
Numpy を使って単調増加する関数をいくつか生成し、合成データで満たされた DataFrame
を覗いてみましょう。
seed = 11
rand = np.random.RandomState(seed)
# Create a data frame using various monotonically increasing functions
x_incr = pd.DataFrame({"X":rand.uniform(0,10,100)})
x_incr["Line+"] = x_incr.X*2+1
x_incr["Sq+"] = x_incr.X**2
x_incr["Exp+"] = np.exp(x_incr.X)
x_incr["Cube+"] = (x_incr.X-5)**3
print(x_incr.head())
| X|Line+|Sq+|Exp+|Cube+|。
それでは、スピアマン相関のヒートマップと X
に対するさまざまな関数のプロットを見てみましょう。
plot_data_corr(x_incr,["X","2X+1","$X^2$","$e^X$","$(X-5)^3$"])
これらのすべての例で、変数の間に完全に単調増加する関係があることがわかります。
スピアマンの相関は、変数が線形関係であるか非線形関係であるかに関係なく、+1である。
Pearsonは、変数間の線形関係に基づいて計算されるので、ここではかなり異なる結果を出したでしょう。
Xが増加するとYが増加する限り、必ずスピアマン順位相関係数は1になります。
単調減少する関数
単調減少する関数について、同じ例を繰り返してみましょう。
再び合成データを生成し、スピアマンの順位相関を計算します。
まず、DataFrame
の最初の4行を見よう。
# Create a data matrix
x_decr = pd.DataFrame({"X":rand.uniform(0,10,100)})
x_decr["Line-"] = -x_decr.X*2+1
x_decr["Sq-"] = -x_decr.X**2
x_decr["Exp-"] = np.exp(-x_decr.X)
x_decr["Cube-"] = -(x_decr.X-5)**3
x_decr.head()
| X | Line- | Sq- | Exp- | Cube-
| — | — | — | — | — | — |
| 0 | 3.181872 | -5.363744 | -10.124309 | 0.041508 | 6.009985 |
| 1 | 2.180034 | -3.360068 | -4.752547 | 0.113038 | 22.424963 |
| 2 | 8.449385 | -15.898771 | -71.392112 | 0.000214 | -41.041680 |
| 3 | 3.021647 | -5.043294 | -9.130350 | 0.048721 | 7.743039 |
| 4 | 4.382207 | -7.764413 | -19.203736 | 0.012498 | 0.235792 |
相関行列のヒートマップと変数のプロットは、以下のようになります。
plot_data_corr(x_decr,["X","-2X+1","$-X^2$","$-e^X$","$-(X-5)^3$"],"blue")
非単調関数
以下の例は、様々な非単調関数に関するものです。
最後に DataFrame
に追加された列は、独立変数 Rand
のもので、これは X
とは何の関連もありません。
これらの例から、スピアマンの相関は2つの変数間の関係の単調性を表す尺度であることも明らかになるでしょう。
係数が0でも関係がないとは限りませんが、両者の間に単調性がないことを示します。
合成データを生成する前に、さらに別のヘルパー関数 display_corr_pairs()
を定義します。
これは、相関行列のヒートマップを表示するために display_correlation()
を呼び出し、 DataFrame
内のすべてのペアの変数を Seaborn library を用いて互いにプロットします。
対角線上には、map_diag()
を使用して、各変数のヒストグラムを黄色で表示します。
対角線の下には、すべての変数のペアの散布図を作成します。
相関行列は対称なので、対角線の上のプロットは必要ありません。
比較のためにピアソン相関係数も表示しましょう。
def display_corr_pairs(df,color="cyan"):
s = set_title = np.vectorize(lambda ax,r,rho: ax.title.set_text("r = " +
"{:.2f}".format(r) +
'
$rho$ = ' +
"{:.2f}".format(rho)) if ax!=None else None
)
r = display_correlation(df)
rho = df.corr(method="pearson")
g = sns.PairGrid(df,corner=True)
g.map_diag(plt.hist,color="yellow")
g.map_lower(sns.scatterplot,color="magenta")
set_title(g.axes,r,rho)
plt.subplots_adjust(hspace = 0.6)
plt.show()
単調でないデータフレーム x_non
を作成し、X
に以下の関数を設定します。
- 放物線: (X-5)2(X-5)2 (X-5)^2
- Sin: sin(X102π)sin(X102π) sin (frac{X}{10}2}π)
- Frac: X−5(X−5)2+1X−5(X−5)2+1 frac{X-5}{(X-5)^2+1}
- Rand: 範囲[-1,1]の乱数
以下は、x_non
の最初の4行です。
x_non = pd.DataFrame({"X":rand.uniform(0,10,100)})
x_non["Parabola"] = (x_non.X-5)**2
x_non["Sin"] = np.sin(x_non.X/10*2*np.pi)
x_non["Frac"] = (x_non.X-5)/((x_non.X-5)**2+1)
x_non["Rand"] = rand.uniform(-1,1,100)
print(x_non.head())
| X|放物線|Sin|Frac|Rand||。
異なるデータペア間のスピアマン相関係数は以下のように図示されています。
display_corr_pairs(x_non)
これらの例は、どのような種類のデータについてスピアマンの相関がゼロに近く、どこで中間値を持つかを示しています。
もう一つ注意すべきことは、スピアマン相関とピアソン相関係数は必ずしも一致しないので、一方が欠けても他方が欠けるとは限らないということです。
これらはデータの異なる側面について相関を調べるために使われるもので、同じように使うことはできません。
場合によっては一致することもありますが、常に一致するわけではありません。
Linnerudデータセットにおけるスピアマン相関係数
Spearman Correlation Coefficient を実際のデータセットに適用してみましょう。
ここでは、sklearn.datasets
パッケージから linnerud
というシンプルな身体運動のデータセットを選び、デモを行います。
import sklearn.datasets.load_linnerud
以下のコードでは、データセットを読み込み、対象となる変数と属性を一つの DataFrame
に結合しています。
linnerud` のデータの最初の 4 行を見てみましょう。
d=load_linnerud()
dat = pd.DataFrame(d.data,columns=d.feature_names)
alldat=dat.join(pd.DataFrame(d.target,columns=d.target_names) )
alldat.head()
| | 顎関節症|腹筋|ジャンプ|体重|ウエスト|脈拍||||||など
| — | — | — | — | — | — | — |
| 0 | 5.0 | 162.0 | 60.0 | 191.0 | 36.0 | 50.0 |
| 1 | 2.0 | 110.0 | 60.0 | 189.0 | 37.0 | 52.0 |
| 2 | 12.0 | 101.0 | 101.0 | 193.0 | 38.0 | 58.0 |
| 3 | 12.0 | 105.0 | 37.0 | 162.0 | 35.0 | 62.0 |
| 4 | 13.0 | 155.0 | 58.0 | 189.0 | 35.0 | 46.0 |
それでは、display_corr_pairs()
関数を使って相関ペアを表示させてみましょう。
display_corr_pairs(alldat)
Spearman の相関値を見ると、次のような興味深い結論を得ることができます。
- ウエストの数値が高いほど、体重の数値が増加する (r = 0.81 より)
- 腹筋の回数が多いほど、ウエストの数値が低い(r = -0.72)。
- あご、腹筋、ジャンプは脈拍と単調な関係にはないようで、対応する r 値はゼロに近い。
結論
このガイドでは、Spearman順位相関係数、その数学的表現、そしてPythonの pandas
ライブラリを用いたその計算について説明しました。
また、様々な合成例と Linnerrud
データセットでこの係数のデモを行いました。
スピアマンの相関係数は、2つの変数間の関係の単調さを計算するための理想的な尺度である。
しかし、値がゼロに近いからといって、必ずしもその変数に関連性がないとは言えない。