Implémentation python de la classe de régression linéaire bayésienne

introduction

J'avais peur qu'il n'y ait pas beaucoup d'implémentations correctes de la régression linéaire bayésienne dans le monde, et il y a peu d'implémentations qui prennent en charge l'entrée multidimensionnelle, donc je l'ai implémentée comme une classe facile à utiliser. La description suit essentiellement PRML.

Classe implémentée

Cela dit, ce n'est pas aussi gros qu'une implémentation, c'est environ 50 lignes ... J'écrirai toute la classe ici. Ses fonctions sont les suivantes. C'est très simple.

-Donner une combinaison de $ \ phi $ et $ t $ pour calculer la distribution postérieure

Beyes_LR.py


import numpy as np
from scipy.stats import multivariate_normal

class BeyesLinearRegression:
    def __init__(self, mu, S, beta):
        self.mu = mu
        self.S = S
        self.beta = beta

    def calc_posterior(self, phi, t):
        S_inv = np.linalg.inv(self.S)

        if len(phi.shape) == 1:
            phi = phi.reshape(1, -1)
            t = t.reshape(1, 1)
        self.S = np.linalg.inv(S_inv + self.beta * phi.T @ phi)
        self.mu = self.S @ (S_inv @ self.mu + np.squeeze(self.beta * phi.T @ t))

    def sampling_params(self, n=1, random_state=0):
        np.random.seed(random_state)
        return np.random.multivariate_normal(self.mu, self.S, n)

    def probability(self, x):
        dist = multivariate_normal(mean=self.mu, cov=self.S)
        return dist.logpdf(x)

    def predict(self, phi):
        if len(phi.shape) == 1:
            phi = phi.reshape(1, -1)
        pred = np.array([self.mu.T @ _phi for _phi in phi])
        S_pred = np.array([(1 / self.beta) + _phi.T @ self.S @ _phi for _phi in phi])

        # Above is a simple implementation.
        # This may be better if you want speed.
        # pred = self.mu @ phi.T
        # S_pred = (1 / self.beta) + np.diag(phi @ self.S @ phi.T)
        return pred, S_pred

Tout le code est également dans git. (Bien que ce soit environ 50 lignes)

GitHub

À propos de la régression linéaire bayésienne

Puisque ce qui suit est détaillé sur la dérivation de la formule, je n'écrirai pas les détails.

Calcul de la distribution postérieure

L'important est de mettre à jour la distribution comme suit. Pour le dire clairement, $ \ phi $ est la variable explicative et $ t $ est la réponse. Les matrices de moyenne et de covariance sont mises à jour en conséquence.

M_N=S_N(S_0^{-1}m_0+\beta\Phi^Tt)
S_N^{-1}=S_0^{-1}+\beta\Phi^T\Phi

Distribution prévue

La distribution prévue est indiquée ci-dessous. Je vais également omettre les détails ici, mais le fait est que la distribution est exprimée par la moyenne et la variance comme indiqué ci-dessous pour le nouveau point $ x $.

N(m_N^T\phi(x), 1/\beta+\phi(x)^TS_N\phi(x))

Utilisez la classe implémentée

À partir de là, essayons la régression linéaire bayésienne en utilisant la classe que nous avons réellement implémentée. La classe que j'ai créée doit recevoir $ \ phi $ en tant que fonctionnalité de $ x $. Dans une implémentation courante, la partie génération de $ \ phi $ (par exemple, un polynôme) est également incluse dans la classe, et il est difficile de dire s'il exécute une régression linéaire bayésienne ou s'il conçoit des entités à l'aide de polynômes. Mais ici, il est séparé.

Donc, si vous entrez les données originales $ x $, $ y $ puis implémentez la fonction pour créer $ \ phi $, c'est fondamentalement OK.

Régression avec données d'onde sinusoïdale

Essayons d'abord avec les données Toy.

Génération de données et conception de fonctions

Les données d'entrée sont les données d'observation en ajoutant du bruit à la distribution réelle de l'onde sinusoïdale. De plus, la fonction caractéristique est conçue comme une onde composite de fonctions triangulaires de plusieurs fréquences. La méthode x_to_phi vectorise 10 ondes et _phi représente une onde composite. L'amplitude est le paramètre obtenu par régression linéaire bayésienne. L'image ci-dessous est mathématique. (Si vous y réfléchissez, le premier élément est zéro ... je n'en ai pas besoin ...)

