pythonで回帰分析の練習

#pythonで回帰分析の練習
##環境
Windows8
Python 3.6.3 

##概要
普段、私が読んでいる統計学の本の練習と
最近、勉強し始めたpythonの復習のために散布図作って回帰分析の練習をやる事にしました。

ちなみに、読んでいる本はこちらになります。
[心理統計学の基礎]
(https://www.amazon.co.jp/%E5%BF%83%E7%90%86%E7%B5%B1%E8%A8%88%E5%AD%A6%E3%81%AE%E5%9F%BA%E7%A4%8E%E2%80%95%E7%B5%B1%E5%90%88%E7%9A%84%E7%90%86%E8%A7%A3%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AB-%E6%9C%89%E6%96%90%E9%96%A3%E3%82%A2%E3%83%AB%E3%83%9E-%E5%8D%97%E9%A2%A8%E5%8E%9F-%E6%9C%9D%E5%92%8C/dp/4641121605/ref=sr_1_1?ie=UTF8&qid=1519540568&sr=8-1&keywords=%E5%BF%83%E7%90%86%E7%B5%B1%E8%A8%88%E5%AD%A6%E3%81%AE%E5%9F%BA%E7%A4%8E)

### データ元
[e-Stat政府統計の総合窓口]
(https://www.e-stat.go.jp/)より生命表を使います。
生命表には、人間が1年以内に死亡する確立、生存数など生命に関連する情報が乗ってあります。
e-Stat政府統計の総合窓口には、生命表以外にも色々なデータがあって面白いので気になったら見てみてください。

### 回帰分析の練習をする
今回は、x軸に年齢　y軸に生存数を使った散布図を作り
回帰直線をひいて見たいと思います。

#### csvデータを抽出
csvに記載されているデータをpythonで使うために抽出します。
書いたのが以下のコードです。

```python:csvデータを抽出
def csv_read(file_path):

    try:
        with open(file_path, 'rt') as fin:
            # csvを読み込む
            cin = csv.reader(fin)
            # ヘッダ―分読み飛ばし
            next(cin)
            survivor = [i[1] for i in cin]

            # int型にして返却
            return list(map(int, survivor))
    except:
        print("エラー発生。プログラム終了。")
        sys.exit()
```
csvを読み込んでデータを抽出し
リスト内包表記を使って生存者の数をsurvivor詰め込んでいます。
読み取ってきたデータがstringなのでintに変換して返却します。

ちなみに年齢は別にcsvデータから取得せずrange関数を使ったら作れるので、ここでは取っていません。

#### グラフの描画
生存数のデータが取得できたのでグラフを作成していきます。
書いたのが以下のコードです。

```python:グラフを描画
def create_graph(female_survivor, male_survivor, age):

    # 描画要素の作成をする
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)

    # グラフを描画する際に日本語を使用できるようにする
    fp = FontProperties(fname='C:\WINDOWS\Fonts\msgothic.ttc', size=14)

    # 女性の点をプロット
    ax.scatter(age, female_survivor,  c='red', label='female')
    # 男性の点をプロット
    ax.scatter(age, male_survivor, c='blue', label='male')
    # 女性の回帰直線を赤色でプロット
    ax.plot(age, np.poly1d(np.polyfit(age, female_survivor, 1))
            (age), color="red", label='predicted_female')
    # 男性の回帰直線を青色でプロット
    ax.plot(age, np.poly1d(np.polyfit(age, male_survivor, 1))
            (age), color="blue", label='predicted_female')

    # 描画する際に表示するタイトルの設定
    ax.set_title('年齢と生存数', fontproperties=fp)
    ax.set_xlabel('年齢', fontproperties=fp)
    ax.set_ylabel('生存数', fontproperties=fp)

    # グラフにグリッドを表示する
    ax.grid(True)
    # グラフにラベルを表示する
    ax.legend()

    # 実際に描画する
    plt.show()
```

female_survivorが女性の生存数リスト
male_survivorが男性の生存数リスト
ageが年齢リストです。
ちなみに、フォントの設定をして日本語を使用できるようにしないと文字がバグって悲惨なことになります。注意しましょう。


#### 出力された散布図
今回出力された散布図は、女性を赤色にし男性を青色にして区別しています。
よく耳にする「女性の方が長生きしやすい」という事が本当なのかグラフ化して確かめてみます。

![Figure_1-1.png](https://qiita-image-store.s3.amazonaws.com/0/195114/122a6f35-a55e-07ec-6c04-ca7700c30273.png)

変化が激しくなるのは６０代を過ぎたあたりからです。
男性が８０歳の時には約６００００人の生存者がいるのに対して
女性が８０歳の時には約８００００人の生存者がいます。
やはり、女性の方が長生きしやすいようです。

相関係数と回帰係数は以下のようになりました。

相関係数（女）：-0.741760884805
相関係数（男）：-0.814598029803
回帰係数（女）：-602.029784508
回帰係数（男）：-823.917623762

女性の相関係数と男性の相関係数が±0.7~±0.9の間にあるので年齢と生存数には、強い負の相関がある（当たり前ですが）と言えます。

回帰係数をみてみます。
女性の場合、年齢１歳の差異に対応し、生存数の予測値は-602異なります。
つまり回帰係数から１年ごとに約602人が亡くなるという事が読み取れます。
男性の場合は、１年ごとに約823人が亡くなっています。


#### グラフを拡大してみる
興味本位で先ほど表示したグラフを０歳から６歳にしぼって拡大してみました。
![Figure_3.png](https://qiita-image-store.s3.amazonaws.com/0/195114/5f114e42-9ac2-9477-e10c-c0d156a110e9.png)
わずかでは、ありますが幼い頃から男性と女性で差はあるようです。
この差に関して、ホルモンの働きが関係しているとか男性の方が基礎代謝が低いとか色々言われていますが今回の分析では、そこまでやりません。


#### 選抜してグラフを再描画してみた
６０歳から１００歳の人を選抜して先ほどと同じ過程でグラフを再描画してみました。


![Figure_2.png](https://qiita-image-store.s3.amazonaws.com/0/195114/c9d980a5-143c-17bd-e618-4be8703b195c.png)

相関係数と回帰係数は以下のようになりました。

相関係数（女）：-0.933679933164
相関係数（男）：-0.980302085323
回帰係数（女）：-2250.67299652
回帰係数（男）：-2593.171777

６０歳を超えたらより相関係数は高くなり女性の相関係数と男性の相関係数は9を超えました。ほぼ完全な負の相関があると言えます。
このように選抜して相関係数が変わることを選抜効果といいます。

回帰係数は若者の分が減ったので大きく増加しています。
女性は１年で約2250人が亡くなり男性は約2593人が亡くなっています。

### コード
グラフ描画で日本語を使う時に何をimportしていたか、相関係数の求め方、回帰係数の求め方など、忘れそうなので載せる事にしました。

```python:コード
import csv
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties


def csv_read(file_path):

    try:
        with open(file_path, 'rt') as fin:
            # csvを読み込む
            cin = csv.reader(fin)
            # ヘッダ―分読み飛ばし
            next(cin)
            survivor = [i[1] for i in cin]

            # int型にして返却
            return list(map(int, survivor))
    except:
        print("エラー発生。プログラム終了。")
        sys.exit()


def create_graph(female_survivor, male_survivor, age):

    # 描画要素の作成をする
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)

    # グラフを描画する際に日本語を使用できるようにする
    fp = FontProperties(fname='C:\WINDOWS\Fonts\msgothic.ttc', size=14)

    # 女性の生存数を赤色でプロット
    ax.scatter(age, female_survivor,  c='red', label='female')
    # 男性の生存数を青色でプロット
    ax.scatter(age, male_survivor, c='blue', label='male')
    # 女性の回帰直線を赤色でプロット
    ax.plot(age, np.poly1d(np.polyfit(age, female_survivor, 1))
            (age), color="red", label='predicted_female')
    # 男性の回帰直線を青色でプロット
    ax.plot(age, np.poly1d(np.polyfit(age, male_survivor, 1))
            (age), color="blue", label='predicted_female')

    # 描画する際に表示するタイトルの設定
    ax.set_title('年齢と生存数', fontproperties=fp)
    ax.set_xlabel('年齢', fontproperties=fp)
    ax.set_ylabel('生存数', fontproperties=fp)

    # グラフにグリッドを表示する
    ax.grid(True)
    # グラフにラベルを表示する
    ax.legend()

    # 実際に描画する
    plt.show()


def main():
    # csvデータを取り込み(女の生存数)
    female_survivor = csv_read('./data/22nd-lifetable-female.csv')
    # csvデータを取り込む(男の生存数)
    male_survivor = csv_read('./data/22nd-lifetable-male.csv')

    # 年齢を取り込む(0歳から100歳まで)
    age = list(range(0, 101))

    # 相関係数を求める
    print("femaleの相関係数：", np.corrcoef(age, female_survivor)[0][1])
    print("maleの相関係数：",  np.corrcoef(age, male_survivor)[0][1])
    # 回帰係数を求める
    print("femaleの回帰係数：", np.polyfit(age, female_survivor, 1)[0])
    print("maleの回帰係数：", np.polyfit(age, male_survivor, 1)[0])

    # グラフを作成する
    create_graph(female_survivor, male_survivor, age)


if __name__ == '__main__':
    main()

```


### 最後に
これからは、Qiitaに統計関係の事やグラフ作成の事をドンドン、アウトプットしていきたいと思います。
このように形に残る事は自分の自身に多少でもつながると思うので良いと思うのです。