PyLearnST03: 相関係数によるデータ分析

本節では、データ分析の基礎となる相関係数による分析を扱います。このコードを勉強する前に、まず相関係数とは何か、調べてみて下さい。最小値、最大値、マイナス・プラスのときの解釈方法、0付近の解釈、少なくとも、これらは答えられるようになってからやってみましょう。なお、実際は実データを用いて分析を行いますが、今回は練習ですので、乱数を使用します。まず、おまじないとして以下のコードを実行してください。

In [1]:
import numpy as np
np.random.seed(1) # 擬似乱数シード: 毎回同じ乱数を出す

# 正相関が生じる乱数列
mu = [1.0, 1.0]
sigma = [[0.15, 0.1], [0.1, 0.15]]
Dat01 = np.random.multivariate_normal(mu, sigma, 100)

# 負相関が生じる乱数列
mu = [1.0, 1.0]
sigma = [[0.15, -0.1], [-0.1, 0.15]]
Dat02 = np.random.multivariate_normal(mu, sigma, 100)

# 無相関が生じる乱数列
mu = [1.0, 1.0]
sigma = [[0.15, 0.0], [0.0, 0.15]]
Dat03 = np.random.multivariate_normal(mu, sigma, 100)

Dat01は正相関、Dat02は負相関が生じ、Dat03は無相関となるように作成した2列の配列となります(上の記法などは、後述する確率密度関数を参照してください)。繰り返しますが、乱数を用いるのではなく、本来は取得したデータで相関係数を算出します。Dat01などは自分でデータを取るんだな、くらいの感覚でいてください。 以下に、Dat01、Dat02、Dat03の散布図を描画してみます。

In [3]:
import matplotlib.pyplot as plt

x = [Dat01[:,0], Dat02[:,0], Dat03[:,0]]
y = [Dat01[:,1], Dat02[:,1], Dat03[:,1]]

col=["orange", "red", "blue"]
figtitle=["Dat01", "Dat02", "Dat03"]

# 描画領域の生成
fig = plt.figure(figsize=(18, 5))
fig.subplots_adjust(wspace=0.3, hspace=0.4) # 横のグラフ同士の幅、縦のグラフ同士の幅

# for文を利用して、4つのグラフを描画
for i in range(0, len(x)):
    plt.subplot(1,3,i+1)
    plt.scatter(x[i], y[i],   # 横軸、縦軸の値
            s=30,               # マーカサイズ
            c=col[i],         # マーカの色(red, blue, pink, yellow, orange, blackなど)
            marker='s',         #マーカの形(.osなど:下記参照)
            alpha=0.8,          # 塗りつぶしの透明度(0:完全に透明〜1:透明にしない)
            linewidths=0.5,     # マーカの線の太さ
            edgecolors='black') # マーカの線の太さ(マーカの色と同じ。不要の場合は''なしでNone)

    plt.title(figtitle[i])  # タイトル
    plt.xlabel("x axis") # 軸名
    plt.ylabel("y axis") #軸名
    plt.grid(True)      #グリッド線(True:引く、False:引かない)
    plt.xlim(0, 2)  # 横軸最小最大
    plt.ylim(0, 2)  # 縦軸最小最大

plt.show()

相関係数を算出するコード

以下は、Dat01の相関係数を算出するコードです。scipyで定義されている関数を使います。

In [4]:
import scipy.stats as st
Dat01cor = st.pearsonr(Dat01[:,0], Dat01[:,1])
print(Dat01cor)
(0.6154055249882459, 9.55310109139995e-12)

数字が2つ出てきました。左側が相関係数、右側がそのp値となります。p値が0.05未満のとき、統計的に意味のある相関であるということを意味しています(詳細を知りたい人は、無相関検定で調べてみて下さい)。なので、以下のように記載すれば良いです。

In [5]:
Dat01cor[0]
print("Dat01の相関係数: ", Dat01cor[0], ", p値:", Dat01cor[1])
Dat01の相関係数:  0.6154055249882459 , p値: 9.55310109139995e-12

正相関が生じそうな具体例は、

  • 横軸: 勉強時間、縦軸: 試験得点
  • 横軸: ご飯を食べる量、縦軸: 体重

といった感じでしょうか。相関係数が正方向に高いと「これが高いとあれも高い、これが低いとあれも低い」という関係を示唆するということがわかります。あと少しややこしい話ですが、相関関係は因果関係を保証しません。より簡単にいうと、相関係数が高い場合は「これを高めるとあれも高まる」という可能性があることを意味すれど、それが保証されるわけではありません。考察のときには注意して下さい(詳しくは、「相関関係と因果関係の違い」などで検索して自分で調べて下さい)。

ところで、小数点以下が多すぎ!と思ったりしませんか。このような場合に小数点以下を指定の桁数できるには、round関数を使います。

In [6]:
print("Dat01の相関係数: ", round(Dat01cor[0], 3), ", p値:", round(Dat01cor[1], 5))
Dat01の相関係数:  0.615 , p値: 0.0

