[PYTHON] Algorithme d'apprentissage automatique (implémentation de la classification multi-classes)

introduction

Pas à pas sur la théorie, l'implémentation en python et l'analyse à l'aide de scikit-learn sur l'algorithme précédemment repris dans "Classification of Machine Learning" J'étudierai avec. Je l'écris pour un apprentissage personnel, alors j'aimerais que vous oubliez toute erreur.

Dernière fois, la classification à 2 classes a été étendue à la classification multi-classes. Cette fois, je vais l'implémenter en Python.

J'ai fait référence aux sites suivants. Merci beaucoup.

Politique de mise en œuvre

Je voudrais étendre Régression logistique précédemment implémentée à plusieurs classes. La méthode est

Je vais essayer.

Données utilisées pour la classification

Les données Ayame sont utilisées pour la classification. Il utilise 4 quantités de caractéristiques (sepal_length, sepal_width, petal_length, petal_width) et les classe en 3 classes (setosa, versicolor, virginica).

Ci-dessous, nous allons implémenter la classification en utilisant sepal_length et sepal_width pour plus de clarté.

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

%matplotlib inline

from sklearn.datasets import load_iris

sns.set()
iris = sns.load_dataset("iris")
ax = sns.scatterplot(x=iris.sepal_length, y=iris.sepal_width,
                     hue=iris.species, style=iris.species)
qiita_classifier_multi_1.png

One-vs-Rest One-vs-Rest crée un classificateur à deux classes pour chaque classe d'étiquette à apprendre, et utilise enfin la valeur la plus plausible. Puisque la régression logistique produit une valeur de probabilité, la classification du classificateur avec la probabilité la plus élevée est adoptée.

Utilisez la classe LogisticRegression, qui est une version légèrement modifiée du code de régression logistique que nous avons utilisé la dernière fois. J'ai fait une méthode predict_proba car elle détermine quelle valeur utiliser avec une probabilité.

from scipy import optimize

class LogisticRegression:
  def __init__(self):
    self.w = None

  def sigmoid(self, a):
    return 1.0 / (1 + np.exp(-a))

  def predict_proba(self, x):
    x = np.hstack([1, x])
    return self.sigmoid(self.w.T @ x)
  
  def predict(self, x):
    return 1 if self.predict_proba(x)>=0.5 else -1

  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 = 1 if t[i] > 0 else 0
      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 = 1 if t[i] > 0 else 0
      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

Implémentez la classe One-vs-Rest. J'ai également implémenté la méthode ʻaccuracy_score` pour calculer à quel point la réponse est correcte, car je l'utiliserai plus tard pour la comparaison d'algorithmes.

from sklearn.metrics import accuracy_score

class OneVsRest:
  def __init__(self, classifier, labels):
    self.classifier = classifier
    self.labels = labels
    self.classifiers = [classifier() for _ in range(len(self.labels))]

  def fit(self, x, y):
    y = np.array(y)
    for i in range(len(self.labels)):
      y_ = np.where(y==self.labels[i], 1, 0)
      self.classifiers[i].fit(x, y_)

  def predict(self, x):
    probas = [self.classifiers[i].predict_proba(x) for i in range(len(self.labels))]
    return np.argmax(probas)

  def accuracy_score(self, x, y):
    pred = [self.labels[self.predict(i)] for i in x]
    acc = accuracy_score(y, pred)
    return acc

Classifiez en fait en utilisant les données précédentes.

model = OneVsRest(LogisticRegression, np.unique(iris.species))
x = iris[['sepal_length', 'sepal_width']].values
y = iris.species
model.fit(x, y)
print("accuracy_score: {}".format(model.accuracy_score(x,y)))

accuracy_score: 0.8066666666666666

Le taux de réponse correcte de 81% n'est pas très bon. Visualisons comment il a été classé. Utilisez la méthode contourf de matplotlib pour la visualisation. Couleurs selon lesquelles la valeur du point de grille est classée

from matplotlib.colors import ListedColormap

x_min = iris.sepal_length.min()
x_max = iris.sepal_length.max()
y_min = iris.sepal_width.min()
y_max = iris.sepal_width.max()

x = np.linspace(x_min, x_max, 100)
y = np.linspace(y_min, y_max, 100)

