Lesson12: Feature Selection まとめ Intro to Machine learning@Udacity 

#Lesson12の概要
このレッスンは特徴選択について。
特徴選択とは機械学習に入力するデータの必要な特徴を含むデータのみ残し(**Removal**)、かつ、足りない特徴量があれば、新しい特徴量作成＆追加(**Making new features**)すること。

とりあえず全部学習してみる⇒必要な情報を含むものだけで学習しましょう

ということ。

###Making new features流れ
＜流れ＞
・人間の勘で特徴選択→コーディング→見える化→改善
今回はEnronのemailデータセットを用いて上記の流れを行っている。
今回の課題は、POIの特定に使える特徴量は何か？

＜今回の考え方＞
・POI同士はメールの送受信回数が多いのでは→コーディング→グラフ化→改善

Video3のQuizをやるときは変数型に注意。整数型で計算してしまうとすべてゼロとなる。
[Pythonで整数を割り算すると、デフォルトでは小数点以下が切り捨てになる問題の解決方法](http://d.hatena.ne.jp/omiyan/20101221/1292938626)
elifで条件分岐させるよりtry except構文で ZerodivエラーとTypeエラー検出することをお勧め。
[Pythonの例外処理「except」は複数連結出来る](https://qiita.com/yas-nyan/items/73d0045b9d943f13cb7d)

◆ここで注意◆←ビデオでケイティが注意してくれる。
新しい特徴量作成＆追加するときは。バグに注意。
今回の課題：POIをメールのやり取りから特定したい。
追加した特徴量：shared receipt・・・POIへ送られているメールの宛先等に入っている人は、その人とPOIそれぞれのshared receiptにカウントが1追加される。POIとメールを共有している人は、大方同じようにPOIだろうという仮定。

結果：100％の精度←高すぎ(バグなのでは?の疑い)
バグ内容：例えば、1通のメールが重要参考人のKen Layと重要参考人ではないKatie Malone に送られたとする。その場合Kenのshared receipt特徴量は+1され、Katieのshared receipt特徴量も+1される。
上記のようなカウントの仕方なので、Kenは必ずshared receiptのカウント数が大きくなる。なぜなら、彼自身が重要参考人なので、彼に来たメールはすべてshared receipt特徴量に+1される為。そりゃ検出率100%になっちゃうよね。

改善：カウントを+1する条件を、異なる重要参考人とシェアしたメールとした。
つまり特徴量を「メールの数」から「メールをやり取りした重要参考人の数」に変更した。するとreasonableな精度になったとのこと。


###Removal流れ
特徴量削除の必要性：
Feature≠**Information**←これが欲しい。
↑**information**にアクセスするための特徴量

sklearnには自動で特徴を選択(つまり削除)してくれるものがある。有名なのは、SelectPercentileとSelectKBest。両関数については[ここ](https://qiita.com/rockhopper/items/a68ceb3248f2b3a41c89)の@rockhopperさんの記事を参照させていただきました。わかりやすい！リンク先のデータセットの内容：[boston housing data](https://www.scipy-lectures.org/packages/scikit-learn/auto_examples/plot_boston_prediction.html)

Quiz10:[Lesson11:text learning](https://qiita.com/Allovertom/items/c1bd9a121d53c37fc63e)でemailの作者がChrisかSaraかを判別するmini-projectで使用した、toolsフォルダの中のemail_preprocess.pyを解説。
[このsklearn.feature_extraction.text.TfidfVectorizerの解説文](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html)のmax_df を見れば、何%の頻度であれば削除するのかすぐわかる。

#Bias-Variance Dilemma
BiasとVarianceはトレードオフの関係。
未学習と過学習について。

・入力する特徴の種類(No. of features)少ない→High bias(未学習)トレーニングセットでさえ精度低い
・入力する特徴の種類(No. of features)多め→High variance(過学習)トレーニングセットは精度高いがテストセットで精度低い

このhigh biasとhigh varianceの中間に精度(lessonではQuality of modelと言ってる)が最大になる特徴量の種類数(No. of features)があるはず。
これを見つけるためにRegularization(正則化)をしていく。


chezouさんの[そのモデル、過学習してるの？未学習なの？と困ったら](https://chezou.hatenablog.com/entry/2016/05/29/215739)を参考にさせていただきました。

参考書籍は[［第2版］Python機械学習プログラミング 達人データサイエンティストによる理論と実践 ](https://www.amazon.co.jp/dp/B07BF5QZ41/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)pp191-192


#Regularization(正則化) in Regression
Regularizationは回帰でよく使用される。例えばLasso回帰

最小化する式：　**SSE+λ*|β|**

**SSE(誤差)項**にて誤差を最小にし、
**|β|(罰則)項**にて回帰曲線の複雑さ(使う特徴数)を小さくする。**SSE**と**|β|**で大きさが違うので、**λ**でそれぞれの影響のバランスをとっている。

SSE = Sum of Squared Error
λ:パラメーター
β:回帰係数(回帰曲線の係数)


正則化の例)
---

下記のような回帰曲線があった場合、

y = m1*x1 + m2*x2 + m3*x3 + m4*x4
m1-m4:回帰係数
x1-x4:特徴

あまり精度に寄与しない特徴は使いたくない。上記、Lasso回帰を使用する(罰則項を導入する)ことによって、例えばm3=0, m4=0と自動で設定してくれる。回帰式は

y = m1*x1 + m2*x2 

となる。

---

###未学習に対する一般的対策###
回帰式(モデル)の複雑さを増やす。(入力する特徴数：No. of featuresを追加・生成 or 罰則項のλを小さくする)

###過学習に対する一般的対策###
トレーニングデータをさらに集める or 回帰式(モデル)の複雑さを減らす。(罰則項のλを大きくする)



Quiz 18, 19, 20, 21は[sklearn.linear_model.Lasso](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html#sklearn.linear_model.Lasso.predict)のfitとpredict, Attributesのcoef_を見ればわかる。

#mini-project
決定木(Lesson4)は伝統的に過学習しやすいアルゴリズムと考えられている。

このprojectはDecision tree のmini-project:Author identificationの準備をしているKatieがぶつかった問題を同僚の自分が助けるという設定。
何かというと、lesson11のvectorize_text.py内では、分類器がまだ過学習しているため、vectorize_text.pyのline55-56で取り除く単語追加したい。それは何かを以下のQuizで見ていく。なので、Quizが進むにつれて、テストデータセットでの精度が上がっていくはず。
僕がlesson11でかいたline55-56が下記です。

```python:vectorize_text.py

### use str.replace() to remove any instances of the words
### ["sara", "shackleton", "chris", "germani"]

for theWord in ["sara", "shackleton", "chris", "germani"]:
     text = text.replace(theWord,'')
```

###Quiz26
find_signature.pyに決定木のアルゴリズムを入れて精度を出す。
このプログラムは、Lesson11のtext learningで使ったワードデータをpickleでロード。このpickleはtext learningのvectorize_text.pyの実行で生成される。今回はlesson11で生成したものを読み込んでいる。

```python:find_signature.py
### your code goes here
from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier()
clf = clf.fit(features_train, labels_train)
accuracy = clf.score(features_test, labels_test)
print("accuracy;"+str(accuracy))
```


###Quiz27
[決定木のアルゴリズムのfeature_importances_メソッド](https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html#sklearn.tree.DecisionTreeClassifier.feature_importances_)を使って、最も影響度の大きい単語を抽出(0.2以上：ビデオで指定される。)
enumerate関数めっちゃ便利！

```python:find_signature.py
from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier()
clf = clf.fit(features_train, labels_train)
accuracy = clf.score(features_test, labels_test)
print("accuracy;"+str(accuracy))

fti = clf.feature_importances_
for i, feat in enumerate(fti):
	if feat >=0.2:
		print(i, feat)
	else:
		pass
```
◆結果◆
accuracy;0.947098976109215

(33613, 0.7647058823529412)


そして、答えに入力するのは、得られたインデックスは最初が0なので、順番としては+1をすることを忘れずに。accuracy;0.947098976109215は高すぎる＝過学習ということか。。

下記参照しました。
・enumerate関数について
[Python, enumerateの使い方: リストの要素とインデックスを取得](https://note.nkmk.me/python-enumerate-start/)

・feature_importanceについて
[ランダムフォレスト系ツールで特徴量の重要度を測る](https://qiita.com/TomokIshii/items/290adc16e2ca5032ca07)

###Quiz28
一番importanceが大きい単語が何かを表示(33613番目だった)

```python:find_signature.py
feature = vectorizer.get_feature_names()
print(feature[33613])
```
◆結果◆
sshacklensf

###Quiz29
Lesson 11のvectorize_text.pyのtextから、Quiz28の33613番目の単語(sshacklensf)を削除し、vectorize_text.py実行。再度pickleを作り、find_signature.pyを下記に書き直して実行。

```python:vectorize_text.py
for theWord in ["sara", "shackleton", "chris", "germani", "sshacklensf"]:
#"sshacklensf"added
                text = text.replace(theWord,'')
```


```python:find_signature.py
from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier()
clf = clf.fit(features_train, labels_train)
accuracy = clf.score(features_test, labels_test)
print("accuracy;"+str(accuracy))

fti = clf.feature_importances_
for i, feat in enumerate(fti):
    if feat >=0.2:
        print(i, feat)
        feature_num = i
    else:
        pass

feature = vectorizer.get_feature_names()
print(feature[feature_num])
```
◆結果◆
accuracy;0.9681456200227532

(14343, 0.6666666666666667)
cgermannsf

→しっかりaccuracyが上がっていますね！

###Quiz30
もう一度cgermannsfを除去して再学習。

```python:vectorize_text.py
for theWord in ["sara", "shackleton", "chris", "germani", "sshacklensf", "cgermannsf"]:
#sshacklensf,cgermannsf is added on lesson12
                text = text.replace(theWord,'')

```

find_signature.pyはいじらず。


◆結果◆
accuracy;0.8071672354948806

(21322, 0.36363636363636365)
houectect

→精度が下がった。。この辺がいいところか。
importanceは0.36まで下がった。

###Quiz31
上記2ワード"sshacklensf", "cgermannsf"はsigniture wordらしいと解説されたけどほんとか？？想像がつかない。。。stemされる前は何なんだ。。。
答え：accuracy;0.8071672354948806

どうもネイティブにとっては、"sshacklensf", "cgermannsf"はsigniture wordと一目瞭然で、"houectect"はemailの本文wordと直感的にわかるらしい。非ネイティブにとっては、過学習かそうでないかの判断は精度8割と、importanceが0.2付近でするしかないのかな。

#感想
lessonの初めから最後まで、記録してみたけど、かなり勉強になった。
これからも記録しながら、レッスンをやっていこう。自分がわかっていないところがはっきりする。
個人的にはlasso回帰がある程度わかってよかった。自動で、重要な特徴量だけにしてくれるのはありがたい。決定木は過学習しやすい！機械学習を設計するエンジニアの「経験と勘」はまだまだ、必要ですね。

#このレッスンで調べた英単語
integer・・・n, 完全体、整数 ex) integer # of messages.
parse・・・品詞・文法的関係を説明する、解剖する
corpus・・・n, (文書などの)集成、集積、全集、(資料の)総体、集成資料、(人・動物の)死体
ex)The imported reader.py file contains functions that we've created to help
    parse e-mails from the corpus.
numerator・・・n, 分子
denominator・・・n, 分母
fraction・・・n, 断片、小部分、ほんの少し、少量、わずか、**分数**、端数
ex)you fill in this code, so that it returns either
    the fraction of all messages to this person that come from POIs
    or
    the fraction of all messages from this person that are sent to POIs
    the same code can be used to compute either quantity

POI(Person Of Interest)・・・n, 重要参考人

crept・・・n, creep の過去形・過去分詞.1. はう，腹ばう. 4. 〔+into+(代)名詞〕〔人に〕ひそかに取り入る.
creep into a person's favor 人にうまく取り入る.

increment・・・v, (不連続に)増加する
skeptical ・・・adj, 懐疑的な、疑い深い、懐疑的で、信用しないで、無神論的な

correlation・・・n, 1不可算名詞 相関させること; 相関性[関係] 〔with〕.
2可算名詞 相互関係 〔between〕.

univariate・・・adj, 単変量の
plummet・・・v, 1〈ものが〉まっすぐに落ちる. 2〈人気・物価などが〉急落する.