Blog

Pythonで「データ解析のための統計モデリング入門」:第3章

Pythonで緑本の演習をしていきます。前記事はこちら

第3章、説明変数をくみこんだ統計モデルについてです。

 

第3章 一般化線形モデル(GLM)

第2章で使用したサンプルデータは、架空の植物50個体からなる集団を調査して得られた各個体の種子数を数えたものでした。このデータで、個体ごとに異なる説明変数(個体の属性)によって平均種子数が変化する統計モデルを観測データにあてはめることを、一般化線形モデル(GLM)と言います。

第3章では、一般化線形モデルの中のポアソン回帰を実施します。

 

3.1 例題:個体ごとに平均種子数が異なる場合

第3章の例題では、架空の植物100個体を調査して得られた、個体ごとの種子数のデータを用います。植物個体iの種子数は ( y_{i} ) 個であり、個体の属性のひとつである体サイズ ( x_{i} ) が観測されているとします。また、全個体のうち50個体は何も処理をしておらず、残り50個体には肥料を加える処理(処理T)をほどこしているとします。

 

3.2 観測されたデータの概要を調べる

サンプルデータ(csvファイル)はこちらからダウンロードできます。pandasのread_csvを使ってDataFrame形式で読み込みます。

# -*- coding:utf-8 -*-
"""
kubo_3.py
"""

from __future__ import division, print_function, absolute_import, unicode_literals
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats

d = pd.read_csv('data/data3a.csv')

print(d)

     y      x  f
0    6   8.31  C
1    6   9.44  C
2    6   9.50  C
3   12   9.07  C
4   10  10.16  C
5    4   8.32  C
6    9  10.61  C
7    9  10.06  C
8    9   9.93  C
9   11  10.43  C
..  ..    ... ..
90   6  11.20  T
91   5   9.86  T
92   8  11.54  T
93   5  10.03  T
94   9  11.88  T
95   8   9.15  T
96   6   8.52  T
97   8  10.24  T
98   7  10.86  T
99   9   9.97  T

dの列ごとにデータを表示させてみます。

print(d.x)

0      8.31
1      9.44
2      9.50
3      9.07
4     10.16
5      8.32
6     10.61
7     10.06
8      9.93
9     10.43
      ...  
90    11.20
91     9.86
92    11.54
93    10.03
94    11.88
95     9.15
96     8.52
97    10.24
98    10.86
99     9.97

print(d.y)

0      6
1      6
2      6
3     12
4     10
5      4
6      9
7      9
8      9
9     11
      ..
90     6
91     5
92     8
93     5
94     9
95     8
96     6
97     8
98     7
99     9

print(d.f)

0 C
1 C
2 C
3 C
4 C
5 C
6 C
7 C
8 C
9 C
 ..
90 T
91 T
92 T
93 T
94 T
95 T
96 T
97 T
98 T
99 T

pandasのinfo()メソッドで各列のデータの型について知ることができます。

print(d.info())

<class 'pandas.core.frame.DataFrame'>
Int64Index: 100 entries, 0 to 99
Data columns (total 3 columns):
y    100 non-null int64
x    100 non-null float64
f    100 non-null object
dtypes: float64(1), int64(1), object(1)
memory usage: 3.1+ KB

describe()メソッドでデータの概要を示します。

print(d.describe())

                y           x
count  100.000000  100.000000
mean     7.830000   10.089100
std      2.624881    1.008049
min      2.000000    7.190000
25%      6.000000    9.427500
50%      8.000000   10.155000
75%     10.000000   10.685000
max     15.000000   12.400000


print(d.f.describe())

count     100
unique      2
top         T
freq       50
Name: f, dtype: object

value_counts()メソッドで ( f )\ の要素の数を得られます。

print(d.f.value_counts())

T    50
C    50
Name: f, dtype: int64

 

3.3 統計モデリングの前にデータを図示する

まずは観測データに余計な手を加えないで、データ全体を見てみます。

横軸に ( x ) 列、縦軸に ( y ) 列をとった散布図をプロットします。

pandasのプロット機能を使っても良いかと思ったのですが(簡単に書ける場合が多い)、後々複雑なプロットをしたいと思った時を考えて、はじめからmatplotlibでいきます。

fig = plt.figure()
ax = fig.add_subplot(111)

ax.scatter(d.x[d.f=='C'], d.y[d.f=='C'], label='C', facecolors='none')
ax.scatter(d.x[d.f=='T'], d.y[d.f=='T'], label='T')
ax.legend(loc='upper left')

fig.savefig('scatter.png')
plt.close(fig)

scatter

次に、横軸を施肥処理、縦軸に ( y ) 列をとった箱ひげ図をプロットします。

fig = plt.figure()
ax = fig.add_subplot(111)

ax.boxplot([d.y[d.f=='C'], d.y[d.f=='T']], labels=['C', 'T'])

fig.savefig('box_plot.png')
plt.close(fig)

box_plot

 

3.4 ポアソン回帰の統計モデル

個体ごとの平均種子数 ( \lambda_{i} ) が体サイズ ( x ) や施肥処理 ( f ) に影響されるようなモデルを設計します。

まず、個体 ( i ) の体サイズ ( x_{i} ) だけに依存する統計モデルについて考えます。切片 ( \beta_{1} ) 、 傾き ( \beta_{2} ) の関係を図示すると次のようになります。

x = np.arange(-4, 4, 0.01)

fig = plt.figure()
ax = fig.add_subplot(111)

ax.plot(x, np.exp(-1 + 0.4 * x), label='{-1, 0.4}')
ax.plot(x, np.exp(-2 + -0.8 * x), label='{-2, 0.8}')
ax.legend(title='{B1, B2}')
ax.set_ylim(0, 2.8)
ax.set_xlabel('body size x_i of i')
ax.set_ylabel('lambda_i of i')

