Beginnen Sie bei Null und schreiben Sie die lineare Regression freihändig in Python

Vorwort

Der Text und die Bilder in diesem Artikel stammen aus dem Internet und dienen nur zu Lern- und Kommunikationszwecken. Sie haben keine kommerzielle Nutzung. Wenn Sie Fragen haben, wenden Sie sich bitte zur Bearbeitung an uns.

PS: Wenn Sie Python-Lernmaterialien benötigen, können Sie auf den folgenden Link klicken, um sie selbst zu erhalten

Python-freie Lernmaterialien und Antworten zur Gruppenkommunikation Klicken Sie hier, um sich anzumelden


Lassen Sie uns zuerst Scikit-learn ablegen und einen Blick auf die reale Technologie werfen.

Für die meisten Datenwissenschaftler sind lineare Regressionsmethoden ihr Ausgangspunkt für statistische Modellierungs- und prädiktive Analyseaufgaben. Diese Methode existiert seit mehr als 200 Jahren und wurde ausgiebig untersucht, ist aber immer noch ein aktives Forschungsfeld. Aufgrund seiner guten Interpretierbarkeit wird die lineare Regression in kommerziellen Daten häufig verwendet. Natürlich mangelt es nicht an Anwendungen der Regressionsanalyse in biologischen Daten, Industriedaten und anderen Bereichen.

Andererseits ist Python zur bevorzugten Programmiersprache für Datenwissenschaftler geworden, und es ist besonders wichtig, eine Vielzahl von Methoden anwenden zu können, um große Datenmengen mit linearen Modellen anzupassen.

Wenn Sie gerade erst in die Tür des maschinellen Lernens eingetreten sind, ist es ein sinnvoller Versuch, mit Python den gesamten linearen Regressionsalgorithmus von Grund auf neu zu codieren. Lassen Sie uns sehen, wie es geht.

Daten

Der erste Schritt bei einem Problem des maschinellen Lernens besteht darin, Daten zu erhalten. Ohne Daten, die gelernt werden können, gibt es kein maschinelles Lernen. In diesem Artikel wird ein sehr herkömmlicher linearer Regressionsdatensatz verwendet.

Dies ist ein einfacher Datensatz mit Immobilienpreisen in Portland, Oregon. Die erste Spalte im Datensatz ist die Hausfläche (in Quadratfuß), die zweite Spalte ist die Anzahl der Schlafzimmer und die dritte Spalte ist der Hauspreis. Dieser Datensatz enthält mehrere Funktionen (z. B. house_size und Anzahl der Räume). Daher werden wir die multiple lineare Regression untersuchen und die Bezeichnung (y) ist der Hauspreis, den wir vorhersagen werden.

Definieren Sie zunächst die Funktion zum Laden des Datensatzes:


def load_data(filename):
    df = pd.read_csv(filename, sep=",", index_col=False)
    df.columns = ["housesize", "rooms", "price"]
    data = np.array(df, dtype=float)
    plot_data(data[:,:2], data[:, -1])
    normalize(data)
    return data[:,:2], data[:, -1]

Wir werden die obige Funktion später aufrufen, um den Datensatz zu laden. Diese Funktion gibt x und y zurück.

Normalisierte Daten

Der obige Code lädt nicht nur Daten, sondern führt auch eine Normalisierungsverarbeitung für die Daten durch und zeichnet Datenpunkte. Bevor wir uns das Datendiagramm ansehen, verstehen wir zunächst die Normalisierung (Daten) im obigen Code.

Nach dem Anzeigen des Originaldatensatzes werden Sie feststellen, dass der Wert der zweiten Datenspalte (die Anzahl der Räume) viel kleiner ist als die erste Spalte (dh die Fläche des Hauses). Das Modell wertet diese Daten nicht als Anzahl der Räume oder Grundfläche aus, für das Modell sind es nur Zahlen. Einige Spalten (oder Merkmale) im Modell des maschinellen Lernens haben höhere Werte als andere Spalten, was zu unerwünschten Verzerrungen führen und auch zu einem Ungleichgewicht in Varianz und mathematischem Mittelwert führen kann. Aus diesen Gründen und um die Arbeit zu vereinfachen, empfehlen wir, die Features so zu skalieren oder zu normalisieren, dass sie im gleichen Bereich liegen (z. B. [-1,1] oder [0,1]), was das Training erheblich erleichtert. Daher verwenden wir die Merkmalsnormalisierung, deren mathematischer Ausdruck wie folgt lautet:

  • Z = (x - μ) / σ
  • μ: Mittelwert
  • σ: Standardabweichung,
    wobei z ein normalisiertes Merkmal und x ein nicht normalisiertes Merkmal ist. Mit der Normalisierungsformel können wir eine Funktion zur Normalisierung erstellen:
def normalize(data):
    for i in range(0,data.shape[1]-1):
        data[:,i] = ((data[:,i] - np.mean(data[:,i]))/np.std(data[:, i]))

Der obige Code durchläuft jede Spalte und normalisiert sie unter Verwendung des Mittelwerts und der Standardabweichung aller Datenelemente in jeder Spalte.

Plotdaten

Bevor wir das lineare Regressionsmodell codieren, müssen wir zuerst nach dem "Warum" fragen.

Warum sollte dieses Problem mithilfe der linearen Regression gelöst werden? Dies ist eine sehr nützliche Frage. Bevor Sie einen bestimmten Code schreiben, sollten Sie sich darüber im Klaren sein, welcher Algorithmus verwendet werden soll und ob dies angesichts des Datensatzes und des zu lösenden Problems wirklich die beste Wahl ist.

Wir können Bilder zeichnen, um zu beweisen, warum die lineare Regression für den aktuellen Datensatz effektiv ist. Zu diesem Zweck rufen wir die Funktion plot_data in den obigen load_data auf. Definieren wir nun die Funktion plot_data:

def plot_data(x, y):
    plt.xlabel('house size')
    plt.ylabel('price')
    plt.plot(x[:,0], y, 'bo')
    plt.show()

Wenn Sie diese Funktion aufrufen, wird die folgende Abbildung generiert:

 

 

Wie in der obigen Abbildung gezeigt, können wir eine Linie grob anpassen. Dies bedeutet, dass die Verwendung der linearen Approximation genauere Vorhersagen treffen kann, sodass eine lineare Regression verwendet werden kann.

Nachdem die Daten vorbereitet wurden, besteht der nächste Schritt darin, Code für den Algorithmus zu schreiben.

Hypothese

Zuerst müssen wir die Hypothesenfunktion definieren, die wir später zur Berechnung der Kosten verwenden werden. Für die lineare Regression gelten folgende Annahmen:

 

 

Der Datensatz enthält jedoch nur zwei Funktionen. Für das aktuelle Problem lautet die Annahme also:

 


Wobei x1 und x2 zwei Merkmale sind (nämlich die Fläche des Hauses und die Anzahl der Räume). Schreiben Sie dann eine einfache Python-Funktion, die diese Hypothese zurückgibt:


def h(x,theta):
    return np.matmul(x, theta)

Als nächstes betrachten wir die Kostenfunktion.

Kostenfunktion

Der Zweck der Verwendung der Kostenfunktion besteht darin, die Qualität des Modells zu bewerten.

Die Gleichung der Kostenfunktion lautet:

 

 

Der Code der Kostenfunktion lautet wie folgt:

def cost_function(x, y, theta):
    return ((h(x, theta)-y).T@(h(x, theta)-y))/(2*y.shape[0])

Bisher haben alle von uns definierten Python-Funktionen genau die gleiche mathematische Bedeutung wie die obige lineare Regression. Als nächstes müssen wir die Kosten minimieren, was einen Gradientenabstieg erfordert.

Gradientenabstieg

Gradient Descent ist ein Optimierungsalgorithmus zum Anpassen von Parametern, um die Kostenfunktion zu minimieren.

Die Hauptaktualisierungsschritte des Gradientenabstiegs sind:

 

 

Daher multiplizieren wir die Ableitung der Kostenfunktion mit der Lernrate (α) und subtrahieren sie dann vom aktuellen Wert des Parameters (θ), um den neuen aktualisierten Parameter (θ) zu erhalten.


def gradient_descent(x, y, theta, learning_rate=0.1, num_epochs=10):
    m = x.shape[0]
    J_all = []

    for _ in range(num_epochs):
        h_x = h(x, theta)
        cost_ = (1/m)*(x.T@(h_x - y))
        theta = theta - (learning_rate)*cost_
        J_all.append(cost_function(x, y, theta))

    return theta, J_all

Die Funktion gradient_descent gibt Theta und J_all zurück. Theta ist offensichtlich ein Parametervektor, der den hypothetischen θs-Wert enthält, und J_all ist eine Liste, die die Kostenfunktion nach jeder Epoche enthält. Die Variable J_all ist nicht unbedingt erforderlich, hilft jedoch bei der besseren Analyse des Modells.

Zusammen integriert

Als nächstes müssen Sie die Funktionen in der richtigen Reihenfolge aufrufen:


x,y = load_data("house_price_data.txt")
y = np.reshape(y, (46,1))
x = np.hstack((np.ones((x.shape[0],1)), x))
theta = np.zeros((x.shape[1], 1))
learning_rate = 0.1
num_epochs = 50
theta, J_all = gradient_descent(x, y, theta, learning_rate, num_epochs)
J = cost_function(x, y, theta)
print("Cost:", J)
print("Parameters:", theta)

#for testing and plotting cost 
n_epochs = []
jplot = []
count = 0
for i in J_all:
    jplot.append(i[0][0])
    n_epochs.append(count)
    count += 1
jplot = np.array(jplot)
n_epochs = np.array(n_epochs)
plot_cost(jplot, n_epochs)

test(theta, [1600, 2])

Rufen Sie zuerst die Funktion load_data auf, um die x- und y-Werte zu laden. Der x-Wert enthält die Trainingsstichprobe und der y-Wert enthält das Etikett (in diesem Fall den Preis des Hauses).

Sie müssen bemerkt haben, dass wir im gesamten Code die Matrixmultiplikation verwendet haben, um auszudrücken, was wir brauchen. Um beispielsweise eine Hypothese zu erhalten, müssen wir jeden Parameter (θ) mit jedem Merkmalsvektor (x) multiplizieren. Wir können eine for-Schleife verwenden, um jede Probe zu durchlaufen und jedes Mal eine Multiplikation durchzuführen. Wenn jedoch zu viele Trainingsproben vorhanden sind, ist dies möglicherweise nicht die effizienteste Methode.

Ein effizienterer Weg ist hier die Verwendung der Matrixmultiplikation. Der in diesem Artikel verwendete Datensatz weist zwei Merkmale auf: Hausfläche und Anzahl der Räume, dh wir haben (2 + 1) drei Parameter. Stellen Sie sich die Hypothese als eine Linie im grafischen Sinne vor und denken Sie auf diese Weise über den zusätzlichen Parameter θ0 nach. Schließlich muss das zusätzliche θ0 dafür sorgen, dass diese Linie die Anforderungen erfüllt.

 

 

Jetzt haben wir drei Parameter und zwei Funktionen. Dies bedeutet, dass die Dimension des Theta oder Parametervektors (1-dimensionale Matrix) (3,1) beträgt, die Dimension des Merkmalsvektors jedoch (46,2). Sie werden sicherlich feststellen, dass es mathematisch unmöglich ist, solche zwei Matrizen miteinander zu multiplizieren. Schauen Sie sich noch einmal unsere Hypothese an:

 


Wenn Sie genau hinschauen, ist dies tatsächlich sehr intuitiv: Wenn Sie am Anfang des Eigenvektors (x) {Dimensionalität (46, 3)} eine zusätzliche Spalte hinzufügen und eine Matrixmultiplikation für x und Theta durchführen, erhalten Sie hθ (x ) Gleichung.

Denken Sie daran, dass beim Ausführen des Codes zur Implementierung dieser Funktion kein Ausdruck wie hθ (x) zurückgegeben wird, sondern der vom Ausdruck erhaltene mathematische Wert. Im obigen Code ist x = np.hstack ((np.ones ((x.shape [0], 1)), x)). Diese Zeile fügt am Anfang von x eine zusätzliche Spalte hinzu, um die Matrixmultiplikation vorzubereiten.

Danach initialisieren wir den Theta-Vektor mit Nullen. Natürlich können Sie auch mit einigen kleinen Zufallswerten initialisieren. Wir geben auch die Lernrate des Trainings und die Anzahl der Epochen an.

Nachdem wir alle Hyperparameter definiert haben, können wir die Gradientenabstiegsfunktion aufrufen, um den Verlauf aller Kostenfunktionen und den endgültigen Vektor des Parameters Theta zurückzugeben. Hier definiert der Theta-Vektor die endgültige Hypothese. Möglicherweise stellen Sie fest, dass die Dimension des Theta-Vektors, die von der Gradientenabstiegsfunktion zurückgegeben wird, (3,1) beträgt.

Erinnern Sie sich an die Hypothese der Funktion?

 

 

Wir brauchen also drei θ, die Dimension des Theta-Vektors ist (3,1), also sind Theta [0], Theta [1] und Theta [2] tatsächlich θ0, θ1 bzw. θ2. Die Variable J_all ist die historische Aufzeichnung aller Kostenfunktionen. Sie können das Array J_all ausdrucken, um zu sehen, wie die Kostenfunktion in jeder Epoche des Gradientenabfalls allmählich abnimmt.

 