data = []
for i in range(len(y)):
  data.append([model.predict([x[j], y[i]]) for j in range(len(x))])

xx, yy = np.meshgrid(x, y)

cmap = ListedColormap(('blue', 'orange', 'green'))
plt.contourf(xx, yy, data, alpha=0.25, cmap=cmap)
ax = sns.scatterplot(x=iris.sepal_length, y=iris.sepal_width,
                     hue=iris.species, style=iris.species)
plt.show()
qiita_classifier_multi_2.png

Comme vous pouvez le voir, setosa est correctement classé, mais les deux classes restantes sont mixtes, il semble donc que le taux de réponse correct soit un peu faible. Pour le moment, ce sera comme ça.

Soft Max multi-classes

Implémentez la classe LogisticRegressionMulti pour la classification softmax dans la régression logistique.

L'erreur d'entropie croisée a été utilisée comme fonction d'erreur pour l'évaluation, et les paramètres ont été calculés en utilisant la méthode de descente de gradient la plus raide. Je l'ai fait assez correctement, je suis désolé

from sklearn.metrics import accuracy_score

class LogisticRegressionMulti:
  def __init__(self, labels, n_iter=1000, eta=0.01):
    self.w = None
    self.labels = labels
    self.n_iter = n_iter
    self.eta = eta
    self.loss = np.array([])

  def softmax(self, a):
    if a.ndim==1:
      return np.exp(a)/np.sum(np.exp(a))
    else:
      return np.exp(a)/np.sum(np.exp(a), axis=1)[:, np.newaxis]

  def cross_entropy_loss(self, w, *args):
    x, y = args
    def safe_log(x, minval=0.0000000001):
      return np.log(x.clip(min=minval))
    
    p = self.softmax(x @ w)
    loss = -np.sum(y*safe_log(p))

    return loss/len(x)

  def grad_cross_entropy_loss(self, w, *args):
    x, y = args

    p = self.softmax(x @ w)
    grad = -(x.T @ (y-p))

    return grad/len(x)

  def fit(self, x, y):
    self.w = np.ones((len(x[0])+1, len(self.labels)))
    x = np.hstack([np.ones((len(x),1)), x])

    for i in range(self.n_iter):
      self.loss = np.append(self.loss, self.cross_entropy_loss(self.w, x, y))
      grad = self.grad_cross_entropy_loss(self.w, x, y)
      self.w -= self.eta * grad
  
  def predict(self, x):
    x = np.hstack([1, x])
    return np.argmax(self.softmax(x @ self.w))

  def accuracy_score(self, x, y):
    pred = [self.predict(i) for i in x]
    y_ = np.argmax(y, axis=1)

    acc = accuracy_score(y_, pred)
    return acc

  @property
  def loss_(self):
    return self.loss