y=w_1sin(0)+w_2sin(2\pi x)+w_3sin(2\times2\pi x)+\cdots+w_9sin(9\times2\pi x)
def x_to_phi(x):
    if len(x.shape) == 1:
        x = x.reshape(-1, 1)
    return np.concatenate([np.sin(2 * np.pi * x * m) for m in range(0, 10)], axis=1)


def _phi(x, params):
    return np.array([p * np.sin(2 * np.pi * x * i) for i, p in enumerate(params)]).sum(axis=0)

Cliquez ici pour la partie réelle de la génération de données.

x = np.arange(0, 1, 0.01)
phi = x_to_phi(x)

e = np.random.randn(len(x)) / 10
y_true = np.sin(2 * np.pi * x)
y = y_true + e

Lorsqu'un seul point est observé

Tout d'abord, considérons le cas où un seul point des 50e données est observé.

train_idx = 50
x_train = x[train_idx]
phi_train = phi[train_idx]
y_train = y[train_idx]
plt.scatter(x_train, y_train, c='crimson', marker='o', label='observation')
plt.plot(x, y_true, label='true')

toy_input.png

Calculons immédiatement la distribution a posteriori de ces données. Si vous voulez juste apprendre, c'est une ligne comme celle-ci:

#Valeur initiale de la régression linéaire bayésienne
input_dim = phi.shape[1]
mu = np.zeros(input_dim)
S = np.identity(input_dim)
sigma = 0.1
beta = 1.0 / (sigma ** 2)

#Définition du modèle et formation
beyes_linear_model = BeyesLR.BeyesLinearRegression(mu, S, beta)
beyes_linear_model.calc_posterior(phi_train, y_train)

Certaines formes d'ondes échantillonnées au hasard de la distribution postérieure post-entraînement sont affichées avec des lignes pointillées vertes et la distribution prédite est affichée en bleu clair. La plupart d'entre eux sont bleus car je n'ai appris qu'un seul point.

toy_sin_predict.png

Lors de l'observation de 50 points

Faisons exactement la même chose à partir de 50 données d'observation. La seule différence dans le code est de sélectionner au hasard 50 train_idx. La distribution prévue des résultats est indiquée dans la figure ci-dessous.

toy_sin_predict_50.png

Retour dans l'ensemble de données publicitaire

Vient ensuite un vrai problème, qui résout également une régression linéaire multidimensionnelle. Si vous extrayez des entités dans plusieurs dimensions, les dimensions augmenteront trop et cela sera difficile à comprendre, donc $ \ phi $ est une fonction de Linear.

Des données d'entrée

Il s'agit d'un ensemble de données publicitaires familier à ISLR. Cette fois, nous utiliserons les dépenses publicitaires TV et Radio comme intrants et les ventes comme réponse.

Cette fois, $ \ phi $ est linéaire, alors ajoutez simplement le terme de section. La formule de la régression est la suivante. $Sales = w_0+w_1TV+w_2Radio$

def x_to_phi(x, typ='linear', degree=3):
    if len(x.shape) == 1:
        x = x.reshape(-1, 1)
    return np.concatenate([np.ones(x.shape[0]).reshape(-1, 1), x], axis=1)


df = pd.read_csv(ADVERTISING_DATASET)
x = df[['TV', 'Radio']].values
y = df['Sales'].values

phi = x_to_phi(x)
x_train, x_test, phi_train, phi_test, y_train, y_test = \
    train_test_split(x, phi, y, train_size=0.05, random_state=0)

Tout ce que vous avez à faire est d'apprendre comme dans l'exemple précédent.

input_dim = phi.shape[1]
mu = np.zeros(input_dim)
S = np.identity(input_dim)
sigma = 10
beta = 1.0 / (sigma ** 2)

beyes_linear_model = BeyesLR.BeyesLinearRegression(mu, S, beta)
beyes_linear_model.calc_posterior(phi_train, y_train)

Dans le code, train_size est défini sur 0,05, mais le plan de régression dessiné lors de sa modification est le suivant. Il est appris par régression linéaire bayésienne, et 5 plans sont extraits et dessinés par échantillonnage aléatoire. Aléatoire lorsque le nombre d'échantillons d'apprentissage est petit Un plan est dessiné, mais il converge à mesure que le nombre de points de données augmente. beyes_linear.gif

en conclusion