Wir können dieses Diagramm zeichnen, indem wir die Funktion plot_cost definieren und aufrufen, wie unten gezeigt:


def plot_cost(J_all, num_epochs):
    plt.xlabel('Epochs')
    plt.ylabel('Cost')
    plt.plot(num_epochs, J_all, 'm', linewidth = "5")
    plt.show()

Jetzt können wir diese Parameter verwenden, um Beschriftungen zu finden, z. B. den Preis eines Hauses für eine bestimmte Hausgröße und die Anzahl der Zimmer.

Prüfung

Jetzt können Sie den Code testen, der die Testfunktion aufruft, die den Hausbereich, die Anzahl der Räume und den endgültigen Theta-Vektor, der vom logistischen Regressionsmodell zurückgegeben wird, als Eingabe verwendet und den Hauspreis ausgibt.


def test(theta, x):
    x[0] = (x[0] - mu[0])/std[0]
    x[1] = (x[1] - mu[1])/std[1]

    y = theta[0] + theta[1]*x[0] + theta[2]*x[1]
    print("Price of house:", y)

Vollständiger Code


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

#variables to store mean and standard deviation for each feature
mu = []
std = []

def load_data(filename):
    df = pd.read_csv(filename, sep=",", index_col=False)
    df.columns = ["housesize", "rooms", "price"]
    data = np.array(df, dtype=float)
    plot_data(data[:,:2], data[:, -1])
    normalize(data)
    return data[:,:2], data[:, -1]

def plot_data(x, y):
    plt.xlabel('house size')
    plt.ylabel('price')
    plt.plot(x[:,0], y, 'bo')
    plt.show()

def normalize(data):
    for i in range(0,data.shape[1]-1):
        data[:,i] = ((data[:,i] - np.mean(data[:,i]))/np.std(data[:, i]))
        mu.append(np.mean(data[:,i]))
        std.append(np.std(data[:, i]))


def h(x,theta):
    return np.matmul(x, theta)

def cost_function(x, y, theta):
    return ((h(x, theta)-y).T@(h(x, theta)-y))/(2*y.shape[0])

def gradient_descent(x, y, theta, learning_rate=0.1, num_epochs=10):
    m = x.shape[0]
    J_all = []

    for _ in range(num_epochs):
        h_x = h(x, theta)
        cost_ = (1/m)*(x.T@(h_x - y))
        theta = theta - (learning_rate)*cost_
        J_all.append(cost_function(x, y, theta))

    return theta, J_all 

def plot_cost(J_all, num_epochs):
    plt.xlabel('Epochs')
    plt.ylabel('Cost')
    plt.plot(num_epochs, J_all, 'm', linewidth = "5")
    plt.show()

def test(theta, x):
    x[0] = (x[0] - mu[0])/std[0]
    x[1] = (x[1] - mu[1])/std[1]

    y = theta[0] + theta[1]*x[0] + theta[2]*x[1]
    print("Price of house:", y)

x,y = load_data("house_price_data.txt")
y = np.reshape(y, (46,1))
x = np.hstack((np.ones((x.shape[0],1)), x))
theta = np.zeros((x.shape[1], 1))
learning_rate = 0.1
num_epochs = 50
theta, J_all = gradient_descent(x, y, theta, learning_rate, num_epochs)
J = cost_function(x, y, theta)
print("Cost:", J)
print("Parameters:", theta)

#for testing and plotting cost 
n_epochs = []
jplot = []
count = 0
for i in J_all:
    jplot.append(i[0][0])
    n_epochs.append(count)
    count += 1
jplot = np.array(jplot)
n_epochs = np.array(n_epochs)
plot_cost(jplot, n_epochs)

test(theta, [1600, 3])

um zusammenzufassen

Dies ist der gesamte Code für die lineare Regression.

Jetzt haben Sie gelernt, lineare Regressionsmodelle erfolgreich von Grund auf neu zu schreiben. Es ist nicht einfach, den gesamten Algorithmus zu verstehen und zu schreiben, und Sie müssen möglicherweise von Zeit zu Zeit zurückblicken, um ihn vollständig zu verstehen. Diese Bemühungen lohnen sich jedoch. Die lineare Regression ist normalerweise der erste Schritt, um Algorithmen für maschinelles Lernen zu erlernen. Danach können Sie einen anderen Datensatz auswählen, der für die lineare Regressionsverarbeitung geeignet ist, und den soeben geschriebenen Algorithmus ausprobieren.

Ich denke du magst

Origin blog.csdn.net/pythonxuexi123/article/details/113060621
Empfohlen
Rangfolge