こんにちは、また久しぶりの投稿になってしまいました。
久しぶりということでtipsとかではなく、ちゃんとした記事書きます。
初めて、理論の本から実装したので、まだまだ甘い部分が目立ちますが許してください。
※3/25 追記
ket-30.hatenablog.com
こっちに今回のコードを改善しつつCWも実装しています。
こっちの記事は結構良くない部分が目立つので、ぜひ参考にしてくださるのであれば、こちらを見てみてください。(むしろご指摘待ってます。)
オンライン学習
まずオンライン学習について、軽く。
まあ僕なんかの説明より本読んだ方が早いっすけど。笑
オンライン学習とは、機械学習の手法の1つです。
通常の機械学習では、データセットを全て舐めて重みのパラメータ調整を行なっていきます。
それに比べてオンライン学習は、1つのデータだけで学習行うという手法です。
1つのデータを読み込み学習する。これを繰り返して重みを調整していくということですね。
デメリット
- 後半に同じラベルのデータを繰り返し読み込んでしまうと、そのラベルに学習が偏ってしまう。
個人的にメリットの方が大きいと思います。
実際には、twitterやyahooなど、毎日大量のデータが手に入る会社が使っているようです。
Passive Aggresssive
Passive Aggressive(以下PA) は、オンライン学習のアルゴリズムの一つで基本となっているもの?らしいです。
まあ古いアルゴリズムなんですかね。
詳しい理論は他サイトや本で確認してください。
理論書いていくのホントめんどい笑
すみません。
実装
pythonコードはこちら。
#coding:utf-8 import numpy as np class PassiveAggressive: def __init__(self, feat_dem=None):#feat_dem="特徴量の次元数" self.t = 0 if feat_dem is not None: self.w = np.ones(feat_dem+1) else: self.w = None self.feat_dem = feat_dem #--------クラス内で使うメソッド----------- def L_hinge(self,feats, y): loss = max([0, 1-y*self.w.dot(feats)]) return loss def update(self, feats, y): loss = self.L_hinge(feats,y) norm = feats.dot(feats) eta = loss/norm #重み更新 #loss=0だったらeta=0 self.w += eta*y*feats self.t += 1#更新回数 #---------呼び出すメソッド------------- def fit(self, feats_vec, y_vec): if self.w is None: weight_dem = len(feats_vc) #全ての要素(引数が次元)が1になるベクトルを作成する self.w = np.ones(weight_em) self.update(feats_vec, y_vec) def predict(self, feats): pred = self.w.dot(feats) return 1 if pred > 0 else -1
このモジュールを使って、次を実行させるとオンライン学習ちっくなことができます。
#coding:utf-8 import numpy as np import pandas as pd import matplotlib.pyplot as plt from passive_aggressive import PassiveAggressive plt.style.use('ggplot') #create datas def make_data(N, draw_plot=True, is_confused=False, confuse_bin=50): #N個のデータセットを作成する #データにノイズをかけるためis_confusedを実装する np.random.seed(1)#シードを固定すると乱数が毎回同じ出力になる feature = np.random.randn(N, 2)#N*2の行列を作成 df = pd.DataFrame(feature, columns=["x","y"]) #二値分類の付与: 人為的な分離戦の上下何方にいるかで機械的に判定 #ここの値がラベルになる df["c"] = df.apply(lambda row : 1 if (5*row.x + 3*row.y -1)>0 else -1, axis=1) #データの攪乱 if is_confused: def get_model_confused(data): c = 1 if (data.name % confuse_bin) == 0 else data.c return c df["c"] = apply(get_model_confused, axis=1) #データの可視化: どんな感じのデータになったかをグラフ化する if draw_plot: plt.scatter(x=df.x, y=df.y, c=df.c, alpha=0.6)#cはカラーにあたる。 plt.xlim([df.x.min() - 0.1, df.x.max() + 0.1]) plt.ylim([df.y.min() - 0.1, df.y.max() + 0.1]) return df def draw_split_line(weight_vector): a,b,c = weight_vector x = np.array(range(-10,10,1)) y = (a * x + c)/-b plt.plot(x,y, alpha=0.3) #データセットの作成 dataset = make_data(1000) print(dataset.head(5)) feats_vec = dataset.ix[:,"x":"y"] feats_vec["b"] = np.ones(dataset.shape[0]) feats_vec = feats_vec.as_matrix() print(feats_vec) y_vec = dataset.ix[:,2] y_vec = y_vec.as_matrix() model = PassiveAggressive() #引数は特徴量の次元数 #引数がない場合は勝手に次元数読み込みます。 #オンライン学習 for i in range(len(y_vec)): model.fit(feats_vec[i,],y_vec[i]) draw_split_line(model.w) print(model.w) plt.show()
ちなみに
from passive_aggressive import PassiveAggressive
で先ほどのモジュールを読み込んでいます。
学習結果
実行結果はこんな感じ。
若干ずれていますが、学習できていますね。
初めてにしては上出来...でしょ!!(自分に甘くしていくスタイル)
p.s. いやいやちゃんと理論かけよ自分...
参考サイト様
実装して理解するオンライン学習器(1) - PassiveAggresive - About connecting the dots.
統計の素人だけどPythonで機会学習モデルを実装したい、そんな人のための第一歩 - Qiita