Enfin, une petite promotion de la régression linéaire bayésienne. Bien que certaines parties ne soient toujours pas entièrement comprises, la conception de la fonction d'extraction de caractéristiques $ \ phi $ de la régression linéaire bayésienne devient importante. Je reconnais que la régression de processus gaussienne traite la matrice distribuée co-distribuée comme une matrice de planification utilisant des fonctions du noyau sans l'écrire explicitement. Cependant, l'expérience montre que la régression linéaire bayésienne est suffisante du point de vue de la descriptivité s'il existe des connaissances préalables capables d'extraire de bonnes caractéristiques. De plus, grâce à la méthode de calcul de la régression linéaire bayésienne, l'apprentissage séquentiel peut être effectué tel quel. Tout ce que vous avez à faire est d'apprendre la distribution postérieure calculée en tant que distribution antérieure. Il n'est pas nécessaire de recalculer la matrice de gramme comme la régression de processus gaussien. Il existe peut-être une version en ligne, mais ...

Au fait, ayez une vie de retour linéaire bayésienne confortable!

Recommended Posts

Implémentation python de la classe de régression linéaire bayésienne
"Régression linéaire" et "Version probabiliste de la régression linéaire" en Python "Régression linéaire de Bayes"
Un mémorandum sur la mise en œuvre des recommandations en Python
Une implémentation Python simple de la méthode k-voisinage (k-NN)
PRML Chapitre 4 Implémentation Python de la régression logistique bayésienne
[Python] J'ai expliqué en détail la théorie et la mise en œuvre de la régression logistique
Reproduction sur plaque de régression linéaire bayésienne (PRML §3.3)
[python] [meta] Le type de python est-il un type?
À propos de l'équation normale de la régression linéaire
L'histoire du traitement A du blackjack (python)
Hit une méthode d'une instance de classe avec l'API Web Python Bottle
PRML §3.3.1 Reproduire le diagramme de convergence de la distribution des paramètres par régression linéaire bayésienne
Implémenté en Python PRML Chapitre 3 Régression linéaire bayésienne
Récupérer l'appelant d'une fonction en Python
Pourquoi l'implémentation Python d'ISUCON 5 a utilisé Bottle
Copiez la liste en Python
Python: préparez un sérialiseur pour l'instance de classe:
Écrire une note sur la version python de python virtualenv
[Python] Une compréhension approximative du module de journalisation
Sortie sous la forme d'un tableau python
Prise en compte des forces et faiblesses de Python
le zen de Python
Créez un environnement python pour apprendre la théorie et la mise en œuvre de l'apprentissage profond
[Python] Implémentation du clustering à l'aide d'un modèle gaussien mixte
[Python] Un programme qui compte le nombre de vallées
Explication du concept d'analyse de régression à l'aide de python Partie 2
Connaissez l'emplacement du fichier de définition de classe Python.
Découpez une partie de la chaîne à l'aide d'une tranche Python
Points Python du point de vue d'un programmeur en langage C
Calculer le coefficient de régression d'une analyse de régression simple avec python
Explication du concept d'analyse de régression à l'aide de Python Partie 1
Tâches au démarrage d'un nouveau projet python
Explication du concept d'analyse de régression à l'aide de Python Extra 1
Implémentation d'estimation bayésienne de variante du modèle de sujet en python
Pourquoi le premier argument de la classe [Python] est-il self?
[Python] Un programme qui compare les positions des kangourous.
Note Python: Le mystère de l'attribution d'une variable à une variable
Une note sur l'implémentation de la bibliothèque qui explore les hyperparamètres à l'aide de l'optimisation bayésienne en Python
Ne prenez pas une instance d'une classe d'exception Python directement comme argument de la classe d'exception!
Implémentation Python du filtre à particules
[Python] Régression linéaire avec scicit-learn
Régression linéaire en ligne en Python
Implémentation du tri rapide en Python
À propos des fonctionnalités de Python
Le pouvoir des pandas: Python
Découvrez la largeur apparente d'une chaîne en python
Comment utiliser la méthode __call__ dans la classe Python
Différent du type d'importation de python. Signification de depuis A import B
Avoir le graphique d'équation de la fonction linéaire dessiné en Python
L'histoire du champ de modèle Django disparaissant de la classe
Obtenez le nombre d'éléments spécifiques dans la liste python
[Note] Importation de fichiers dans le répertoire parent en Python
Trouver les valeurs propres d'une vraie matrice symétrique en Python
Script Python qui compare le contenu de deux répertoires
__init__ appelé par wxPython ou Tkinter était un appel __init__ de la classe héritée en Python
Mémorandum de l'outil de gestion de paquets Python ez_setup
Un enregistrement de patcher un package python
Créer une instance d'une classe prédéfinie à partir d'une chaîne en Python