はじめに
投稿された記事に下手にコメントをつけると,うざがれたり,ブロックされたりするので,別個記事を書きます。
スピアマンの順位相関係数とは
さて,今回は「スピアマンの順位相関係数」です。わざわざ「スピアマンの」とあるのは,他に「ケンドールの順位相関係数」というのもあるからです。
いきなり,端的に言ってしまえば,「スピアマンの順位相関係数は,元のデータ(たとえば x, y の2つ)それぞれについて平均順位をつけ,その平均順位に基づき「ピアソンの積率相関係数」を計算したものです。またまた「ピアソンの積率」というのがついていますが,普通に「相関係数」として扱われているものの正式名称は「ピアソンの積率相関係数」なのです。
統計学のお話をするときに,やたらと数式を書きまくって煙に巻くということが多々ありますが,新規に開発した手法ならまだしも,もう100年以上も前に確立された手法を数式を用いて説明(証明)しようとするのは無意味でしょう。
それよりは,それぞれの手法の前提とか使用できるデータの条件とか結果の解釈に主眼を置くべきでしょう。もっとも,然るべき参考書やサイトならば,そのあたりはちゃんと押さえてあります。抑えてないなら,そのようなサイトは信用してはいけません。
実際の計算例
では,順を追って見ていきましょう。
以下のようなデータがあるとします。
x = -0.5, 1.1, -1.6, -1.3, 0.8, 0.9, -0.2, -0.8, 0.6, 1.0
y = -0.2, -1.1, -1.8, -0.3, 0.2, 1.3, 0.3, -0.2, 0.4, 1.5
x, y の「相関係数」...ピアソンの積率相関係数は,以下のようにして求めることができます。
よく使われるシークエンスとしては,データはデータフレームで用意されていると...
import pandas as pd
df = pd.DataFrame({'x': [-0.5, 1.1, -1.6, -1.3, 0.8, 0.9, -0.2, -0.8, 0.6, 0.9],
'y': [-0.2, -1.1, -1.8, -0.3, 0.2, 1.3, 0.3, -0.3, 0.4, 1.5]})
print(df)
x y
0 -0.5 -0.2
1 1.1 -1.1
2 -1.6 -1.8
3 -1.3 -0.3
4 0.8 0.2
5 0.9 1.3
6 -0.2 0.3
7 -0.8 -0.3
8 0.6 0.4
9 0.9 1.5
ピアソンの積率相関係数
x と y の相関係数(ピアソンの積率相関係数ですが,めんどうなので相関係数と言います)は以下のようにして求めることができます。
3変数以上の場合も含めているので行列形式で出力されますが,2変数の場合には右上(または左下)の数値が,相関係数です。
つまり,0.590726 ですね。
なお,以後,結果の出力は単に変数の値の表示の場合でも print(*) のように使用します。REPL でやっているような場合には print() は不要です。
print(df.corr())
x y
x 1.000000 0.587425
y 0.587425 1.000000
または,scipy.stats にある pearsonr() を使うこともできます。この関数は結果を2つ返しますが最初のものが相関係数です。2番めのものが何なのかはあとで書くかもしれません。
まあ,いずれにせよ,この x, y の相関係数は 0.5907261518582546 だったと記録しておいてください。
from scipy.stats import pearsonr
print(pearsonr(df['x'], df['y']))
PearsonRResult(statistic=0.587425029508349, pvalue=0.07415621034190775)
スピアマンの順位相関係数
次に,スピアマンの順位相関係数についてです(ここでも,面倒くさいから順位相関係数って略します)。
データフレームの場合は df.corr() のカッコの中に method='spearman' を書きます。ちなみに,相関係数の場合にはカッコの中に何も書かなかったですがそれは method='pearson' と書いたとみなされていたのでした。またまた,余計なことですが,method='kendall'と書いたら,「ケンドールの順位相関係数が計算されます。
print(df.corr(method='spearman'))
x y
x 1.000000 0.518293
y 0.518293 1.000000
scipy.stats にある spearmanr() で計算すると以下のようになります。
from scipy.stats import spearmanr
spearmanr(df['x'], df['y'])
SignificanceResult(statistic=0.5182926829268293, pvalue=0.12484673932719759)
数式なんかなくて清々しいですね。
その代わり,どのような場合にどちらを使うべきかと言うのは気をつけておきましょう。
どのような相関なのか?
直線的な相関の場合
2変数 x, y が直線的な関係(比例関係)であるかどうかを調べるときには相関係数も順位相関係数も同じような結果になります。
例えば, y = x のような場合(バカバカしいですが),相関係数は 1 になり,「完全な相関関係である」ということを意味します。
以下の例は y = x + 10 です。
df2 = pd.DataFrame({'x': range(0,10),
'y': range(10,20)})
print(df2)
x y
0 0 10
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
6 6 16
7 7 17
8 8 18
9 9 19
相関係数も,順位相関係数も 1 です。つまり,「完全な相関関係がある」ということです。
print(pearsonr(df2['x'], df2['y']))
PearsonRResult(statistic=0.9999999999999998, pvalue=1.0635035875250968e-62)
print(spearmanr(df2['x'], df2['y']))
SignificanceResult(statistic=0.9999999999999999, pvalue=6.646897422032013e-64)
曲線的な相関の場合
2 変数 x,y が曲線的な関係をもつ場合,たとえば以下の例では y = x**2 の関係があります。
df3 = pd.DataFrame({'x': range(0,10),
'y': [z**2 for z in range(0, 10)]})
print(df3)
x y
0 0 0
1 1 1
2 2 4
3 3 9
4 4 16
5 5 25
6 6 36
7 7 49
8 8 64
9 9 81
print(pearsonr(df3['x'], df3['y']))
PearsonRResult(statistic=0.9626907371412555, pvalue=8.103391267431776e-06)
print(spearmanr(df3['x'], df3['y']))
SignificanceResult(statistic=0.9999999999999999, pvalue=6.646897422032013e-64)
相関係数は 1 ではない値ですが,順位相関係数は 1 です。
つまり,x と x**2 というような場合は,x と x**2 のペアの大小関係は常に一定なので,「順位に基づく相関係数である順位相関係数はこの場合には 1 になる」ということです。
相関係数と順位相関係数の関係
さて,話を先に勧めましょう。
「順位相関係数は,元のデータの平均順位をつけて,その平均順位をデータと見て計算した相関係数である」ということについてです。
データは一番はじめの df を例に上げます。
単純に思える「順位付け」というのも何通りかあります。
もっとも馴染みの深いのは,競技のような場合です。同じ記録値を持つものは同じ順位とするものでしょう。例えば,9点,8点,8点,7点という4人がいた場合,順位を「1位,2位,2位,4位」とするような場合です。平均順位というのは「1位,2.5位,2.5位,4位」とするものです(同点のものは同点がなかったものとしてつけた順位の平均値を順位とするわけです...わかりにく〜〜)。
さて,平均順位をつけるのも Python には用意されていて,データフレームの場合は,それは簡単にデータフレーム名.rank()
で行われます。
df4 = df.rank()
print(df4)
x y
0 4.0 5.0
1 10.0 2.0
2 1.0 1.0
3 2.0 3.5
4 7.0 6.0
5 8.5 9.0
6 5.0 7.0
7 3.0 3.5
8 6.0 8.0
9 8.5 10.0
または,scipy.stats の rankdata() でも行なえます
from scipy.stats import rankdata
print(rankdata(df['x']))
print(rankdata(df['y']))
[ 4. 10. 1. 2. 7. 8.5 5. 3. 6. 8.5]
[ 5. 2. 1. 3.5 6. 9. 7. 3.5 8. 10. ]
では,この平均順位をデータと見て相関係数と計算してみましょう。(df4 を使いますよ)
print(df4.corr())
x y
x 1.000000 0.518293
y 0.518293 1.000000
これが,順位相関家数です。前の方の結果 print(df.corr(method='spearman')) と比べてみましょう。
print(df.corr(method='spearman'))
x y
x 1.000000 0.518293
y 0.518293 1.000000
おなじになっていますね。
scipy.stats の spearmanr, pearsonr を使っても同じ関係がであることが確認できます。
print(spearmanr(df4['x'], df4['y']))
SignificanceResult(statistic=0.5182926829268293, pvalue=0.12484673932719759)
print(pearsonr(df4['x'], df4['y']))
PearsonRResult(statistic=0.5182926829268292, pvalue=0.12484673932719782)
終わりです
はい。ご苦労様でした。
数式がないのに結構面倒くさかった...ですか?
そんなもんです。
あ,追加しておきますね。scipy.stats の spearmanr, pearsonr で返される結果の 2 番目のものは 'pvalue' という名前がついていますが,この数値は「2つの変数の間の相関係数が 0
である(つまり相関がない)という帰無仮説のもとで,実際に観察された標本相関係数が得られる確率を表します。
面倒くさいと思うかもしれないですが,この手続き及びその記述は,「要するに~~~」などと簡単に述べるのは厳に慎むべきことなのですが...それはまた,別のお話。
また,スピアマンの順位相関係数の正確検定 exact test についても,ここでは触れない。