L'entrée dans LogisticRegressionMulti utilise une étiquette One-Hot-Encoded. C'est facile avec les pandas 'get_dummies'. (J'ai pensé après l'avoir fait, mais j'aurais dû utiliser get_dummies dans la classe)

model = LogisticRegressionMulti(np.unique(iris.species), n_iter=10000, eta=0.1)
x = iris[['sepal_length', 'sepal_width']].values
y = pd.get_dummies(iris['species']).values
model.fit(x, y)
print("accuracy_score: {}".format(model.accuracy_score(x, y)))

accuracy_score: 0.8266666666666667

Le taux de réponse correcte est d'environ 83%. En regardant l'historique des erreurs, il semble qu'il a convergé, donc cela semble être le cas.

qiita_classifier_multi_3.png

Aussi, colorions comment il est classé de la même manière qu'avant.

qiita_classifier_multi_4.png

Comparez avec la régression logistique de scikit-learn

Enfin, en utilisant toutes les fonctionnalités, comparez le classificateur créé cette fois avec la classe LogisticRegression de scikit-learn.

Méthode accuracy_score
OneVsRest 0.98
LogisticRegressionMulti 0.98
sklearn LogisticRegression 0.973

Même avec cette implémentation, il semble que vous puissiez obtenir un bon score s'il s'agit de la classification d'Ayame.

Résumé

Implémentation de la classification multi-classes à l'aide de la régression logistique. Je pense que d'autres classificateurs peuvent être utilisés de la même manière. Surtout dans les réseaux de neurones, le softmax multi-classes est une méthode courante, j'ai donc pensé qu'il serait utile de comprendre la partie théorique plus tard.

Recommended Posts

Algorithme d'apprentissage automatique (implémentation de la classification multi-classes)
Résumé de la classification et de la mise en œuvre des algorithmes d'apprentissage automatique
Classification de l'apprentissage automatique
Algorithme d'apprentissage automatique (généralisation de la régression linéaire)
Mémo d'étude Python & Machine Learning ⑤: Classification d'Ayame
Algorithme d'apprentissage automatique (de la classification à 2 classes à la classification à plusieurs classes)
Classification des images de guitare par apprentissage automatique, partie 2
Techniques liées à l'apprentissage automatique / à la classification
Bases de l'apprentissage automatique (mémoire)
À propos des tests dans la mise en œuvre de modèles d'apprentissage automatique
Apprendre avec l'enseignant 1 Principes de base de l'apprentissage avec l'enseignant (classification)
Algorithme d'apprentissage automatique (perceptron simple)
Importance des ensembles de données d'apprentissage automatique
Machine learning supervisé (classification / régression)
Algorithme d'apprentissage automatique (machine vectorielle de support)
Apprentissage par renforcement profond 2 Mise en œuvre de l'apprentissage par renforcement
Algorithme d'apprentissage automatique (régression logistique)
Programmation Python Machine Learning Chapitre 2 Problèmes de classification - Résumé de la formation à l'algorithme d'apprentissage automatique
Essayez d'évaluer les performances du modèle d'apprentissage automatique / de classification
<Course> Machine learning Chapitre 6: Algorithme 2 (k-means)
Explication et implémentation de l'algorithme ESIM
Importance de l'apprentissage automatique et de l'apprentissage par mini-lots
Qiskit: Implémentation de Quantum Boltsman Machine
Algorithme d'apprentissage automatique (prise en charge de l'application de machine vectorielle)
Apprentissage automatique par python (1) Classification générale
Algorithme d'apprentissage automatique (analyse de régression multiple)
Apprentissage automatique ③ Résumé de l'arbre de décision
Algorithme d'apprentissage automatique (analyse de régression unique)
Classification et régression dans l'apprentissage automatique
Algorithme d'apprentissage automatique (méthode de descente de gradient)
Implémentation de la méthode Dyxtra par python
Apprentissage automatique
Classification multi-étiquette d'images multi-classes avec pytorch
Deep learning 2 appris par l'implémentation (classification d'images)
Othello-De la troisième ligne de "Implementation Deep Learning" (3)
[Apprentissage automatique] Classification des sujets LDA à l'aide de scikit-learn
Implémentation d'un réseau neuronal à 3 couches (pas d'apprentissage)
20 sélections recommandées en 2020 de livres d'introduction à l'apprentissage automatique
Explication et implémentation de l'algorithme Decomposable Attention
[Apprentissage automatique] Liste des packages fréquemment utilisés
Algorithme d'apprentissage automatique (résumé de régression linéaire et régularisation)
Classification EV3 x Pyrhon Machine Learning Partie 3
Othello-De la troisième ligne de "Implementation Deep Learning" (2)
Mémo d'apprentissage automatique d'un ingénieur débutant Partie 1
Algorithme EM modèle mixte gaussien [apprentissage automatique statistique]
Début de l'apprentissage automatique (matériel didactique / informations recommandés)
Apprentissage automatique du sport-Analyse de la J-League à titre d'exemple-②
[Super Introduction] Apprentissage automatique utilisant Python - De la construction d'environnement à l'implémentation de perceptron simple-
Tournoi Numerai - Fusion de quants traditionnels et apprentissage automatique -
[Mémo d'apprentissage] Apprentissage profond à partir de zéro ~ Mise en œuvre de l'abandon ~
Mémo d'étude Python & Machine Learning ②: Introduction de la bibliothèque
SVM (classification multi-classes)
Algorithme d'apprentissage du dictionnaire
Liste des liens que les débutants en apprentissage automatique apprennent
Vue d'ensemble des techniques d'apprentissage automatique apprises grâce à scikit-learn
À propos du contenu de développement de l'apprentissage automatique (exemple)
Résumé des fonctions d'évaluation utilisées dans l'apprentissage automatique
Analyse de l'utilisation de l'espace partagé par l'apprentissage automatique