他の 100 本ノックシリーズ

言語処理 100 本ノック(第 6 章: 機械学習)

使用するパラメータや変数の一部は前半で使用したものを使っています。

55. 混同行列の作成

52 で学習したロジスティック回帰モデルの混同行列(confusion matrix)を,学習データおよび評価データ上で作成せよ.

from sklearn.metrics import confusion_matrix

print("訓練データ")
print('confusion matrix = \n', confusion_matrix(y_true=train_Y, y_pred=train_Y_pred))
print()
print("検証データ")
print('confusion matrix = \n', confusion_matrix(y_true=valid_Y, y_pred=valid_Y_pred))
訓練データ
confusion matrix =
 [[4522   12    0   23]
 [  13 4165    0    2]
 [  10    7  727    0]
 [  50   17    1 1135]]

検証データ
confusion matrix =
 [[511  11   3  18]
 [ 13 524   2   3]
 [ 15  11  62   4]
 [ 33  26   0 100]]

前回記事と比較してみて要素数は合っていそうです。

56. 適合率,再現率,F1 スコアの計測

52 で学習したロジスティック回帰モデルの適合率,再現率,F1 スコアを,評価データ上で計測せよ.カテゴリごとに適合率,再現率,F1 スコアを求め,カテゴリごとの性能をマイクロ平均(micro-average)とマクロ平均(macro-average)で統合せよ.

from sklearn.metrics import precision_score, recall_score, f1_score

# 適合率,再現率,F1スコア
print('適合率: ', precision_score(y_true=valid_Y, y_pred=valid_Y_pred, average='macro'))
print('再現率: ', recall_score(y_true=valid_Y, y_pred=valid_Y_pred, average='macro'))
print('F1スコア: ', f1_score(y_true=valid_Y, y_pred=valid_Y_pred, average='macro'))
適合率:  0.8837034234422294
再現率:  0.8026754172370425
F1スコア:  0.8353613834243956

適合率は分類されたものが実際にそのクラスである割合、

再現率はあるクラスのうち、実際にそのクラスに分類された割合

F1スコアは適合率と再現率の調和平均

57. 特徴量の重みの確認

52 で学習したロジスティック回帰モデルの中で,重みの高い特徴量トップ 10 と,重みの低い特徴量トップ 10 を確認せよ.

weights = {}
for i,w in enumerate(lr.coef_[0]):
  weights[dct[i]] = w

sw = sorted(weights.items(), key=lambda x: x[1])

print("低いの")
print(*sw[:10], sep="\n")
print()
print("重いの")
print(*sw[-10:], sep="\n")
低いの
('Aereo', -1.4943036354257244)
('Ebola', -1.1926602012817413)
('past', -1.1663878014633782)
('virus', -1.1543506450531948)
('video', -1.1108024121277575)
('Hat', -1.101384620566056)
('baby', -1.0766692762320573)
('child', -1.0604199141307464)
('soda', -1.0543633796789418)
('Activision', -1.041767185267918)

重いの
('Uber', 1.4360522689124577)
('profit', 1.456241534603359)
('China', 1.4986359849111417)
('bank', 1.5456660201232657)
('Argentina', 1.5867187020325588)
('ECB', 1.7131083455287186)
('Yellen', 1.749698918090413)
('Fed', 1.8263312436827537)
('Ukraine', 1.8665880775606447)
('Bank', 1.9822040580267537)

58. 正則化パラメータの変更

ロジスティック回帰モデルを学習するとき,正則化パラメータを調整することで,学習時の過学習(overfitting)の度合いを制御できる.異なる正則化パラメータでロジスティック回帰モデルを学習し,学習データ,検証データ,および評価データ上の正解率を求めよ.実験の結果は,正則化パラメータを横軸,正解率を縦軸としたグラフにまとめよ.

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

lrl1 = LogisticRegression(penalty="l1", solver='liblinear', max_iter=1000)
lrl1.fit(train_X, train_Y)

train_Y_pred = lrl1.predict(train_X)
valid_Y_pred = lrl1.predict(valid_X)

print('訓練データ:', accuracy_score(y_true=train_Y, y_pred=train_Y_pred))
print('検証データ:', accuracy_score(y_true=valid_Y, y_pred=valid_Y_pred))
訓練データ: 0.9514226881317859
検証データ: 0.875748502994012

前回記事をまんま流用L1正則化で学習させました。

59. ハイパーパラメータの探索

学習アルゴリズムや学習パラメータを変えながら,カテゴリ分類モデルを学習せよ.検証データ上の正解率が最も高くなる学習アルゴリズム・パラメータを求めよ.また,その学習アルゴリズム・パラメータを用いたときの評価データ上の正解率を求めよ.

アルゴリズムl1, l2においてそれぞれC1/100, 1/10, 1, 10, 100と変化させつつ学習結果を見る。

params = [{
    "model": LogisticRegression,
    "penalty": penalty,
    "solver": solver,
    "C": 10**i,
    }
    for i in range(-2, 3)
    for penalty, solver in  [("l1", "liblinear"), ("l2", "lbfgs")]]

for p in params:
  lr = p["model"](C=p["C"], penalty=p["penalty"], solver=p["solver"], max_iter=1000)
  lr.fit(train_X, train_Y)

  valid_Y_pred = lr.predict(valid_X)
  acc = accuracy_score(y_true=valid_Y, y_pred=valid_Y_pred)
  p["acc"] = acc

params.sort(key=lambda x: x.get("acc"))
print(*params, sep="\n")
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l1', 'solver': 'liblinear', 'C': 0.01, 'acc': 0.5883233532934131}
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l2', 'solver': 'lbfgs', 'C': 0.01, 'acc': 0.7567365269461078}
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l1', 'solver': 'liblinear', 'C': 0.1, 'acc': 0.7574850299401198}
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l2', 'solver': 'lbfgs', 'C': 0.1, 'acc': 0.8562874251497006}
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l1', 'solver': 'liblinear', 'C': 1, 'acc': 0.875748502994012}
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l1', 'solver': 'liblinear', 'C': 100, 'acc': 0.8809880239520959}
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l2', 'solver': 'lbfgs', 'C': 100, 'acc': 0.8832335329341318}
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l1', 'solver': 'liblinear', 'C': 10, 'acc': 0.8884730538922155}
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l2', 'solver': 'lbfgs', 'C': 1, 'acc': 0.8959580838323353}
{'model': <class 'sklearn.linear_model._logistic.LogisticRegression'>, 'penalty': 'l2', 'solver': 'lbfgs', 'C': 10, 'acc': 0.8974550898203593}

正規化度合い(C 値)が影響を与えているのがよくわかりますね。

その中でもL2正規化C=10が一番いい結果になりました。