Lesson7: Regression まとめ Intro to Machine learning@Udacity

#概要
今までのレッスンで学んできたのは、すべてアウトプットが離散的(2値)だったが、数値を推定するものを回帰という。例えば、年齢から、年収を予測するようなもの。
下記の図の、赤い丸から直線を引くこと。
![regression.jpg](https://qiita-image-store.s3.amazonaws.com/0/333380/59cf643a-7d37-24ec-4d86-710c06c45a89.jpeg)
Slope:直線の傾き
Intercept：切片

#Coding it up!
上記のage-net worth問題を回帰で解く。
このプログラミングはUdacityに埋め込んであるpythonで、ブラウザで行う。ちなみにpython2系です。

```python:studentMain.py
import numpy
import matplotlib
matplotlib.use('agg')

import matplotlib.pyplot as plt
from studentRegression import studentReg
from class_vis import prettyPicture, output_image
from ages_net_worths import ageNetWorthData

ages_train, ages_test, net_worths_train, net_worths_test = ageNetWorthData()

reg = studentReg(ages_train, net_worths_train)#studentReg()にてregression

plt.clf()
plt.scatter(ages_train, net_worths_train, color="b", label="train data")
plt.scatter(ages_test, net_worths_test, color="r", label="test data")
plt.plot(ages_test, reg.predict(ages_test), color="black")
plt.legend(loc=2)
plt.xlabel("ages")
plt.ylabel("net worths")

plt.savefig("test.png")
output_image("test.png", "png", open("test.png", "rb").read())

```

```python:studentRegression.py

def studentReg(ages_train, net_worths_train):
    ### import the sklearn regression module, create, and train your regression
    ### name your regression reg
    ### your code goes here!
    from sklearn import datasets, linear_model
    reg = linear_model.LinearRegression()
    reg.fit(ages_train, net_worths_train)
    
    return reg
```
＜出力＞
![regression_quiz.png](https://qiita-image-store.s3.amazonaws.com/0/333380/9b7315a8-e165-3688-3f22-5e67ceeead5f.png)

青い点がトレーニングデータで、赤い点がテストデータ。linear regression(線形回帰)が引いた線が、直線。いい感じにひけてますねー。テストデータはトレーニングデータで引いた回帰式が、どのくらい正しいか評価するのに使う(reg.score())。テストデータでスコアが低いと、過学習しているということ。

###よく使うAttributesとmethodsの紹介
<Attributes>
.coef_　:　回帰式の係数出力
.intercept_ : 切片を出力
<methods>
.score(ages_test, Net_worths_tests) : テストデータでの精度出す。
.score(ages_train, net_worths_train) : トレーニングデータでの精度出して、テストデータと比べ、過学習か判定する。

##回帰式の評価の仕方
どうやって回帰式：y = ax + b のa,bを決めているかというと、

```math
\sum_{全トレーニングデータ} (トレーニングポイント-推定値)  

```
を最小化しているみたい。
最小化する方法はいくつかあって、有名なのは
・Ordinary Least Squares(OLS)：最小二乗回帰
・Gradient descent：最急降下法

###最小二乗法：Ordinary Least Squares(OLS)
最小二乗法の場合、実際にどうやって回帰式を求めているのかは
[最小二乗法の意味と計算方法 - 回帰直線の求め方](https://sci-pursuit.com/math/statistics/least-square-method.html)がわかりやすかった。

下記引用（数式かくの面倒だったので、スクリーンショト画像です）
![数式.png](https://qiita-image-store.s3.amazonaws.com/0/333380/796f5980-e306-ec0e-bb31-b1038ec9997e.png)
詳しくは上記リンク先参照。

なぜ誤差の計算の仕方が「絶対値の引き算」ではなく「二乗の引き算」なのかは、下記図参照。二乗しないと収束しないんですね。

![regression.png](https://qiita-image-store.s3.amazonaws.com/0/333380/25a96180-cb37-550c-f732-fcade4af225d.png)



##r sqeared：決定係数
学習して得られた回帰線をどうやって評価するか？すぐ思いつくのは評価方法に、SSE(Sum of Squared Error)を使うことだが、これだと、データ数が多ければ、それだけSSEも大きくなってしまう。そこで出てくるのは決定係数。
入力特徴量と出力の関係をどの程度よく表しているかを表現する。1に近いほどよく表している。
学習した予測器の評価に使う値。なのでclf.score(X,y)のメソッドで使える。

ここがすごくわかりやすかったです。
[27-4. 決定係数と重相関係数](https://bellcurve.jp/statistics/course/9706.html)
簡潔に言うと、

```math
R^2 = \frac{\sum_{i=1}^{n}{(データのyの平均から推定値がどれだけ差があるか)^2}}{\sum_{i=1}^{n}{(データのy平均値と各データのyがどれだけ差があるか)^2}}

```
ポイントは、各データに対する推定値の平均からの差分(回帰変動)を各データの生のyの平均からの差分(全変動)で割っているので、データ数と比例して大きくならない点ですね。二乗しているのはおそらく、そうしないと二乗誤差の時と同じように収束しないからでしょう。

##Multi-variate regression：多変量回帰
今までは入力-出力の関係が1vs1の場合を話ししてきたが、複数vs1の場合もある。



#Mini-project
Enronデータセットを使って、さまざまな特徴量から、ボーナスの額を推定する回帰を行う。
後半には、outlier(外れ値)が、回帰に与える影響を見ていく。

参考はsklearn正式ドキュメント[sklearn.linear_model.LinearRegression
](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html#sklearn.linear_model.LinearRegression)

```python

### list the features you want to look at--first item in the 
### list will be the "target" feature
features_list = ["bonus","salary",]
data = featureFormat( dictionary, features_list, remove_any_zeroes=True)
target, features = targetFeatureSplit( data )

### training-testing split needed in regression, just like classification
from sklearn.cross_validation import train_test_split
feature_train, feature_test, target_train, target_test = train_test_split(features, target, test_size=0.5, random_state=42)
train_color = "b"
test_color = "r"


### Your regression goes here!
### Please name it reg, so that the plotting code below picks it up and 
### plots it correctly. Don't forget to change the test_color above from "b" to
### "r" to differentiate training points from test points.
#print(dictionary.items())

from sklearn import linear_model
reg = linear_model.LinearRegression()
print("**feature_train**\n"+str(feature_train))
print("**target_train**\n"+str(target_train))
reg.fit(feature_train,target_train)

print("slope:"+str(reg.coef_))
print("intercept:"+str(reg.intercept_))
score_tr = reg.score(feature_train,target_train)
print("score_train:"+str(score_tr))
score_te = reg.score(feature_test,target_test)
print("score_test:"+str(score_te))


```
Your regression goes here!以下を書いた。

＜出力＞
＊＊feature_train＊＊
[array([415189.]), array([243293.]), array([213625.]), array([184899.]), array([248546.]), array([221003.]), array([197091.]), array([261516.]), array([309946.]), array([248146.]), array([213999.]), array([278601.]), array([304110.]), array([269076.]), array([262663.]), array([272880.]), array([240189.]), array([339288.]), array([278601.]), array([265214.]), array([201955.]), array([251654.]), array([365038.]), array([330546.]), array([76399.]), array([229284.]), array([261879.]), array([329078.]), array([211844.]), array([267102.]), array([239502.]), array([211788.]), array([170941.]), array([273746.]), array([182245.]), array([262788.]), array([304588.]), array([271442.]), array([314288.])]
＊＊target_train＊＊
[1000000.0, 1500000.0, 1000000.0, 325000.0, 850000.0, 70000.0, 400000.0, 750000.0, 700000.0, 600000.0, 5249999.0, 800000.0, 2000000.0, 650000.0, 700000.0, 750000.0, 1250000.0, 8000000.0, 1350000.0, 600000.0, 4175000.0, 1100000.0, 1100000.0, 900000.0, 100000.0, 400000.0, 1000000.0, 750000.0, 200000.0, 1200000.0, 500000.0, 1700000.0, 350000.0, 1000000.0, 200000.0, 1000000.0, 2500000.0, 3100000.0, 800000.0]
slope:[5.44814029]
intercept:-102360.5432938796
score_train:0.04550919269952436
score_test:-1.48499241736851

![regression_0.png](https://qiita-image-store.s3.amazonaws.com/0/333380/53498ba7-07e3-6046-c109-63b8043dbd8f.png)
トレーニングデータで学習して傾きと切片出して、テストデータで直線引いてる。

###Video44
3行目の
￼features_list = ["bonus","salary",]
を
features_list = ["bonus",“long_term_incentive”,]
に書き換えればよい。コードは上記。

＜出力＞
**feature_train**
[array([200000.]), array([100000.]), array([69223.]), array([1586055.]), array([1617011.]), array([300000.]), array([974293.]), array([156250.]), array([1617011.]), array([1294981.]), array([694862.]), array([300000.]), array([422158.]), array([323466.]), array([175000.]), array([125000.]), array([2234774.]), array([554422.]), array([335349.]), array([71023.]), array([554422.]), array([554422.]), array([75000.]), array([2035380.]), array([983346.]), array([275000.]), array([304805.])]
**target_train**
[325000.0, 750000.0, 1700000.0, 1200000.0, 2000000.0, 1000000.0, 1350000.0, 100000.0, 1500000.0, 3000000.0, 2600000.0, 700000.0, 600000.0, 400000.0, 200000.0, 400000.0, 200000.0, 100000.0, 600000.0, 600000.0, 1100000.0, 2000000.0, 300000.0, 8000000.0, 1150000.0, 300000.0, 4175000.0]
slope:[1.19214699]
intercept:554478.7562150093
score_train:0.21708597125777662
score_test:-0.5927128999498639
![regression_longterm.png](https://qiita-image-store.s3.amazonaws.com/0/333380/85c4bb08-6fec-fb3f-d126-f88f0013646a.png)

トレーニングデータへのスコアは下がったが、テストデータに対しては上がっている。スコアだけを見ると特徴量としてはlong_term_incentiveのほうが優れていることがわかる。


###Video46：外れ値
外れ値(Outliner)の影響を見てみるために、トレーニングデータに外れ値があると、どの程度回帰線が変化するのか見てみる。
外れ値があるテストデータ(赤)でトレーニングして(テストデータとトレーニングデータデータを入れ替えている)、プロットする為に、下記コードを足すよう指示あり。
reg.fit(feature_test, target_test)
plt.plot(feature_train, reg.predict(feature_train), color="b") 
print("slope_new:"+str(reg.coef_))
を下のほうに足した。

```python

### draw the scatterplot, with color-coded training and testing points
import matplotlib.pyplot as plt
for feature, target in zip(feature_test, target_test):
    plt.scatter( feature, target, color=test_color ) 
for feature, target in zip(feature_train, target_train):
    plt.scatter( feature, target, color=train_color ) 

### labels for the legend
plt.scatter(feature_test[0], target_test[0], color=test_color, label="test")
plt.scatter(feature_test[0], target_test[0], color=train_color, label="train")

### draw the regression line, once it's coded
try:
    plt.plot( feature_test, reg.predict(feature_test) )
except NameError:
    pass

###Video46で足すように指示されたコード###
reg.fit(feature_test, target_test)
plt.plot(feature_train, reg.predict(feature_train), color="b") 
print("slope_new:"+str(reg.coef_))
######

plt.xlabel(features_list[1])
plt.ylabel(features_list[0])
plt.legend()
plt.show()

```
＜出力＞
slope_new:[2.27410114]
![regression_mini.png](https://qiita-image-store.s3.amazonaws.com/0/333380/19622139-db6f-6169-b869-2a81ab383a32.png)

左下に、短い回帰線が追加されている。トレーニングデータに対して、プロットしているので、回帰線の長さが、短いのはご愛敬。
確かに一番右の外れ値に影響されて、回帰線がかなり寝ているのがわかる。

#感想
今回復習と記録のために2回目受けてみた。
最小二乗法で誤差計算しないと、回帰線が一意に決まらないことが直観的に示せたのは良かった！
決定係数は完全に忘れていたので、復習してよかった。

#調べた英単語
constraint・・・n, 強制、圧 迫、束縛、制約 
arbitrary・・・n, 任意の、恣意(しい)的な、勝手な
discrete・・・n, 分離した、不連続の(continuous vs discrete)
coefficient・・・n, 係数
shortcoming・・・n, 短所、欠点
hefty・・・adj, かなりの、重い、屈強な
ex)hefty bonus