sklearn.svm.SVCの使い方
公式ドキュメント
パラメータ
- C=1.0
- kernel=‘rbf’
- degree=3
- gamma=‘auto’
- coef0=0.0
- shrinking=True(調査中)
- probability=False
- tol=0.001
- cache_size=200(調査中)
- class_weight=None
- verbose=FalseC
- max_iter=-1
- decision_function_shape=None(調査中)
- random_state=None
パラメータを変えて様子をみる。
サンプルデータ
デフォルトのまま
- accuracy: 0.635
- std: 0.362
C
- Cの意味を表した式はこちらを参照
- Cは学習データに対する分類の正しさとモデルの複雑さのトレードオフをコントロールする。
- Cが大きいと分類の正しさを優先し、モデルが複雑になる(モデルパラメータのノルム-2が大きくなる)。
- 分類(C=10, kernel=‘rbf’)
- 分類(C=1000)
kernel
取りうる値:
- ‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’ or a callable
分類(kernel=‘linear’)
分類(kernel=‘poly’)
分類(kernel=‘rbf’)
分類(kernel=‘sigmoid’)
rbf以外上手く分類できなかった。原因を調査中。
degree
- kernel=‘poly'のときのみ使用できる。
- polynomialの次数を指定する。
gamma
- kernel=‘rbf’, ‘poly’, ‘sigmoid’のとき使用できる。
- gammaの意味を表した式はこちらを参照
- 分類(kernel=‘rbf’, gamma=0.1)
- 分類(kernel=‘rbf’, gamma=2.0)
coef0
- kernelのindependent term。kernel=‘poly’, ‘sigmoid'のとき重要。
RandomForestClassifierの使い方
公式ドキュメント
パラメータ
- DecisionTreeのアンサンブル学習なので多くはDecisionTreeと同じ。こちらを参照
特有のパラメータ
- n_estimators
- bootstrap
- oob_score
- n_jobs
- verbose
- warm_start(調査中)
パラメータを変えて様子をみる。
n_estimators
- 他のパラメータはデフォルトのまま。つまり、汎化能力は低いdecision treeの組み合わになる。
- AUCの推移
- estimatorの数が1のときに比べ、数個のestimatorを加えるだけでかなり精度が上がっている。
bootstrap
- ツリー構築時に学習データからbootstrapをするかのフラグ。bootstrapをすることで性能が向上する。相関が減るからだっけ?(確認中)
- AUCの推移
- 赤がTrue、青がFalse
verbose
- 途中のツリー構築処理のログを出力してくれる。
(prop.get_family(), self.defaultFamily[fontext])) [Parallel(n_jobs=1)]: Done 10 out of 10 | elapsed: 0.0s finished [Parallel(n_jobs=1)]: Done 10 out of 10 | elapsed: 0.0s finished [Parallel(n_jobs=1)]: Done 10 out of 10 | elapsed: 0.0s finished
DecisionTreeClassifierの限界
これまで
限界を探る。
関係のないデータを混ぜる。
- x2というデータを入れる。
- targetはx2に全く依存していない。
結果
- accuracy: 0.810
- std: 0.100
- 分岐ツリー
- 重要度
{'x2': 0.24604190914667379, 'x1': 0.45724873019357137, 'x0': 0.29670936065975489}
- かなり精度が悪化した。
- 関係ないはずのx2の重要度が0.25もある。
データを45度回転させる。
結果
- accuracy: 0.835
- std: 0.037
- 分類
- 分岐ツリー
- 多少ではあるが精度が悪化している。
- 分類結果を見ると境界が直線であってほしいにも関わらず、階段状になってしまう。理論上仕方ないが。
DecisionTreeClassifierのパラメータ調整
設定
- DecisionTreeClassifierの使い方はこちら
- 下記のデータの分類をDecisionTreeClassifierを使って行う
- 約10%ほどノイズが入っている。
- x0: (0.5, 1.5), x1:(0.5, 1.5)で分岐すれば精度90%で分類するごとができる。
- 何も制約を入れずに全データを使って学習させると、下記の通りオーバーフィッティングしている。
とりあえずパラメータを変えてみる
- クロスバリデーションを使ってモデルの評価を行う。
デフォルトパラメータの場合(ツリーへの制約がない状態)
- accuracy: 0.800
- std: 0.039
- 分類
- 分岐ツリー
- かなり複雑になっている。
- 90%くらいの精度になってほしいが、80%くらい。
max_depthを調整する。
max_depth=3
- accuracy: 0.777
- std: 0.035
- 分類
- 分岐ツリー
max_depth=4
- accuracy: 0.889
- std: 0.038
- 分類
分岐ツリー
max_depth=4でかなりいい感じの結果になった。
GridSearchを使って最適なパラメータを探す。
- accuracy: 0.882
- std: 0.044
- 分類
- 分岐ツリー
まとめ
- ツリーの大きさを制約するようなパラメータを上手く設定することで、汎化性能が上がることを確認。
DecisionTreeClassifierの使い方
公式ドキュメント
- sklearn.tree.DecisionTreeClassifier — scikit-learn 0.18.1 documentation
パラメータ
- criterion
- splitter
- max_features
- max_depth
- min_samples_split
- min_samples_leaf
- min_weight_fraction_leaf
- max_leaf_nodes
- class_weight
- random_state
- min_impurity_split
- presort
パラメータを変えて様子をみる。
サンプルデータ
decision treeで分類しやすいように格子状のデータを作成する。
パラメータを変えて実験
デフォルトのパラメータのまま
- 分類結果
- 分岐ツリー
- 重要度
{'x1': 0.69674185463659166, 'x0': 0.30325814536340839}
- ちゃんとすべて分類できている。線形で分類できるからな。
- feature importance で本当はx0とx1の重要度は同じはず、ただ、最初の分岐がx0だったので、x0の方が高くなったいる。使用する乱数によって変わる。
criterion=‘entropy’
- 分類結果
- 分岐ツリー
- 今回のケースだと何もかわらず。。
- どう結果に影響するかを他のケースを作って検証しよう(また今度)
splitter=‘random’
- 分類結果
- 分岐ツリー
- 重要度
{'x1': 0.51479236812570128, 'x0': 0.48520763187429866}
- 境界をランダムに決めているので、分岐ツリーが巨大になっている。
- 重要度は近い値に。
max_features=1
- 今、特徴数は2なので、1とした場合をみる。2の場合は良い方で分岐するが、1だと乱数次第。
- 分類結果
- 分岐ツリー
- 重要度
{'x0': 0.052631578947368363, 'x1': 0.94736842105263164}
- 複雑な分岐になる。
- 重要度も乱数次第なので、当てにならない。
max_depth=3
- ツリーの深さの最大を3とする。3に達したらそこで終了
- 分類結果
- 分岐ツリー
min_samples_split=80
- nodeに残っているサンプル数が80個未満になったら分岐せずにそこで終了。
- 分類結果
- 分岐ツリー
min_samples_leaf=11
- リーフに残るサンプル数の最低数を指定
- 分類結果
- 分岐ツリー
min_weight_fraction_leaf = 6 / 400
- class_weightを指定していないので、min_samples_leaf=6と同じ。
- 分類結果
- 分岐ツリー
max_leaf_nodes=10
- リーフの最大個数を指定。今回は10個のリーフができている。
- 分類結果
- 分岐ツリー
min_impurity_split=0.48
- criterionが指定した値以下になったら、そこで分岐終了
- 分類結果
- 分岐ツリー
まとめ
- 今回は各パラメータの意味を確認できた。
- キレイに分類できるようにデータを作っている&予測をしていないので、当然、パラメータ調整しても意味がない。
ソースコードの一部
import numpy as np import pandas as pd from sklearn import tree import nsb import pydotplus def grid_data(): n = 20 x0, x1 = np.meshgrid(np.linspace(0, 2, n), np.linspace(0, 2, n)) def is_even(x): return np.round(x) % 2 == 0 y = np.logical_xor(is_even(x0), np.logical_not(is_even(x1))).astype(np.int64) return pd.DataFrame({'x0': x0.ravel(), 'x1': x1.ravel(), 'y': y.ravel()}) if __name__ == '__main__': df = grid_data() clf = tree.DecisionTreeClassifier(min_impurity_split=0.48) clf.fit(df[['x0', 'x1']], df['y']) nsb.plot.scatter_with_boundary(df['x0'], df['x1'], df['y'], clf, 'fig.png') dot_data = tree.export_graphviz(clf, out_file=None, feature_names=['x0', 'x1']) graph = pydotplus.graph_from_dot_data(dot_data) graph.write_png('tree.png') print(dict(zip(['x0', 'x1'], clf.feature_importances_)))
To Do, Doing, Done
因果推論3 操作変数法
統計的因果推論の勉強
- 理論の詳しい話は下記の本を見てください。
調査観察データの統計科学―因果推論・選択バイアス・データ融合 (シリーズ確率と情報の科学)
- 作者: 星野崇宏
- 出版社/メーカー: 岩波書店
- 発売日: 2009/07/29
- メディア: 単行本
- 購入: 29人 クリック: 285回
- この商品を含むブログ (25件) を見る
問題設定
- 目的
- バウチャー制度の効果を評価したい。
- 背景
- くじ引きで当たると、「私立高校へ進学したら授業料が半額になる権利」がもらえる。
- くじ引きは希望者全員が引ける。当たりは40%とする。
- 私立高校、公立高校ともに入学試験はないとする。
- しかし、私立高校の方が質の高い授業を行っているとする。
- 卒業時に、私立・公立高校で統一テストを実施している。
- 状況整理
- 全部で4つのパターンがある
- くじ引き当たり、私立へ進学する
- くじ引き当たり、公立へ進学する
- くじハズれ、私立へ進学する
- くじハズれ、公立へ進学する
- バウチャー制度の評価ポイント
- くじ引きが当たれば、私立へ進学し、外れたら公立へ進学する生徒の卒業時の成績。
- 全部で4つのパターンがある
観察データ作成(ケース1)
- 全体の10%当たりは結果に関係なく必ず公立へ進学する。
- 生徒の20%は裕福で、上記の10%に入った生徒以外はくじ引きの結果に関係なく私立へ進学する。
- 生徒の成績の平均は、y = 600 + 80 * (私立) + 150 * (裕福)
- 観測できない影響を大きくするために、150 * (裕福)とする。
- 標準偏差は50
- 生徒数は1000
- 生成したデータはこんな感じ。
- 生徒が裕福かどうかは不明とする。
lottery private score 0 0 0 605.830138 1 0 0 595.145346 2 0 0 660.159643 3 1 1 676.014558 4 0 0 612.031560 5 0 0 592.204991 6 0 1 704.909145 7 0 0 618.559375 8 0 0 626.251403 9 0 0 536.343088
lottery private score count 1000.00000 1000.000000 1000.000000 mean 0.41700 0.485000 649.887460 std 0.49331 0.500025 72.562223 min 0.00000 0.000000 476.666647 25% 0.00000 0.000000 595.276742 50% 0.00000 0.000000 644.046202 75% 1.00000 1.000000 704.860884 max 1.00000 1.000000 856.068556
簡単な分析(ケース1)
- 単純に私立と公立で平均をとってみる。
- データ生成時のモデル上、差は80程度のはず。
- 他の要素の影響が含まれている。
106.589641791
操作変数法
- 割当
- くじ引きが当たる:
- くじ引きが外れる:
- 操作変数
- のとき、私立へ進学する:
- のとき、公立へ進学する:
- のとき、私立へ進学する:
- のとき、公立へ進学する:
- 結果に影響しないので、仮定する(単調性)
- 私立へ進学するかどうか
- テストの成績
- 独立性
- とは独立
- とは独立
- 推定したいもの
- くじ引きが当たれば私立へ進学するが、外れれば公立へ進学する生徒の成績の差
- ]
- くじ引きが当たれば私立へ進学するが、外れれば公立へ進学する生徒の成績の差
- 計算する上での問題
- 条件を満たす生徒が誰なのかがわからない。(当たっても私立へ進学しない生徒の存在など。)
- 当然、かのどちらかしか観測できていない。
- どう計算するか(詳細な計算は本を見てください)。
- 準備
- -E[y|z=0]=E[y_1-y_0|d_1-d_0=0]p(d_1-d_0=1)]
- 以上より
- 最終的にはデータから計算できるものばかりで表される!!
- 準備
- 結果は期待通り80に近い。
81.2776422538
今後の課題
- 結果の検定をどうするのか?
- 入学試験がある場合はどうすればよいか?(選択バイアスが出るよね?)
調査観察データの統計科学―因果推論・選択バイアス・データ融合 (シリーズ確率と情報の科学)
- 作者: 星野崇宏
- 出版社/メーカー: 岩波書店
- 発売日: 2009/07/29
- メディア: 単行本
- 購入: 29人 クリック: 285回
- この商品を含むブログ (25件) を見る
使ったプログラムコード
import numpy as np import pandas as pd def sampling(): n = 1000 score_base = 600 score_private = 80 score_rich = 150 score_sigma = 50 rich_ratio = 0.2 public_ratio = 0.1 winning_ticket_ratio = 0.4 data = pd.DataFrame({ 'rich': np.random.binomial(1, rich_ratio, n), 'lottery': np.random.binomial(1, winning_ticket_ratio, n) }) data['private'] = data.apply(lambda d: 1 if d['rich'] == 1 or d['lottery'] == 1 else 0, axis=1) data['private'] = data['private'] * np.random.binomial(1, 1 - public_ratio, n) data['score'] = score_base + score_private * data['private'] + score_rich * data['rich'] \ + np.random.normal(0, score_sigma, n) return data.drop(['rich'], axis=1) def simple_analysis(data): d0 = data[data['private'] == 0] d1 = data[data.apply(lambda d: d['private'] == 1 and d['lottery'] == 1, axis=1)] print(np.average(d1['score']) - np.average(d0['score'])) def instrumental_variable_method(data): data0 = data[data['lottery'] == 0] data1 = data[data['lottery'] == 1] y0 = np.average(data0['score']) y1 = np.average(data1['score']) d0 = np.average(data0['private']) d1 = np.average(data1['private']) print((y1 - y0) / (d1 - d0)) if __name__ == '__main__': np.random.seed(123) data = sampling() print(data.head(10)) print(data.describe()) simple_analysis(data) instrumental_variable_method(data) print('hello')```