本節では、データ分析の基礎となる相関係数による分析を扱います。このコードを勉強する前に、まず相関係数とは何か、調べてみて下さい。最小値、最大値、マイナス・プラスのときの解釈方法、0付近の解釈、少なくとも、これらは答えられるようになってからやってみましょう。なお、実際は実データを用いて分析を行いますが、今回は練習ですので、乱数を使用します。まず、おまじないとして以下のコードを実行してください。
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の散布図を描画してみます。
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で定義されている関数を使います。
import scipy.stats as st
Dat01cor = st.pearsonr(Dat01[:,0], Dat01[:,1])
print(Dat01cor)
数字が2つ出てきました。左側が相関係数、右側がそのp値となります。p値が0.05未満のとき、統計的に意味のある相関であるということを意味しています(詳細を知りたい人は、無相関検定で調べてみて下さい)。なので、以下のように記載すれば良いです。
Dat01cor[0]
print("Dat01の相関係数: ", Dat01cor[0], ", p値:", Dat01cor[1])
正相関が生じそうな具体例は、
といった感じでしょうか。相関係数が正方向に高いと「これが高いとあれも高い、これが低いとあれも低い」という関係を示唆するということがわかります。あと少しややこしい話ですが、相関関係は因果関係を保証しません。より簡単にいうと、相関係数が高い場合は「これを高めるとあれも高まる」という可能性があることを意味すれど、それが保証されるわけではありません。考察のときには注意して下さい(詳しくは、「相関関係と因果関係の違い」などで検索して自分で調べて下さい)。
ところで、小数点以下が多すぎ!と思ったりしませんか。このような場合に小数点以下を指定の桁数できるには、round関数を使います。
print("Dat01の相関係数: ", round(Dat01cor[0], 3), ", p値:", round(Dat01cor[1], 5))
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つのデータすべての相関係数を出してみましょう。
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は正方向に値が大きいので右肩上がり、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です。
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です。
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つの変数には関係がありそうだ!大発見かもしれない!論文化しよう!!!」と思うことがあります。例えば「ある食べ物の摂取量と病気の発生率」に相関があったとして、今まで誰も明らかにしていなかった場合、かなりの大発見です。しかし、相関関係がないのにも関わらず、相関係数が高い値を出してくることがあります。この例を以下に示します。
# 無相関である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つ添加してみました。かなり怪しいデータです。計測器のミスなどが考えられますね。とりあえず相関係数を計算してみます。
Dat04cor = st.pearsonr(Dat04[:,0], Dat04[:,1])
print("Dat04の相関係数: ", round(Dat04cor[0], 3), ", p値:", round(Dat04cor[1], 5))
正相関で、係数も高いし、p値も低いです。したがってこの結果は、統計的に有意に正相関が生じていることになります。しかし、その実態は「無相関であったDat03に1つだけ外れ値を加えてみたデータ」です。散布図を見ると、確かに右肩上がりのように見えてしまいますが、それは外れ値1点を原因としています。このようなデータは、外れ値として分析から除外することが普通です。ただし、当たり前のことですが、意図的に相関関係を出したいがゆえに、不都合なデータを削除することは絶対にやってはいけない行為です。研究倫理違反として、学生の皆さんは、かなり厳しく罰せられます。外れ値かもしれないデータを見つけたとき、分析に慣れていないうちは、教員に相談して下さい。
話が長くなりましたが、外れ値のせいで相関関係がないのにもかかわらず、相関係数がそれっぽい値を出してくることもありますので、基本的には散布図を目で見て、係数が正しそうか確認して下さい。外れ値を自動検出する統計的なアプローチもありますので、興味がある人は調べて見て下さい。