Pythonプログラミング(ステップ7・統計計算・ファイル入力と相関係数)
このページでは、Pythonを使った基本的な統計計算の方法について考える。
ファイルからデータを読み込んでリストにセットする
コンピュータに統計処理を行わせる場合、プログラムの中に数値データを書き込んでしまうよりは、 データを別ファイルに保存しておいて、プログラムはその内容を読んで、結果を出力する、といった流れのほうが何かと便利だ。 例えば、1万件のデータを処理しなければならない場合、エディタを使ってプログラムにそれを書き込むだけで、相当な手間になるはずだ。 ここでは、データファイルの形式として、データ1件分(1レコード)が1行ごとに、以下のように並んでいる場合を考えよう。
身長と体重データの例
ダウンロード
186 87 180 76 175 67 178 78 174 74 185 86
このデータが、height-vs-weight.txt
というファイル名で、Pythonプログラムと同じディレクトリ(フォルダ)に保存されていると想定する。
以下は、そこからデータを読み出して、値をリストにセットするプログラムの例である:
# coding: utf-8 file=open("height-vs-weight.txt") lines=file.readlines() file.close() x_vs_y=[ ] for i in range(0,len(lines),1): x,y=map(float,lines[i].split()) print("i=",i," x=",x," y=",y) x_vs_y.append([x,y])
このプログラム中に登場した新しい記法や関数について、以下で説明する:
file=open("height-vs-weight.txt")
- open("ファイル名")でファイルを開き、「ファイルについての情報」を変数fileにセットする。
lines=file.readlines()
- ファイルからデータを読み込み、リストを作成し、linesにセットする。リストの0番目がファイルの1行目, 1番目が2行目・・・、にそれぞれ対応している。
file.close()
- データを読み込んだので、ファイルを「閉じる。」
x_vs_y=[ ]
- 数値データを保存するため、空のリストを用意する。
x,y=map(float,lines[i].split())
-
ファイルのi番目の行を実数値に変換して、それぞれ変数x,yにセットする。
キーボード入力
x,y=map(float,input().split())
と同じパターン。
x_vs_y.append([x,y])
-
リストの末尾に
[x,y]
というリストを追加する。
以上の手順でデータを読み込むと、(0番目から始めて)i番目のデータのxはx_vs_y[i][0]
、yはx_vs_y[i][1]
で参照できる。身長(x)と体重(y)の平均をそれぞれ計算するコードの例を以下に示す。
# coding: utf-8 file=open("height-vs-weight.txt") lines=file.readlines() file.close() x_vs_y=[ ] n=0 for i in range(0,len(lines),1): x,y=map(float,lines[i].split()) print("i=",i," x=",x," y=",y) x_vs_y.append([x,y]) n=n+1 s_x=0 s_y=0 for i in range(0,n,1): s_x = s_x + x_vs_y[i][0] s_y = s_y + x_vs_y[i][1] mu_x=s_x/n mu_y=s_y/n print("身長の平均=",mu_x," 体重の平均=",mu_y)
データ間の関係性を調べる:相関係数
二つの量$X$と$Y$の間の関係性を特徴づける量として、相関係数(さらに詳しくは、ここで述べるのはピアソンの相関係数)が広く使われている。 $n$ 点のデータのペア $(x_i,y_i)$ (ただし、$n=0,1,\cdots,n-1$)が与えられたとして、それぞれの平均 $$ E(X) = \frac{1}{n} \sum_{i=0}^{n-1} x_i,\ \ \ E(Y) = \frac{1}{n} \sum_{i=0}^{n-1} y_i $$ および、二乗平均 $$ E(XX) = \frac{1}{n} \sum_{i=0}^{n-1} {x_i}^2,\ \ \ E(YY) = \frac{1}{n} \sum_{i=0}^{n-1} {y_i}^2 $$ を求める。これらを用いると、$X$と$Y$の分散は $$ V_X = E(XX) - E(X)^2 ,\ \ \ V_Y = E(YY) - E(Y)^2 , $$ となる。
同様に、$X$と$Y$の積の平均 $$ E(XY) = \frac{1}{n} \sum_{i=0}^{n-1} x_i y_i $$ から、共分散(covariance) $$ V_{XY} = E(XY) - E(X) E(Y) $$ が得られる。共分散を分散で規格化した量が相関係数で、 $$ r = \frac{V_{XY}}{\sqrt{V_X V_Y}} $$ で与えられる。相関係数は $-1 \le r \le +1$ の値を取る。
横軸と縦軸のスケールをデータのばらつきに合わせ調整した上で、$X$, $Y$を散布図で表現した際に、点が斜め上45度方向の直線に沿って分布すると$r$は1に近く、 右下がり45度方向の直線に沿って分布すると$r$は-1に近い値を取る。 反対に、$r$が0に近い場合は、$X$が増えても$Y$は同じようには(直線的には)増えない、という状況に対応しているが、 このことは、必ずしも$X$と$Y$の間に関係性がないことを意味するわけではない。
練習:相関係数
プロ野球球団の選手の身長(cm)、体重(kg)、年齢、推定年俸(万円)などのデータがプロ野球データFreakで公開されている。それを元に、2015年のある球団について、
身長(cm) 体重(kg) 年齢 推定年俸(万円)
の数値を並べたファイルをこちらに用意した。 このファイル(rakuten.txt)を読み込み、 W:身長 X:体重 Y:年齢 Z:年俸 としたとき、年俸との相関係数($R_{WZ}, R_{XZ}, R_{YZ}$)を計算するプログラムを作成せよ。
なお、年俸は、他の変量と較べて、選手(働き)によって桁が違ってくるような量である。
すなわち、金額そのものよりも、その「桁」のほうに注目するのが自然であろう。
そのような観点から、年俸については、math.log()
関数を使い、金額の対数を変量とした解析を行うこと。
年俸と最も相関が強いと考えられるのは、身長か、体重か、年齢か?
ヒント
データを4件ずつ読み込むためには、このページで示したサンプルプログラムの中で
wxyz=[ ] for i in range(0,len(lines),1): w,x,y,z=map(float,lines[i].split()) xxyz.append([w,x,y,z])
といった書き換えが必要となる。
解説: 疑似相関
$X$と$Y$の相関係数が大きいからと言って、$X$と$Y$の間に直接的な因果関係があるとは限らない。 たとえば、Spurious Correlationsのサイトには、 疑似相関の例がいくつも紹介されている。
例えば、第三の(隠れた)要因$Z$があって、$X, Y$が共に$Z$に影響されているような場合、$X$と$Y$の間に強い相関が見られる可能性がある。