round(A, n)で、Aの小数点以下をn桁にする、という意味があります。研究報告をするときや、外部公表をするときは、適切な桁数で区切って下さい。数字をズラーっと並べると、怒る人も多いです。ちなみに、この結果が出たときは、論文や研究報告では以下のように記載して下さい。

変数XとYの相関係数は0.713であり、1%水準で有意であった。
変数XとYの相関係数は$r(X, Y)=.615$ $(p<.01)$出会った。
変数XとYの相関係数は$r(X, Y)=0.615$ $(p<0.01)$出会った。

書き方はいろいろありますが、ポイントは、係数とp値の2つとものせてあげるという点です。片手落ちはNGです。注意しましょう。p値は、0.05未満であれば5%水準有意、0.01未満であれば1%水準有意であることを明示的に示します。$p<0.01$といった記述をすれば、1%水準有意であることを伝えたことになります。つまり、それだけ相関がありそうだということを示しています。
さて、相関係数の出し方がわかったところで、3つのデータすべての相関係数を出してみましょう。

In [7]:
Dat01cor = st.pearsonr(Dat01[:,0], Dat01[:,1])
Dat02cor = st.pearsonr(Dat02[:,0], Dat02[:,1])
Dat03cor = st.pearsonr(Dat03[:,0], Dat03[:,1])
print("Dat01の相関係数: ", round(Dat01cor[0], 3), ", p値:", round(Dat01cor[1], 5))
print("Dat02の相関係数: ", round(Dat02cor[0], 3), ", p値:", round(Dat02cor[1], 5))
print("Dat03の相関係数: ", round(Dat03cor[0], 3), ", p値:", round(Dat03cor[1], 5))
Dat01の相関係数:  0.615 , p値: 0.0
Dat02の相関係数:  -0.695 , p値: 0.0
Dat03の相関係数:  -0.052 , p値: 0.61018

Dat01は正方向に値が大きいので右肩上がり、Dat02は負方向に値が大きいので右肩下がり、Dat03は値が0に近いので右肩上がり・下りといった傾向がないことを意味します。実際の散布図と相関係数はぴったり関係がマッチしていますね。また、無相関の場合のみ、p値が0.05を超えています。すなわち、Dat03は「統計的に有意な相関関係はない」ことを意味します。こういった場合は以下のように記述して下さい。

変数XとYには有意な相関関係が存在しなかった($r(X, Y)=-0.052$, $p=0.610$)。
変数XとYには有意な相関関係が存在しなかった($r(X, Y)=-.052$, $p=.610$)。

さて、相関係数とp値が求まったので、かっこよく散布図に載せて見ましょう。figtitleリストに対し、タイトルを格納し、pltの引数に渡せばokです。

In [8]:
import matplotlib.pyplot as plt

x = [Dat01[:,0], Dat02[:,0], Dat03[:,0]]
y = [Dat01[:,1], Dat02[:,1], Dat03[:,1]]
col=["orange", "red", "blue"]

# 相関係数とp値の算出
Dat01cor = st.pearsonr(Dat01[:,0], Dat01[:,1])
Dat02cor = st.pearsonr(Dat02[:,0], Dat02[:,1])
Dat03cor = st.pearsonr(Dat03[:,0], Dat03[:,1])

figtitle=[
    "Dat01"+":r="+str(round(Dat01cor[0],3)),
    "Dat02"+":r="+str(round(Dat02cor[0],3)),
    "Dat03"+":r="+str(round(Dat03cor[0],3))]

# 描画領域の生成
fig = plt.figure(figsize=(18, 5))
fig.subplots_adjust(wspace=0.3, hspace=0.4) # 横のグラフ同士の幅、縦のグラフ同士の幅

# for文を利用して、4つのグラフを描画
for i in range(0, len(x)):
    plt.subplot(1,3,i+1)
    plt.scatter(x[i], y[i],   # 横軸、縦軸の値
            s=30,               # マーカサイズ
            c=col[i],         # マーカの色(red, blue, pink, yellow, orange, blackなど)
            marker='s',         #マーカの形(.osなど:下記参照)
            alpha=0.8,          # 塗りつぶしの透明度(0:完全に透明〜1:透明にしない)
            linewidths=0.5,     # マーカの線の太さ
            edgecolors='black') # マーカの線の太さ(マーカの色と同じ。不要の場合は''なしでNone)

    plt.title(figtitle[i])  # タイトル
    plt.xlabel("x axis") # 軸名
    plt.ylabel("y axis") #軸名
    plt.grid(True)      #グリッド線(True:引く、False:引かない)
    plt.xlim(0, 2)  # 横軸最小最大
    plt.ylim(0, 2)  # 縦軸最小最大

plt.show()

ちょっと文字サイズが小さいです。大きくするには、以下のようにかけばokです。

In [9]:
import matplotlib.pyplot as plt

x = [Dat01[:,0], Dat02[:,0], Dat03[:,0]]
y = [Dat01[:,1], Dat02[:,1], Dat03[:,1]]
col=["orange", "red", "blue"]