fig.savefig('test.png')
plt.close(fig)

test

 

3.4.2 あてはめとあてはまりの良さ

ポアソン回帰とは、観測データに対するポアソン分布を使った統計モデルのあてはめであり、この統計モデルの対数尤度 ( \log L ) が最大になるパラメータ ( \hat{\beta}{1} ) と ( \hat{\beta}{2} ) の推定値を決めることです。

 Rではglm()関数を使うことで手軽にGLMのあてはめができます。pythonでやる方法をググッてみたら、scikit-learnやstatsmodelsというモジュールが有名なようです。statsmodelsはRライクに使えるとのことで、ここではstatsmodelでやってみます。

調べてみると、Statsmodelsには通常の関数型呼び出しに対応するAPIと、R-styleのモデル式を用いる数式対応API(formula API)の2種類が実装されているとのことでした。

Statsmodels formula API と多項式回帰モデル

以下のようにして切片 \( \hat{\beta}_{1} \) と \( \hat{\beta}_{2} \) の推定値を求めてみました。GLMはformula APIで実行し、ポアソン分布の指定に通常のAPIを使っています。Rのように、formulaの指定を’従属変数 ~ 説明変数’という風に指定できました。

import statsmodels.api as sm
import statsmodels.formula.api as smf 

fit = smf.glm(formula='y ~ x', data=d, family=sm.families.Poisson())

print(fit.fit().summary())
                 Generalized Linear Model Regression Results                  
==============================================================================
Dep. Variable:                      y   No. Observations:                  100
Model:                            GLM   Df Residuals:                       98
Model Family:                 Poisson   Df Model:                            1
Link Function:                    log   Scale:                             1.0
Method:                          IRLS   Log-Likelihood:                -235.39
Date:                Tue, 10 May 2016   Deviance:                       84.993
Time:                        18:18:59   Pearson chi2:                     83.8
No. Iterations:                     7                                         
==============================================================================
                 coef    std err          z      P>|z|      [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept      1.2917      0.364      3.552      0.000         0.579     2.005
x              0.0757      0.036      2.125      0.034         0.006     0.145
==============================================================================

 

3.4.3 ポアソン回帰モデルによる予測

次に、このポアソン回帰の推定結果を使って、様々な体サイズ ( x ) における平均種子数 ( \lambda ) の予測を行います。

 \[ \lambda = \exp (1.29 + 0.0757 x) \]

これを図示します。

fig = plt.figure()
ax = fig.add_subplot(111)

ax.scatter(d.x[d.f=='C'], d.y[d.f=='C'], label='C', facecolors='none')
ax.scatter(d.x[d.f=='T'], d.y[d.f=='T'], label='T')

xx = np.arange(min(d.x), max(d.x), (max(d.x) - min(d.x)) / 100)
ax.plot(xx, np.exp(1.29 + 0.0757 * xx))

ax.set_xlabel('d.x')
ax.set_ylabel('d.y')
ax.legend(loc='upper left')

fig.savefig('predict.png')
plt.close(fig)

predict

 

3.5 説明変数が因子型の統計モデル

施肥効果 ( f_{i} ) を説明変数としてくみこんだモデルも検討します。施肥処理は因子型、カテゴリ型のデータとして格納されています。

Pythonで推定を行います。因子型の説明変数であっても、簡単にモデル式を指定できます。

import statsmodels.api as sm
import statsmodels.formula.api as smf 

fit = smf.glm(formula='y ~ f', data=d, family=sm.families.Poisson())

print(fit.fit().summary())
                 Generalized Linear Model Regression Results                  
==============================================================================
Dep. Variable:                      y   No. Observations:                  100
Model:                            GLM   Df Residuals:                       98
Model Family:                 Poisson   Df Model:                            1
Link Function:                    log   Scale:                             1.0
Method:                          IRLS   Log-Likelihood:                -237.63
Date:                Tue, 10 May 2016   Deviance:                       89.475
Time:                        19:19:42   Pearson chi2:                     87.1
No. Iterations:                     7                                         
==============================================================================
                 coef    std err          z      P>|z|      [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept      2.0516      0.051     40.463      0.000         1.952     2.151
f[T.T]         0.0128      0.071      0.179      0.858        -0.127     0.153
==============================================================================

 

3.6 説明変数が数量型 + 因子型の統計モデル

個体の体サイズ ( x_{i} ) と施肥効果 ( f_{i} ) の複数の説明変数を同時にくみこんだ統計モデルを作ってみます。

statsmodelでは、モデル式の部分をx + fとするだけで適切に処理してくれます。

import statsmodels.api as sm
import statsmodels.formula.api as smf 

fit = smf.glm(formula='y ~ x + f', data=d, family=sm.families.Poisson())

print(fit.fit().summary())
                 Generalized Linear Model Regression Results                  
==============================================================================
Dep. Variable:                      y   No. Observations:                  100
Model:                            GLM   Df Residuals:                       97
Model Family:                 Poisson   Df Model:                            2
Link Function:                    log   Scale:                             1.0
Method:                          IRLS   Log-Likelihood:                -235.29
Date:                Wed, 11 May 2016   Deviance:                       84.808
Time:                        13:32:13   Pearson chi2:                     83.8
No. Iterations:                     7                                         
==============================================================================
                 coef    std err          z      P>|z|      [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept      1.2631      0.370      3.417      0.001         0.539     1.988
f[T.T]        -0.0320      0.074     -0.430      0.667        -0.178     0.114
x              0.0801      0.037      2.162      0.031         0.007     0.153
==============================================================================

 

This Post Has 0 Comments

Leave A Reply