機械学習における誤認識
> 数値の大きさとばらつきに大きな差があるため、同じ基準では評価できません。
> そのため、標準化を行い、スケールを揃える必要があります。
そのようなことは必要なし 後に示す
「特徴量」,「正解」という言葉を使うが,独立変数(説明変数),従属変数(目的変数)と呼ぼう。
少なくとも,「正解」というのは変だ。
重回帰分析をする際にさえもデータを標準化する(平均値=0,標準偏差=1)。
標準化データで「モデルを作成」し,「モデルを訓練」する。
言葉も変だが,重回帰分析プログラムはそれ自体が内部でデータを標準化して偏回帰係数と必要なら定数項を計算する。
前もって標準化したデータを使って重回帰すると標準化を 2 回することになる。
標準化は何回行ってもかまわないが,無駄であるだけでなく,そのあとのあらゆる計算処理を複雑にする。
Python で以下のように行われている。
#住宅価格以外のデータを特徴量Xに設定
X = df.iloc[:, 0:13].values
#住宅価格を正解yに設定
y = df['MEDV'].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state=0)
#特徴量の標準化
sc = StandardScaler()
#訓練データで標準化モデルを作成し変換
X_train_std = sc.fit_transform(X_train)
#作成した標準化モデルでテストデータを変換
X_test_std = sc.transform(X_test)
#標準化された訓練データ
X_train_std[0]
#モデルの作成
model = LinearRegression()
#モデルの訓練
model.fit(X_train_std,y_train)
print('傾き: ' , model.coef_)
print('切片: ' , model.intercept_)
傾き: [-0.97082019 1.05714873 0.03831099 0.59450642 -1.8551476 2.57321942
-0.08761547 -2.88094259 2.11224542 -1.87533131 -2.29276735 0.71817947
-3.59245482]
切片: 22.611881188118836
------------------------------------------------
統計学の観点からは,従属変数と独立変数を定めて,解を求める。それだけだ。
using DataFrames, CSV
df_train = CSV.read("train.csv", DataFrame);
df_test = CSV.read("test.csv", DataFrame);
names(df_train); # "CRIM", "ZN", "INDUS", "CHAS", "NOX", "RM", "AGE"
# "DIS", "RAD", "TAX", "PTRATIO", "B", "LSTAT", "MEDV"
using GLM
a = lm(@formula(MEDV ~ CRIM+ZN+INDUS+CHAS+NOX+RM+AGE+DIS+RAD+TAX+PTRATIO+B+LSTAT), df_train);
a
StatsModels.TableRegressionModel{LinearModel{GLM.LmResp{Array{Float64,1}},GLM.DensePredChol{Float64,LinearAlgebra.Cholesky{Float64,Array{Float64,2}}}},Array{Float64,2}}
MEDV ~ 1 + CRIM + ZN + INDUS + CHAS + NOX + RM + AGE + DIS + RAD + TAX + PTRATIO + B + LSTAT
Coefficients:
─────────────────────────────────────────────────────────────────────────────────
Coef. Std. Error t Pr(>|t|) Lower 95% Upper 95%
─────────────────────────────────────────────────────────────────────────────────
(Intercept) 38.0917 5.52243 6.90 <1e-10 27.2342 48.9491
CRIM -0.119443 0.0366674 -3.26 0.0012 -0.191534 -0.0473529
ZN 0.04478 0.0144348 3.10 0.0021 0.0164002 0.0731597
INDUS 0.00548526 0.0634058 0.09 0.9311 -0.119175 0.130145
CHAS 2.3408 0.902172 2.59 0.0098 0.567075 4.11453
NOX -16.1236 4.21177 -3.83 0.0002 -24.4042 -7.84299
RM 3.70871 0.45754 8.11 <1e-14 2.80916 4.60826
AGE -0.00312108 0.0143289 -0.22 0.8277 -0.0312926 0.0250504
DIS -1.3864 0.213951 -6.48 <1e-9 -1.80704 -0.965756
RAD 0.244178 0.070156 3.48 0.0006 0.106247 0.38211
TAX -0.0109896 0.00389829 -2.82 0.0051 -0.0186539 -0.00332534
PTRATIO -1.04592 0.136975 -7.64 <1e-12 -1.31522 -0.77662
B 0.00811011 0.00295064 2.75 0.0063 0.00230896 0.0139113
LSTAT -0.492793 0.0542393 -9.09 <1e-17 -0.599431 -0.386155
─────────────────────────────────────────────────────────────────────────────────
機械学習で得られた定数項と偏回帰係数が違うじゃないか。
傾き: [-0.97082019 1.05714873 0.03831099 0.59450642 -1.8551476 2.57321942
-0.08761547 -2.88094259 2.11224542 -1.87533131 -2.29276735 0.71817947
-3.59245482]
切片: 22.611881188118836
まず,上に示した偏回帰係数 Coef. は,標準化しないデータ(元データ)に掛ける係数である。
予測値は
predict(a);
で得られる。その最初の方を見てみると
32.55692655238963
21.927094777364772
27.543825734416142
23.603188290149532
6.5719096200611755
:
である。
機械学習では,
#訓練データ、テストデータの住宅価格を予測
y_train_pred = model.predict(X_train_std)
y_train_pred
array([32.55692655, 21.92709478, 27.54382573, 23.60318829, 6.57190962,
ということであるから,予測値は同じである。
機械学習の結果示されたのは,統計学では「標準化偏回帰係数」と呼ばれるもので,
「独立変数を標準化して重回帰分析を行ったときの偏回帰係数」というものである。
上に示された偏回帰係数にそれぞれの変数の標準偏差を掛けたものに等しい。
coefficient = coef(a)
14-element Array{Float64,1}:
38.09169492628502
-0.11944344700245542
0.044779951066505716
0.005485261681822424
2.3408036062417357
-16.123604315423176
3.708709012220785
-0.0031210817807432118
-1.38639737027842
0.24417832698878614
-0.010989636563082644
-1.0459211887458149
0.008110106932704319
-0.4927927245046289
coefficient[1] は定数項である。
coefficient[2:14] が独立変数に対する偏回帰係数である。
df_train[:. 1:13]が独立変数データ行列である。
よって,
using Statistics
coefficient[2:14] .* std(Matrix(df_train[:, 1:13]), corrected=false, dims=1)'
13×1 Array{Float64,2}:
-0.970820190461867
1.0571487264361754
0.038310993617902085
0.5945064227496165
-1.8551475975879652
2.573219418816067
-0.08761546983261663
-2.880942593098789
2.1122454191874787
-1.8753313056828191
-2.2927673485303135
0.7181794734592682
-3.5924548228794757
となり,機械学習のときの結果と同じであることがわかる。
傾き: [-0.97082019 1.05714873 0.03831099 0.59450642 -1.8551476 2.57321942
-0.08761547 -2.88094259 2.11224542 -1.87533131 -2.29276735 0.71817947
-3.59245482]
標準化偏回帰係数が必要なときには,このように追加の計算をするだけである。
次は,機械学習のときの
切片: 22.611881188118836
である。
これは簡単で,標準化しないままの従属変数の平均値である。
print(mean(df_train[:, 14]))
22.611881188118815
あれこれ書いてきたが,機械学習派は「予測値が同じならドッチでもよいじゃないか」というであろう。
しかし,重回帰分析の一つの目的である「予測」という観点からは,元のデータに掛ける偏回帰係数を示す方がよいだろう。
そうしないと,test データセットにおける予測値を計算するときに面倒な手続きが必要になる。
まず,test データセットの標準化をしなければならないが,その時に使う平均値と標準偏差は train データセットのものを使わないといけない。
#作成した標準化モデルでテストデータを変換
X_test_std = sc.transform(X_test)
y_test_pred = model.predict(X_test_std)
y_test_pred
array([24.88963777, 23.72141085, 29.36499868, 12.12238621, 21.44382254,
19.2834443 , 20.49647539, 21.36099298, 18.8967118 , 19.9280658 ,
5.12703513, 16.3867396 , 17.07776485, 5.59375659, 39.99636726,
しかし,下手の考えで標準化してからあれこれさらに余計なことなどしなくても,元の test データセットそのままで,以下のようにするだけで予測値が求まる。
predict(a, df_test)
24.889637772755968
23.72141085316374
29.364998677355622
12.122386208110687
21.44382254072625
19.28344430480102
20.496475391456304
21.360992984142296
:
というように,以上のように,機械学習は無駄なことばかりやっている。
それ以上に問題なのは,「必要なことをやっていない」ということである。
それは,分析結果の吟味である。
機械学習は,予測値がどれくらい正確かダケを見ている。
> MSEとはモデルの評価指標の一つで、この値が低いほどモデルの性能が良いと言えます。
> 算出方法は、予測値と正解の平均二乗和誤差です。
#MSEの計算
MSE_train = np.mean((y_train_pred - y_train) ** 2)
MSE_test = np.mean((y_test_pred - y_test) ** 2)
print('MSE train: ', MSE_train)
print('MSE test:', MSE_test)
MSE train: 19.32647020358573 # mean(residuals(a).^2)
MSE test: 33.44897999767649 # mean((predict(a, df_test) .- df_test[:, 14]) .^ 2)
何と比べて MSE が小さいのか?
test と比べて小さい(逆に言えば test の MSE が大きい)
それはある意味仕方ない。サンプルサイズが train:test ≒ 4:1 なのだから。
他のモデルと比べて MSE が小さいといわなければあまり意味がないのではないか。
重回帰分析結果の評価でよく使われるのは,決定係数 R2 と自由度調整済み決定係数 adj. R2 である。
これは,従属変数の分散が,独立変数によってどの程度説明できるかを表すもので,0 〜 1 の値をとり,
1 に近いほど予測がうまくいっているということになる。
r2(a) # 0.7730135569264233
adjr2(a) # 0.765447342157304
であるから,まずますではあるが,あまりよくはない。
重回帰分析の観点からは,上の方に示した GLM での解析結果 Coefficients で,Pr(>|t|) の列は,
その「変数に対する偏回帰係数が0である」という帰無仮説に対する P 値である。この値がたとえば
0.05 より大きければ,「有意水準5%で帰無仮説は棄却される」。
逆に言えば,P > 0.05 なら,「その変数の偏回帰係数は 0 でないとはいえない」のだ。
INDUS では 0.9311, AGE では 0.8277 なので,この 2 変数は予測にはあまり役立っていないということである。
b = lm(@formula(MEDV ~ CRIM+ZN+CHAS+NOX+RM+DIS+RAD+TAX+PTRATIO+B+LSTAT), df_train);
r2(b) # 0.7729811407453248
adjr2(b) # 0.7666107135723619