あゝお腹いっぱい、次なに食べよ

機械学習とかAWSとかiPadProとかGalaxynote8とか

Gradient boosting tree iPad pro + Sagemaker

お疲れ様です、sysopjpです

scikit-learnとか sklean とか名前も安定していないし

GBTとかGBTDとか、GBTCとかえーと よくわかんなかったのでまずは使ってみました 後でこの認識間違ってるよとかツッコミくだしあ

環境は ipad pro+Sagemakerです。

Gradient boosting tree

まずはデータを用意します https://archive.ics.uci.edu/ml/datasets/Adult

!wget https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data

カラム情報は https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.namesに書いてありました

age: continuous.

workclass: Private, Self-emp-not-inc, Self-emp-inc, Federal-gov, Local-gov, State-gov, Without-pay, Never-worked.

fnlwgt: continuous.

education: Bachelors, Some-college, 11th, HS-grad, Prof-school, Assoc-acdm, Assoc-voc, 9th, 7th-8th, 12th, Masters, 1st-4th, 10th, Doctorate, 5th-6th, Preschool.

education-num: continuous.

marital-status: Married-civ-spouse, Divorced, Never-married, Separated, Widowed, Married-spouse-absent, Married-AF-spouse.

occupation: Tech-support, Craft-repair, Other-service, Sales, Exec-managerial, Prof-specialty, Handlers-cleaners, Machine-op-inspct, Adm-clerical, Farming-fishing, Transport-moving, Priv-house-serv, Protective-serv, Armed-Forces.

relationship: Wife, Own-child, Husband, Not-in-family, Other-relative, Unmarried.

race: White, Asian-Pac-Islander, Amer-Indian-Eskimo, Other, Black.

sex: Female, Male.

capital-gain: continuous.

capital-loss: continuous.

hours-per-week: continuous.

native-country: United-States, Cambodia, England, Puerto-Rico, Canada, Germany, Outlying-US(Guam-USVI-etc), India, Japan, Greece, South, China, Cuba, Iran, Honduras, Philippines, Italy, Poland, Jamaica, Vietnam, Mexico, Portugal, Ireland, France, Dominican-Republic, Laos, Ecuador, Taiwan, Haiti, Columbia, Hungary, Guatemala, Nicaragua, Scotland, Thailand, Yugoslavia, El-Salvador, Trinadad&Tobago, Peru, Hong, Holand-Netherlands.

これをリストにしておく

col = ['age', 'workclass', 'fnlwgt', 'education', 'education-num',
       'marital-status', 'occupation', 'relationship', 'race', 'sex',
       'capital-gain', 'capital-loss', 'hours-per-week', 'native-country',
       'label']

説明変数と目的変数

データをXとYに分けます。

そもそも名称からして 説明変数、X、学習データ 目的変数、Y、教師データ 他にも呼び名がたくさんあってわかりません とりあえず僕は当てたいデータをY、元になるデータをXで通します。

今回の adult_data はどうやらその人の属性を入れると 収入が 50k を超えるか以下かをあてるデータのようです

adult_data = pd.read_csv('adult.data',names=col) f:id:sysop:20181019205617p:plain

一番右の label が Y ですね。 そこでこの label列を分離します

y = adult_data['label']

x = adult_data.drop('label', axis=1)

Gradient boosting tree  にぶっこんでみる

とりあえずぶっこんでみます

from sklearn.ensemble import GradientBoostingClassifier

import numpy as np

import pandas as pd

clf = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1,max_depth=1)