# 相関係数とp値の算出
Dat01cor = st.pearsonr(Dat01[:,0], Dat01[:,1])
Dat02cor = st.pearsonr(Dat02[:,0], Dat02[:,1])
Dat03cor = st.pearsonr(Dat03[:,0], Dat03[:,1])

figtitle=[
    "Dat01"+":r="+str(round(Dat01cor[0],3)),
    "Dat02"+":r="+str(round(Dat02cor[0],3)),
    "Dat03"+":r="+str(round(Dat03cor[0],3))]

# 描画領域の生成
fig = plt.figure(figsize=(18, 5))
fig.subplots_adjust(wspace=0.3, hspace=0.4) # 横のグラフ同士の幅、縦のグラフ同士の幅

# for文を利用して、4つのグラフを描画
for i in range(0, len(x)):
    plt.subplot(1,3,i+1)
    plt.scatter(x[i], y[i],   # 横軸、縦軸の値
            s=30,               # マーカサイズ
            c=col[i],         # マーカの色(red, blue, pink, yellow, orange, blackなど)
            marker='s',         #マーカの形(.osなど:下記参照)
            alpha=0.8,          # 塗りつぶしの透明度(0:完全に透明〜1:透明にしない)
            linewidths=0.5,     # マーカの線の太さ
            edgecolors='black') # マーカの線の太さ(マーカの色と同じ。不要の場合は''なしでNone)

    plt.title(figtitle[i], fontsize=20)  # タイトル
    plt.xlabel("x axis", fontsize=20) # 軸名
    plt.ylabel("y axis", fontsize=20) #軸名
    plt.grid(True)      #グリッド線(True:引く、False:引かない)
    plt.xlim(0, 2)  # 横軸最小最大
    plt.ylim(0, 2)  # 縦軸最小最大

plt.show()

意味のない相関係数に踊らさないために

相関係数が高いと「おっ、この2つの変数には関係がありそうだ!大発見かもしれない!論文化しよう!!!」と思うことがあります。例えば「ある食べ物の摂取量と病気の発生率」に相関があったとして、今まで誰も明らかにしていなかった場合、かなりの大発見です。しかし、相関関係がないのにも関わらず、相関係数が高い値を出してくることがあります。この例を以下に示します。

In [10]:
# 無相関であるDat03に対して、外れ値データを添加
Dat04=np.concatenate([Dat03, np.array([[-3, -3]])], 0)

x = Dat04[:,0]
y = Dat04[:,1]

plt.figure(figsize=(5, 4)) # figureの縦横の大きさ

plt.scatter(x, y,           # 横軸、縦軸の値
        s=30,               # マーカサイズ
        c='orange',         # マーカの色(red, blue, pink, yellow, orange, blackなど)
        marker='s',         #マーカの形(.osなど:下記参照)
        alpha=0.8,          # 塗りつぶしの透明度(0:完全に透明〜1:透明にしない)
        linewidths=0.5,     # マーカの線の太さ
        edgecolors='black') # マーカの線の太さ(マーカの色と同じ。不要の場合は''なしでNone)

plt.title("Title")  # タイトル
plt.xlabel("x axis") # 軸名
plt.ylabel("y axis") #軸名
plt.grid(True)      #グリッド線(True:引く、False:引かない)
plt.xlim(-4, 2.5)  # 横軸最小最大
plt.ylim(-4, 2.5)  # 縦軸最小最大

plt.show() # グラフの表示

無相関であったDat03に対し、外れ値となるデータを1つ添加してみました。かなり怪しいデータです。計測器のミスなどが考えられますね。とりあえず相関係数を計算してみます。

In [11]:
Dat04cor = st.pearsonr(Dat04[:,0], Dat04[:,1])
print("Dat04の相関係数: ", round(Dat04cor[0], 3), ", p値:", round(Dat04cor[1], 5))
Dat04の相関係数:  0.476 , p値: 0.0

正相関で、係数も高いし、p値も低いです。したがってこの結果は、統計的に有意に正相関が生じていることになります。しかし、その実態は「無相関であったDat03に1つだけ外れ値を加えてみたデータ」です。散布図を見ると、確かに右肩上がりのように見えてしまいますが、それは外れ値1点を原因としています。このようなデータは、外れ値として分析から除外することが普通です。ただし、当たり前のことですが、意図的に相関関係を出したいがゆえに、不都合なデータを削除することは絶対にやってはいけない行為です。研究倫理違反として、学生の皆さんは、かなり厳しく罰せられます。外れ値かもしれないデータを見つけたとき、分析に慣れていないうちは、教員に相談して下さい。

話が長くなりましたが、外れ値のせいで相関関係がないのにもかかわらず、相関係数がそれっぽい値を出してくることもありますので、基本的には散布図を目で見て、係数が正しそうか確認して下さい。外れ値を自動検出する統計的なアプローチもありますので、興味がある人は調べて見て下さい。