確率的勾配降下法までくるともう訳わかりまてん

#はじめに

なんか他の確率的降下法のサイト色々見てみたけど、
単純パーセプトロンとか、バッチ式勾配降下法とかと違いが全然分からん。


```python

class AdalineSGD(object):
    def __init__(self, eta=0.01, n_iter=10, shuffle=True, random_state=None):
        self.eta = eta
        self.n_iter = n_iter
        self.w_initialized = False
        self.shuffle = shuffle
        self.random_state = random_state

```
shuffle??
それ以外はADALINEと同じ。

```python

    def fit(self, X, y):
        self._initialize_weights(X.shape[1])
        self.cost_ = []
        for i in range(self.n_iter):　#エポックをn_iter回まわす
            if self.shuffl: #Trueの場合は循環を回避する為シャッフル
                X, y = self._shuffle(X, y)
            #各サンプルのコストを格納するリストの生成
            cost = []
            for xi, target in zip(X, y):
                #特徴量xi と目的変数y を用いた重みの更新とコストの計算　
                cost.append(self._update_weights(xi, target))
            #トレーニングサンプルの平均コストとしてエポック毎のコストの計算
            avg_cost = sum(cost) / len(y)
            #平均コストの格納
            self.cost_.append(avg_cost)
        return self
```

5,6行目：
指定された場合はシャッフルを行う。
ランダムに取ってきて、重みを更新するアルゴリズムなので、
循環を回避する為にシャッフル機能が存在する。




トレーニングサンプルごとに重みを更新する。

```python

    def partial_fit(self, X, y):
        """Fit training data without reinitializing the weights"""
        if not self.w_initialized:
            self._initialize_weights(X.shape[1])
        if y.ravel().shape[0] > 1:
            for xi, target in zip(X, y):
                self._update_weights(xi, target)
        else:
            self._update_weights(X, y)
        return self

```

partial_fitメソッドは、fitメソッドと違い、オンライン学習に合わせて、重みの初期化を行わない

オンライン学習用のメソッド


```python

    def _shuffle(self, X, y):
        """Shuffle training data"""
        r = self.rgen.permutation(len(y))
        return X[r], y[r]
```
各エポックの前にトレーニングデータをシャッフルする。
これはコスト関数を最適化する時の循環を避ける為。
numpy.randomのpermutation関数を使って0以上99以下の乱数を順列で生成。
それらの乱数は、特徴行列とクラスラベルベクトルをシャッフルする為のインデックスとして使用する。


```python

    def _initialize_weights(self, m):
        """Initialize weights to small random numbers"""
        self.rgen = np.random.RandomState(self.random_state)
        self.w_ = self.rgen.normal(loc=0.0, scale=0.01, size=1 + m)
        self.w_initialized = True
```

今までのADALINEの初期化部分が関数化された。

> self.rgen = np.random.RandomState(self.random_state)

npクラスのrandomクラスの、RandomStateクラスは、乱数を自動発生させる。
self.rgenには乱数が代入される。

> self.w_ = self.rgen.normal(loc=0.0, scale=0.01, size = 1+m)

self.w_ の重み配列を初期化する行。
normalメソッドで平均0,標準偏差0.01の正規分布からsize個のデータを引っ張ってくる。

```python

    def _update_weights(self, xi, target):
        """Apply Adaline learning rule to update the weights"""
        output = self.activation(self.net_input(xi))
        error = (target - output)
        self.w_[1:] += self.eta * xi.dot(error)
        self.w_[0] += self.eta * error
        cost = 0.5 * error**2
        return cost

```
update_weigthsはコスト関数を計算して返すメソッド。

3行目：
net_inputで総出力zが返ってきて、activationは恒等関数なのでzのまま

4行目：
target訓練用ラベル - output総出力z = error

7行目：
コスト関数J(w)を計算している。

```math
\begin{align}
J(w) &= \frac{1}{2}\sum_{i}(y^{(i)}-φ(y^{(i)}))^2
\end{align}
```


```python

    def net_input(self, X):
        """Calculate net input"""
        return np.dot(X, self.w_[1:]) + self.w_[0]
```
net_inputは総入力zを返す関数。
np.dot関数は行列の積や、ベクトルの内積を計算する。
z = w0 + w1 * x1 + w2みたいなやつを分解します。

ここではXはがく片の長さ*花びらの長さの二次元。
self.w_[1:]は、w1,w2の二次元。
self.w_[0]はw0の一次元。
なので行列の積が求まる。

よって、
z = np.dot(X,self.w_[1:]) + self.w_[0]
これが総入力！これをreturn

```python

    def activation(self, X):
        """Compute linear activation"""
        return X

    def predict(self, X):
        """Return class label after unit step"""
        return np.where(self.activation(self.net_input(X)) >= 0.0, 1, -1)


```

```python


X_std = np.copy(X)
X_std[:, 0] = (X[:, 0] - X[:, 0].mean()) / X[:, 0].std()
X_std[:, 1] = (X[:, 1] - X[:, 1].mean()) / X[:, 1].std()

ada = AdalineSGD(n_iter=15, eta=0.01, random_state=1)
ada.fit(X_std, y)
```

```python

#境界領域のプロット
plot_decision_regions(X_std, y, classifier=ada)
plt.title('Adaline - Stochastic Gradient Descent')
plt.xlabel('sepal length [standardized]')
plt.ylabel('petal length [standardized]')
plt.legend(loc='upper left')

```

[plot_decision_regios](https://rasbt.github.io/mlxtend/user_guide/plotting/plot_decision_regions/)は分類機の境界線をプロットする関数。

```python

plt.tight_layout()
# plt.savefig('images/02_15_1.png', dpi=300)
plt.show()

plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Average Cost')

plt.tight_layout()
# plt.savefig('images/02_15_2.png', dpi=300)
plt.show()




ada.partial_fit(X_std[0, :], y[0])



# # Summary

# ...

# ---
#
# Readers may ignore the following cell

```