clf.fit(x, y)  ```


>could not convert string to float: ' United-States'  


GBTでは float 型しか扱えないの、ごめんね
と言われます。

さて、これを手で直していると時間もかかるのでライブラリに頼ります
結局プログラムなんてライブラリをどれだけ「知っているか」
で効率が変わるので便利なライブラリをたくさん使って、たくさん覚えましょう

http://own-search-and-study.xyz/2016/11/23/sklearn%E3%81%AEpreprocessing%E3%81%AE%E5%85%A8%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%92%E8%A7%A3%E8%AA%AC/

こちらの人の解説がわかりやすかったです、あざーす


### label_binarize


説明変数Xがラベルの時はこっち使う
ちなみに目的変数がラベルの時はLabelEncoder
を使う、理由は長くなるから別の機会に

col = x["native-country"].unique()

nc_df = pd.DataFrame(sp.label_binarize(x["native-country"], classes=col), columns=col)


### 他のデータもやっちゃう

*workclass

* education

*marital-status
* occupation

* relationship

* race

* sex
もやってしまいます

ただし sex は

x['sex'].unique()

array([' Male', ' Female'], dtype=object)

元データが2値しかなかったので LabelEncoder で
http://own-search-and-study.xyz/2016/11/23/sklearn%E3%81%AEpreprocessing%E3%81%AE%E5%85%A8%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%92%E8%A7%A3%E8%AA%AC/#LabelEncoder

0、1に置き換えます

ラベルを数値に変換する

train_df = x

transform_col =  ['native-country','workclass','education','marital-status','occupation','relationship','race']

for i in transform_col:     tmp_df = pd.DataFrame(sp.label_binarize(x[i], classes=x[i].unique()), columns=x[i].unique())     train_df = pd.concat([train_df, tmp_df], axis=1)

SEX の変換

le = sp.LabelEncoder()

le.fit(x['sex'].unique())

tmp_df = pd.DataFrame(le.transform(x['sex']), columns=['sex_binary'])

train_df = pd.concat([train_df, tmp_df], axis=1)

transform_col.append('sex')

変換の終わったデータを抹消する

x_train = train_df.drop(transform_col, axis=1)


### GBT してみる


ではやってみましょう

`clf.fit(x_train, y) `

>GradientBoostingClassifier(criterion='friedman_mse', init=None,
              learning_rate=0.1, loss='deviance', max_depth=1,
              max_features=None, max_leaf_nodes=None,
              min_impurity_decrease=0.0, min_impurity_split=None,
              min_samples_leaf=1, min_samples_split=2,
              min_weight_fraction_leaf=0.0, n_estimators=100,
              presort='auto', random_state=None, subsample=1.0, verbose=0,
              warm_start=False)


お???おお?なんかできた?できたっぽいぞ??


### 推測して見る

とりあえずぶっこんでみましょう


`clf.predict(x_train[:1])`

>array([' <=50K'], dtype=object)

ほー、あたってるね。
まあ、学習データ入れてるんだから、そりゃあたり率高いはずなんですけどね


`clf.predict(x_train[:10])`
こうやって 10個くらいまとめてリストDFの状態でも入れられます

array([' <=50K', ' >50K', ' <=50K', ' <=50K', ' <=50K', ' >50K', ' <=50K',        ' <=50K', ' >50K', ' >50K'], dtype=object)

んー?みにくい

for x in clf.predict(x_train[:10]):     print(x)

 <=50K  >50K  <=50K  <=50K  <=50K  >50K  <=50K  <=50K  >50K  >50K

上から10個渡して見たらこんなデータじゃね?ってきましたね

y[:10]

0     <=50K

1     <=50K

2     <=50K

3     <=50K

4     <=50K

5     <=50K

6     <=50K

7      >50K

8      >50K

9      >50K

Name: label, dtype: object

あーんー結構はずしますね。



## 学習データとテストデータ

さて、あたった外れたとか目視でやっていると大変なので
ここもライブラリに頼ります
さきほどモデル作成に使ったデータを学習とテストに分解します


`len(x_train)`

> 32561

どこらへんでわけるの?と言われるとよくわかりません
とりあえず端数でわけて、GBTに入れて見ます

x_train2 = x_train[:30000]

y_train2 = y[:30000]

x_test2 = x_train[30000:]

y_test2 = y[30000:]

clf.fit(x_train2, y_train2)

> GradientBoostingClassifier(criterion='friedman_mse', init=None,
              learning_rate=0.1, loss='deviance', max_depth=1,
              max_features=None, max_leaf_nodes=None,
              min_impurity_decrease=0.0, min_impurity_split=None,
              min_samples_leaf=1, min_samples_split=2,
              min_weight_fraction_leaf=0.0, n_estimators=100,
              presort='auto', random_state=None, subsample=1.0, verbose=0,
              warm_start=False)


できた clf の性能は score という関数で観れます

print (clf.score(x_test2, y_test2))

>0.8543537680593518

当たった確率なので
このモデルは 85% くらいであたる精度だったようですね



### マルチクラスだかマルチラベルだか

マルチラベルとマルチクラスとどういう名称が正しいのか
いまだにわかりませんが
二次元データをあてにいきます

具体的には、そうですね、データを入れると
人種とlabel を推論するモデルを作成します


Yとして label と race を分離します

adult_df = pd.read_csv('adult.data',names=col)

target_col = ['label','race']

y = adult_df[target_col]

x = adult_df.drop(target_col, axis=1)


fit してみます

clf.fit(x_train, y)

> bad input shape (32561, 2)

まあそうですよね、二次元のデータをいきなりあてるのは無理ですよね。



### マルチクラスの次元圧縮

まず bad input shape (32561, 2)にあるとおり

Yが2次元なのは無理、と言われているので、これを一次元に
次元圧縮します

そう、次元圧縮します!!
大事なことなので二回いいました
かっこいいですよね、次元圧縮

ま、難しい言葉使っておきながら
一番頭の悪い方法でいきます


`y['data'] = y['label'] + ',' + y['race']`

はいできた!!!!
え?足しただけだろ?
はい、そうです、カンマセパレートで足しただけです



`clf.fit(x_train, y['data']) `

> GradientBoostingClassifier(criterion='friedman_mse', init=None,
              learning_rate=0.1, loss='deviance', max_depth=1,
              max_features=None, max_leaf_nodes=None,
              min_impurity_decrease=0.0, min_impurity_split=None,
              min_samples_leaf=1, min_samples_split=2,
              min_weight_fraction_leaf=0.0, n_estimators=100,
              presort='auto', random_state=None, subsample=1.0, verbose=0,
              warm_start=False)


それでもほらできた!!
先ほどと同じように、テストデータと学習データにわけて精度みてやると

clf.fit(x_train[:30000], y['data'][:30000])

print (clf.score(x_train[30000:], y['data'][30000:]))

> 0.7348691917219836


73% であたるって!結構高いね

ちなみに出力はこんな感じになります

clf.predict(x_train[30000:30010]))

[' <=50K, White' ' <=50K, White' ' <=50K, White' ' <=50K, White'  ' <=50K, White' ' <=50K, White' ' >50K, White' ' <=50K, Black'  ' <=50K, White' ' <=50K, White']




print(y['data'][30000:30010].tolist())

>[' <=50K, White', ' <=50K, Black', ' <=50K, White', ' <=50K, White', ' <=50K, White', ' <=50K, White', ' >50K, White', ' <=50K, Black', ' <=50K, White', ' <=50K, White']


おー、ここらへんは 100%あたってますね、すごいすごい




### モデル複数つくればいいやん

さて、別にGBTはモデル作成早いし、別々のモデル作ればよくね?
ということで複数モデル作って当てに行ってみます

label_clf = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1,max_depth=1)

race_clf = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1,max_depth=1)

label_clf.fit(x_train[:30000], y['label'][:30000])

race_clf.fit(x_train[:30000], y['race'][:30000])


`label_clf.score(x_train[30000:], y['label'][30000:])`

> 0.8543537680593518



`race_clf.score(x_train[30000:], y['race'][30000:])`

> 0.8734869191721983

さて、これをさらに並べたデータを作ってみましょう

label_pdr = label_clf.predict(x_train[30000:])

race_pdr = race_clf.predict(x_train[30000:])

pdr_df = pd.DataFrame({ 'pdr_label' : label_pdr, 'pdr_race' : race_pdr})

pdr_df['pdr'] = pdr_df['pdr_label'] + ',' + pdr_df['pdr_race']


pdr_df['pdr']がどれくらい正解したか判定したいので

y[30000:]をとりますが index があわなくて比較が難しいので添え字を初期化(reset_index)します

result_y = y[30000:].reset_index()

出てきたデータを合わせて、比較してみると

result['check'] = result['pdr']==result['data']

result['check'].value_counts()

> True     1892

> False     669


1892 個/2561個があたっていたので

0.73!!!  

あまりさっきと正解率かわらないですねw  

とりあえずこんなところになります

以上、よろしくお願いします