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$の間に関係性がないことを意味するわけではない

icon-pc 練習:相関係数

プロ野球球団の選手の身長(cm)、体重(kg)、年齢、推定年俸(万円)などのデータがプロ野球データFreakで公開されている。それを元に、2015年のある球団について、

身長(cm)  体重(kg)  年齢  推定年俸(万円)

の数値を並べたファイルをこちらに用意した。 このファイル(rakuten.txt)を読み込み、 W:身長 X:体重 Y:年齢 Z:年俸 としたとき、年俸との相関係数($R_{WZ}, R_{XZ}, R_{YZ}$)を計算するプログラムを作成せよ。

なお、年俸は、他の変量と較べて、選手(働き)によって桁が違ってくるような量である。 すなわち、金額そのものよりも、その「桁」のほうに注目するのが自然であろう。 そのような観点から、年俸については、math.log()関数を使い、金額の対数を変量とした解析を行うこと。

年俸と最も相関が強いと考えられるのは、身長か、体重か、年齢か?

icon-hint ヒント

データを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])

といった書き換えが必要となる。


icon-teacher 解説: 疑似相関

$X$と$Y$の相関係数が大きいからと言って、$X$と$Y$の間に直接的な因果関係があるとは限らない。 たとえば、Spurious Correlationsのサイトには、 疑似相関の例がいくつも紹介されている。

例えば、第三の(隠れた)要因$Z$があって、$X, Y$が共に$Z$に影響されているような場合、$X$と$Y$の間に強い相関が見られる可能性がある。