Schritt für Schritt zur Theorie, Implementierung in Python und Analyse mit scikit-learn über den Algorithmus, der zuvor in "Klassifikation des maschinellen Lernens" verwendet wurde. Ich werde mit lernen. Ich schreibe es zum persönlichen Lernen, daher möchte ich, dass Sie alle Fehler übersehen.
Diesmal über ** Logistic Return **. Die logistische Regression ist auch ein Algorithmus, der die binäre Klassifizierung wie Perceptron behandelt, obwohl er als Regression geschrieben ist.
Die folgenden Seiten wurden auf diese Zeit verwiesen. Vielen Dank.
In Bezug auf die Theorie der logistischen Regression leiten wir zunächst die Aktivierungsfunktion ** Sigmoidfunktion ** ab.
Da die logistische Regression eine binäre Klassifizierung ist, sollten Sie die Klassen $ C_1 $ und $ C_2 $ berücksichtigen. Die Summe der $ C_1 $ Wahrscheinlichkeit $ P (C_1) $ und der $ C_2 $ Wahrscheinlichkeit $ P (C_2) $ ist 1.
Die Wahrscheinlichkeit, $ C_1 $ zu werden, wenn die Datenzeichenfolge $ \ boldsymbol {x} $ angegeben wird, ergibt sich aus dem Satz von ** Bayes **.
\begin{align}
P(C_1|\boldsymbol{x})&=\frac{P(\boldsymbol{x}|C_1)P(C_1)}{P(\boldsymbol{x})} \\
&= \frac{P(\boldsymbol{x}|C_1)P(C_1)}{P(\boldsymbol{x}|C_1)P(C_1)+P(\boldsymbol{x}|C_2)P(C_2)} \\
&= \frac{1}{1+\frac{P(\boldsymbol{x}|C_2)P(C_2)}{P(\boldsymbol{x}|C_1)P(C_1)}} \\
&= \frac{1}{1+\exp(-\ln\frac{P(\boldsymbol{x}|C_1)P(C_1)}{P(\boldsymbol{x}|C_2)P(C_2)})} \\
&= \frac{1}{1+\exp(-a)} = \sigma(a)
\end{align}
Dieses $ \ sigma (a) $ heißt ** Sigmoidfunktion **. Die Sigmoidfunktion nimmt einen Wert von 0 bis 1 an, wie unten gezeigt, daher ist es eine bequeme Funktion, die Wahrscheinlichkeit auszudrücken.
Verwenden Sie die angegebene Datenzeichenfolge $ \ boldsymbol {x} = (x_0, x_1, \ cdots, x_n) $ und die Klassifizierung des Lehrers $ \ boldsymbol {t} = (t_0, t_1, \ cdots, t_n) $
L(\boldsymbol{x})=\frac{1}{1+\exp(-\boldsymbol{w}^T\boldsymbol{x})}
Wir werden den Parameter $ \ boldsymbol {w} = (w_0, w_1, \ cdots, w_n) $ von optimieren.
Gibt es
Dies auf alle Daten anwenden
\begin{align}
P(\boldsymbol{t}|\boldsymbol{x})&=P(t_0|x_0)P(t_1|X_1)\cdots P(t_{n-1}|x_{n-1}) \\
&=\prod_{i=0}^{n-1}P(t_i|x_i) \\
&=\prod_{i=1}^{n-1}p_i^{t_i}(1-p_i)^{1-t_i}
\end{align}
Es wird sein. Den Logarithmus beider Seiten nehmen,
\log P(\boldsymbol{t}|\boldsymbol{x}) = \sum_{i=0}^{n-1}\{t_i\log p_i+(1-t_i)\log (1-p_i)\}
Dies wird als ** Protokollwahrscheinlichkeit ** bezeichnet, wobei das Vorzeichen invertiert wird, um die Protokollwahrscheinlichkeit zu maximieren.
E(\boldsymbol{x}) = -\frac{1}{n}\log P(\boldsymbol{t}|\boldsymbol{x}) = \frac{1}{n}\sum_{i=0}^{n-1}\{-t_i\log p_i-(1-t_i)\log (1-p_i)\}
Dieses $ E $ wird als ** Kreuzentropiefehlerfunktion ** bezeichnet. Die Differenzierung von $ E $ wird später verwendet.
\frac{\partial{E}}{\partial{w_i}}=\frac{1}{n}\sum_{i=0}^{n-1}(p_i-t_i)x_i
(Erklärung weggelassen)
Um die Kreuzentropiefehlerfunktion zu minimieren, verwenden wir die zuvor entwickelte Gradientenmethode. Auch hier können die Methode mit dem steilsten Abstieg und die Methode mit dem probabilistischen Gradientenabstieg verwendet werden, es wird jedoch die ** Conjugate Gradient Method ** verwendet. Weitere Informationen finden Sie unter [Wikipedia: Conjugated Gradient Method](https://ja.wikipedia.org/wiki/%E5%85%B1%E5%BD%B9%E5%8B%BE%E9%85%8D%E6% Ich werde es B3% 95) geben, aber es ist ein Algorithmus, der schneller als die Methode mit dem steilsten Gradienten ist und konvergiert, ohne die Lernrate festzulegen. Ich möchte dies auch mit Python implementieren, aber es ist problematisch (!) Scipy.optimize.fmin_cg von Python Wir verwenden eine Bibliothek namens .fmin_cg.html).
Wir werden die LogisticRegression-Klasse unter Verwendung der bisherigen Theorie implementieren. fmin_cg verwendet die zuvor erwähnte Gradientenfunktion, da sie bei einer Gradientenfunktion gute Ergebnisse liefert.
from scipy import optimize
class LogisticRegression:
def __init__(self):
self.w = np.array([])
def sigmoid(self, a):
return 1.0 / (1 + np.exp(-a))
def cross_entropy_loss(self, w, *args):
def safe_log(x, minval=0.0000000001):
return np.log(x.clip(min=minval))
t, x = args
loss = 0
for i in range(len(t)):
ti = (t[i]+1)/2
h = self.sigmoid(w.T @ x[i])
loss += -ti*safe_log(h) - (1-ti)*safe_log(1-h)
return loss/len(t)
def grad_cross_entropy_loss(self, w, *args):
t, x = args
grad = np.zeros_like(w)
for i in range(len(t)):
ti = (t[i]+1)/2
h = self.sigmoid(w.T @ x[i])
grad += (h - ti) * x[i]
return grad/len(t)
def fit(self, x, y):
w0 = np.ones(len(x[0])+1)
x = np.hstack([np.ones((len(x),1)), x])
self.w = optimize.fmin_cg(self.cross_entropy_loss, w0, fprime=self.grad_cross_entropy_loss, args=(y, x))
@property
def w_(self):
return self.w
Verwenden wir diese Klasse, um Irisdaten zu klassifizieren. Zeichnen Sie auch die Grenze. Die Grenze ist eine Linie von $ \ boldsymbol {w} ^ T \ boldsymbol {x} = 0 $. Ich habe die 2 Klassen in 1 und -1 geändert und den Code entsprechend erstellt.
df = df_iris[df_iris['target']!='setosa']
df = df.drop(df.columns[[1,2]], axis=1)
df['target'] = df['target'].map({'versicolor':1, 'virginica':-1})
#Zeichnen eines Diagramms
fig, ax = plt.subplots()
df_versicolor = df_iris[df_iris['target']=='versicolor']
x1 = df_iris[df_iris['target']=='versicolor'].iloc[:,3].values
y1 = df_iris[df_iris['target']=='versicolor'].iloc[:,0].values
x2 = df_iris[df_iris['target']=='virginica'].iloc[:,3].values
y2 = df_iris[df_iris['target']=='virginica'].iloc[:,0].values
xs = StandardScaler()
ys = StandardScaler()
xs.fit(np.append(x1,x2).reshape(-1, 1))
ys.fit(np.append(y1,y2).reshape(-1, 1))
x1s = xs.transform(x1.reshape(-1, 1))
x2s = xs.transform(x2.reshape(-1, 1))
y1s = ys.transform(y1.reshape(-1, 1))
y2s = ys.transform(y2.reshape(-1, 1))
x = np.concatenate([np.concatenate([x1s, y1s], axis=1), np.concatenate([x2s, y2s], axis=1)])
y = df['target'].values
model = LogisticRegression()
model.fit(x, y)
ax.scatter(x1s, y1s, color='red', marker='o', label='versicolor')
ax.scatter(x2s, y2s, color='blue', marker='s', label='virginica')
ax.set_xlabel("petal width (cm)")
ax.set_ylabel("sepal length (cm)")
#Klassifizierungsgrenzen zeichnen
w = model.w_
x_fig = np.linspace(-2.,2.,100)
y_fig = [-w[1]/w[2]*xi-w[0]/w[2] for xi in x_fig]
ax.plot(x_fig, y_fig)
ax.set_ylim(-2.5,2.5)
ax.legend()
print(w)
plt.show()
Optimization terminated successfully.
Current function value: 0.166434
Iterations: 12
Function evaluations: 41
Gradient evaluations: 41
[-0.57247091 -5.42865492 -0.20202263]
Es scheint, dass sie ziemlich ordentlich klassifiziert werden können.
scikit-learn hat auch eine LogisticRegression-Klasse, daher ist sie fast identisch mit dem obigen Code.
from sklearn.linear_model import LogisticRegression
df = df_iris[df_iris['target']!='setosa']
df = df.drop(df.columns[[1,2]], axis=1)
df['target'] = df['target'].map({'versicolor':1, 'virginica':-1})
#Zeichnen eines Diagramms
fig, ax = plt.subplots()
df_versicolor = df_iris[df_iris['target']=='versicolor']
x1 = df_iris[df_iris['target']=='versicolor'].iloc[:,3].values
y1 = df_iris[df_iris['target']=='versicolor'].iloc[:,0].values
x2 = df_iris[df_iris['target']=='virginica'].iloc[:,3].values
y2 = df_iris[df_iris['target']=='virginica'].iloc[:,0].values
xs = StandardScaler()
ys = StandardScaler()
xs.fit(np.append(x1,x2).reshape(-1, 1))
ys.fit(np.append(y1,y2).reshape(-1, 1))
x1s = xs.transform(x1.reshape(-1, 1))
x2s = xs.transform(x2.reshape(-1, 1))
y1s = ys.transform(y1.reshape(-1, 1))
y2s = ys.transform(y2.reshape(-1, 1))
x = np.concatenate([np.concatenate([x1s, y1s], axis=1), np.concatenate([x2s, y2s], axis=1)])
y = df['target'].values
model = LogisticRegression(C=100)
model.fit(x, y)
ax.scatter(x1s, y1s, color='red', marker='o', label='versicolor')
ax.scatter(x2s, y2s, color='blue', marker='s', label='virginica')
ax.set_xlabel("petal width (cm)")
ax.set_ylabel("sepal length (cm)")
#Klassifizierungsgrenzen zeichnen
w = model.coef_[0]
x_fig = np.linspace(-2.,2.,100)
y_fig = [-w[0]/w[1]*xi-model.intercept_/w[1] for xi in x_fig]
ax.plot(x_fig, y_fig)
ax.set_ylim(-2.5,2.5)
ax.legend()
plt.show()
Dies wird auch als gut eingestuft.
Wir haben die logistische Regression zusammengefasst, die in der Welt des maschinellen Lernens relativ wichtig ist (angenommen wird). Die Theorie ist von hier aus schwieriger geworden.
Recommended Posts