Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Το άρθρο εξετάζει διάφορους τρόπους προσδιορισμού της μαθηματικής εξίσωσης μιας απλής (ζευγοποιημένης) γραμμής παλινδρόμησης.

Όλες οι μέθοδοι επίλυσης της εξίσωσης που συζητούνται εδώ βασίζονται στη μέθοδο των ελαχίστων τετραγώνων. Ας χαρακτηρίσουμε τις μεθόδους ως εξής:

  • Αναλυτική λύση
  • Gradient Descent
  • Στοχαστική κλίση κάθοδος

Για κάθε μέθοδο επίλυσης της εξίσωσης μιας ευθείας γραμμής, το άρθρο παρέχει διάφορες συναρτήσεις, οι οποίες χωρίζονται κυρίως σε αυτές που έχουν γραφτεί χωρίς τη χρήση της βιβλιοθήκης μουδιασμένος και αυτά που χρησιμοποιούν για υπολογισμούς μουδιασμένος. Πιστεύεται ότι επιδέξια χρήση μουδιασμένος θα μειώσει το υπολογιστικό κόστος.

Όλος ο κώδικας που δίνεται στο άρθρο είναι γραμμένος στη γλώσσα python 2.7 χρησιμοποιώντας Jupyter Notebook. Ο πηγαίος κώδικας και το αρχείο με δείγματα δεδομένων δημοσιεύονται στο Github

Το άρθρο απευθύνεται περισσότερο τόσο σε αρχάριους όσο και σε εκείνους που έχουν ήδη αρχίσει σταδιακά να κατακτούν τη μελέτη μιας πολύ ευρείας ενότητας στην τεχνητή νοημοσύνη - μηχανική μάθηση.

Για να επεξηγήσουμε το υλικό, χρησιμοποιούμε ένα πολύ απλό παράδειγμα.

Παραδείγματα συνθηκών

Έχουμε πέντε αξίες που χαρακτηρίζουν την εξάρτηση Y από X (Πίνακας Νο. 1):

Πίνακας Νο. 1 «Παράδειγμα συνθηκών»

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Θα υποθέσουμε ότι οι τιμές Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης είναι ο μήνας του έτους, και Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης — έσοδα αυτόν τον μήνα. Με άλλα λόγια, τα έσοδα εξαρτώνται από τον μήνα του έτους, και Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης - το μόνο σημάδι από το οποίο εξαρτώνται τα έσοδα.

Το παράδειγμα είναι έτσι, τόσο από την άποψη της υπό όρους εξάρτησης των εσόδων από τον μήνα του έτους, όσο και από την άποψη του αριθμού των τιμών - υπάρχουν πολύ λίγες από αυτές. Ωστόσο, μια τέτοια απλοποίηση θα επιτρέψει, όπως λένε, να εξηγήσουμε, όχι πάντα με ευκολία, το υλικό που αφομοιώνουν οι αρχάριοι. Και επίσης η απλότητα των αριθμών θα επιτρέψει σε όσους επιθυμούν να λύσουν το παράδειγμα σε χαρτί χωρίς σημαντικό κόστος εργασίας.

Ας υποθέσουμε ότι η εξάρτηση που δίνεται στο παράδειγμα μπορεί να προσεγγιστεί αρκετά καλά από τη μαθηματική εξίσωση μιας απλής (ζευγοποιημένης) γραμμής παλινδρόμησης της μορφής:

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

όπου Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης είναι ο μήνας κατά τον οποίο ελήφθησαν τα έσοδα, Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης — έσοδα που αντιστοιχούν στο μήνα, Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης είναι οι συντελεστές παλινδρόμησης της εκτιμώμενης γραμμής.

Σημειώστε ότι ο συντελεστής Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης συχνά ονομάζεται κλίση ή κλίση της εκτιμώμενης γραμμής. αντιπροσωπεύει το ποσό με το οποίο το Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης όταν αλλάζει Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης.

Προφανώς, το καθήκον μας στο παράδειγμα είναι να επιλέξουμε τέτοιους συντελεστές στην εξίσωση Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης, στις οποίες οι αποκλίσεις των υπολογισμένων τιμών εσόδων μας ανά μήνα από τις αληθινές απαντήσεις, π.χ. Οι τιμές που παρουσιάζονται στο δείγμα θα είναι ελάχιστες.

Μέθοδος ελάχιστου τετραγώνου

Σύμφωνα με τη μέθοδο των ελαχίστων τετραγώνων, η απόκλιση πρέπει να υπολογιστεί τετραγωνίζοντάς την. Αυτή η τεχνική σας επιτρέπει να αποφύγετε την αμοιβαία ακύρωση των αποκλίσεων εάν έχουν αντίθετα σημάδια. Για παράδειγμα, εάν σε μια περίπτωση, η απόκλιση είναι +5 (συν πέντε), και στο άλλο -5 (μείον πέντε), τότε το άθροισμα των αποκλίσεων θα ακυρωθεί το ένα το άλλο και θα ανέλθει στο 0 (μηδέν). Είναι δυνατόν να μην τετραγωνιστεί η απόκλιση, αλλά να χρησιμοποιηθεί η ιδιότητα του συντελεστή και τότε όλες οι αποκλίσεις θα είναι θετικές και θα συσσωρεύονται. Δεν θα σταθούμε λεπτομερώς σε αυτό το σημείο, αλλά απλώς θα υποδείξουμε ότι για λόγους ευκολίας των υπολογισμών, συνηθίζεται να τετραγωνίζεται η απόκλιση.

Έτσι μοιάζει ο τύπος με τον οποίο θα προσδιορίσουμε το ελάχιστο άθροισμα των τετραγωνικών αποκλίσεων (λάθη):

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

όπου Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης είναι συνάρτηση προσέγγισης των αληθών απαντήσεων (δηλαδή των εσόδων που υπολογίσαμε),

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης είναι οι αληθινές απαντήσεις (τα έσοδα παρέχονται στο δείγμα),

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης είναι ο δείκτης του δείγματος (αριθμός του μήνα στον οποίο προσδιορίζεται η απόκλιση)

Ας διαφοροποιήσουμε τη συνάρτηση, ας ορίσουμε τις μερικές διαφορικές εξισώσεις και ας είμαστε έτοιμοι να προχωρήσουμε στην αναλυτική λύση. Αλλά πρώτα, ας κάνουμε μια σύντομη εκδρομή για το τι είναι η διαφοροποίηση και ας θυμηθούμε τη γεωμετρική σημασία της παραγώγου.

ΔΙΑΦΟΡΕΤΙΚΟΤΗΤΑ-διάκριση

Η διαφοροποίηση είναι η λειτουργία εύρεσης της παραγώγου μιας συνάρτησης.

Σε τι χρησιμεύει το παράγωγο; Η παράγωγος μιας συνάρτησης χαρακτηρίζει το ρυθμό μεταβολής της συνάρτησης και μας λέει την κατεύθυνση της. Εάν η παράγωγος σε ένα δεδομένο σημείο είναι θετική, τότε η συνάρτηση αυξάνεται, διαφορετικά η συνάρτηση μειώνεται. Και όσο μεγαλύτερη είναι η τιμή της απόλυτης παραγώγου, τόσο μεγαλύτερος είναι ο ρυθμός μεταβολής των τιμών της συνάρτησης, καθώς και τόσο μεγαλύτερη είναι η κλίση του γραφήματος συνάρτησης.

Για παράδειγμα, υπό τις συνθήκες ενός καρτεσιανού συστήματος συντεταγμένων, η τιμή της παραγώγου στο σημείο M(0,0) είναι ίση με + 25 σημαίνει ότι σε ένα δεδομένο σημείο, όταν η τιμή μετατοπίζεται Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης προς τα δεξιά από μια συμβατική μονάδα, τιμή Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης αυξάνεται κατά 25 συμβατικές μονάδες. Στο γράφημα φαίνεται σαν μια αρκετά απότομη αύξηση των τιμών Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης από ένα δεδομένο σημείο.

Ενα άλλο παράδειγμα. Η τιμή της παραγώγου είναι ίση -0,1 σημαίνει ότι όταν μετατοπίζεται Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης ανά μία συμβατική μονάδα, αξία Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης μειώνεται μόνο κατά 0,1 συμβατική μονάδα. Ταυτόχρονα, στο γράφημα της συνάρτησης, μπορούμε να παρατηρήσουμε μια ελάχιστα αισθητή κλίση προς τα κάτω. Σχεδιάζοντας μια αναλογία με ένα βουνό, είναι σαν να κατεβαίνουμε πολύ αργά μια ήπια πλαγιά από ένα βουνό, σε αντίθεση με το προηγούμενο παράδειγμα, όπου έπρεπε να ανεβούμε σε πολύ απότομες κορυφές :)

Έτσι, αφού διαφοροποιηθεί η συνάρτηση Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης κατά πιθανότητες Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης, ορίζουμε μερικές διαφορικές εξισώσεις 1ης τάξης. Αφού προσδιορίσουμε τις εξισώσεις, θα λάβουμε ένα σύστημα δύο εξισώσεων, λύνοντας τις οποίες θα μπορούμε να επιλέξουμε τέτοιες τιμές των συντελεστών Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης, για τις οποίες οι τιμές των αντίστοιχων παραγώγων σε δεδομένα σημεία αλλάζουν κατά πολύ, πολύ μικρό ποσό, και στην περίπτωση μιας αναλυτικής λύσης δεν αλλάζουν καθόλου. Με άλλα λόγια, η συνάρτηση σφάλματος στους συντελεστές που βρέθηκαν θα φτάσει στο ελάχιστο, αφού οι τιμές των μερικών παραγώγων σε αυτά τα σημεία θα είναι ίσες με μηδέν.

Άρα, σύμφωνα με τους κανόνες διαφοροποίησης, η μερική εξίσωση παραγώγου 1ης τάξης ως προς τον συντελεστή Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης θα λάβει τη μορφή:

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Μερική παράγωγη εξίσωση 1ης τάξης ως προς Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης θα λάβει τη μορφή:

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Ως αποτέλεσμα, λάβαμε ένα σύστημα εξισώσεων που έχει μια αρκετά απλή αναλυτική λύση:

αρχή{εξίσωση*}
αρχή{περιπτώσεις}
na + bsumlimits_{i=1}^nx_i — sumlimits_{i=1}^ny_i = 0

sumlimits_{i=1}^nx_i(a +bsumlimits_{i=1}^nx_i — sumlimits_{i=1}^ny_i) = 0
τέλος{περιπτώσεις}
τέλος{εξίσωση*}

Πριν λύσουμε την εξίσωση, ας προφορτίσουμε, ας ελέγξουμε ότι η φόρτωση είναι σωστή και ας μορφοποιήσουμε τα δεδομένα.

Φόρτωση και μορφοποίηση δεδομένων

Θα πρέπει να σημειωθεί ότι λόγω του γεγονότος ότι για την αναλυτική λύση, και στη συνέχεια για ντεγκραντέ και στοχαστική κλίση, θα χρησιμοποιήσουμε τον κώδικα σε δύο παραλλαγές: χρησιμοποιώντας τη βιβλιοθήκη μουδιασμένος και χωρίς να το χρησιμοποιήσουμε, τότε θα χρειαστούμε κατάλληλη μορφοποίηση δεδομένων (βλ. κώδικα).

Κώδικας φόρτωσης και επεξεργασίας δεδομένων

# импортируем все нужные нам библиотеки
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import math
import pylab as pl
import random

# графики отобразим в Jupyter
%matplotlib inline

# укажем размер графиков
from pylab import rcParams
rcParams['figure.figsize'] = 12, 6

# отключим предупреждения Anaconda
import warnings
warnings.simplefilter('ignore')

# загрузим значения
table_zero = pd.read_csv('data_example.txt', header=0, sep='t')

# посмотрим информацию о таблице и на саму таблицу
print table_zero.info()
print '********************************************'
print table_zero
print '********************************************'

# подготовим данные без использования NumPy

x_us = []
[x_us.append(float(i)) for i in table_zero['x']]
print x_us
print type(x_us)
print '********************************************'

y_us = []
[y_us.append(float(i)) for i in table_zero['y']]
print y_us
print type(y_us)
print '********************************************'

# подготовим данные с использованием NumPy

x_np = table_zero[['x']].values
print x_np
print type(x_np)
print x_np.shape
print '********************************************'

y_np = table_zero[['y']].values
print y_np
print type(y_np)
print y_np.shape
print '********************************************'

Οραματισμός

Τώρα, αφού πρώτα έχουμε φορτώσει τα δεδομένα, δεύτερον, ελέγξουμε την ορθότητα της φόρτωσης και τελικά μορφοποιήσουμε τα δεδομένα, θα πραγματοποιήσουμε την πρώτη οπτικοποίηση. Η μέθοδος που χρησιμοποιείται συχνά για αυτό είναι Pairplot βιβλιοθήκη Θαλασσοπόρος. Στο παράδειγμά μας, λόγω των περιορισμένων αριθμών, δεν έχει νόημα η χρήση της βιβλιοθήκης Θαλασσοπόρος. Θα χρησιμοποιήσουμε την κανονική βιβλιοθήκη matplotlib και απλά κοιτάξτε το scatterplot.

Κωδικός Scatterplot

print 'График №1 "Зависимость выручки от месяца года"'

plt.plot(x_us,y_us,'o',color='green',markersize=16)
plt.xlabel('$Months$', size=16)
plt.ylabel('$Sales$', size=16)
plt.show()

Διάγραμμα Νο. 1 «Εξάρτηση εσόδων από τον μήνα του έτους»

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Αναλυτική λύση

Ας χρησιμοποιήσουμε τα πιο κοινά εργαλεία Πύθων και να λύσουμε το σύστημα των εξισώσεων:

αρχή{εξίσωση*}
αρχή{περιπτώσεις}
na + bsumlimits_{i=1}^nx_i — sumlimits_{i=1}^ny_i = 0

sumlimits_{i=1}^nx_i(a +bsumlimits_{i=1}^nx_i — sumlimits_{i=1}^ny_i) = 0
τέλος{περιπτώσεις}
τέλος{εξίσωση*}

Σύμφωνα με τον κανόνα του Cramer θα βρούμε τη γενική ορίζουσα, καθώς και τις ορίζουσες κατά Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης και Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης, μετά την οποία, διαιρώντας την ορίζουσα με Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης στη γενική ορίζουσα - βρείτε τον συντελεστή Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης, ομοίως βρίσκουμε τον συντελεστή Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης.

Κωδικός αναλυτικής λύσης

# определим функцию для расчета коэффициентов a и b по правилу Крамера
def Kramer_method (x,y):
        # сумма значений (все месяца)
    sx = sum(x)
        # сумма истинных ответов (выручка за весь период)
    sy = sum(y)
        # сумма произведения значений на истинные ответы
    list_xy = []
    [list_xy.append(x[i]*y[i]) for i in range(len(x))]
    sxy = sum(list_xy)
        # сумма квадратов значений
    list_x_sq = []
    [list_x_sq.append(x[i]**2) for i in range(len(x))]
    sx_sq = sum(list_x_sq)
        # количество значений
    n = len(x)
        # общий определитель
    det = sx_sq*n - sx*sx
        # определитель по a
    det_a = sx_sq*sy - sx*sxy
        # искомый параметр a
    a = (det_a / det)
        # определитель по b
    det_b = sxy*n - sy*sx
        # искомый параметр b
    b = (det_b / det)
        # контрольные значения (прооверка)
    check1 = (n*b + a*sx - sy)
    check2 = (b*sx + a*sx_sq - sxy)
    return [round(a,4), round(b,4)]

# запустим функцию и запишем правильные ответы
ab_us = Kramer_method(x_us,y_us)
a_us = ab_us[0]
b_us = ab_us[1]
print ' 33[1m' + ' 33[4m' + "Оптимальные значения коэффициентов a и b:"  + ' 33[0m' 
print 'a =', a_us
print 'b =', b_us
print

# определим функцию для подсчета суммы квадратов ошибок
def errors_sq_Kramer_method(answers,x,y):
    list_errors_sq = []
    for i in range(len(x)):
        err = (answers[0] + answers[1]*x[i] - y[i])**2
        list_errors_sq.append(err)
    return sum(list_errors_sq)

# запустим функцию и запишем значение ошибки
error_sq = errors_sq_Kramer_method(ab_us,x_us,y_us)
print ' 33[1m' + ' 33[4m' + "Сумма квадратов отклонений" + ' 33[0m'
print error_sq
print

# замерим время расчета
# print ' 33[1m' + ' 33[4m' + "Время выполнения расчета суммы квадратов отклонений:" + ' 33[0m'
# % timeit error_sq = errors_sq_Kramer_method(ab,x_us,y_us)

Να τι πήραμε:

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Έτσι, οι τιμές των συντελεστών έχουν βρεθεί, το άθροισμα των τετραγωνικών αποκλίσεων έχει καθοριστεί. Ας σχεδιάσουμε μια ευθεία γραμμή στο ιστόγραμμα σκέδασης σύμφωνα με τους συντελεστές που βρέθηκαν.

Κωδικός γραμμής παλινδρόμησης

# определим функцию для формирования массива рассчетных значений выручки
def sales_count(ab,x,y):
    line_answers = []
    [line_answers.append(ab[0]+ab[1]*x[i]) for i in range(len(x))]
    return line_answers

# построим графики
print 'Грфик№2 "Правильные и расчетные ответы"'
plt.plot(x_us,y_us,'o',color='green',markersize=16, label = '$True$ $answers$')
plt.plot(x_us, sales_count(ab_us,x_us,y_us), color='red',lw=4,
         label='$Function: a + bx,$ $where$ $a='+str(round(ab_us[0],2))+',$ $b='+str(round(ab_us[1],2))+'$')
plt.xlabel('$Months$', size=16)
plt.ylabel('$Sales$', size=16)
plt.legend(loc=1, prop={'size': 16})
plt.show()

Διάγραμμα Νο. 2 «Σωστές και υπολογισμένες απαντήσεις»

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Μπορείτε να δείτε το γράφημα απόκλισης για κάθε μήνα. Στην περίπτωσή μας, δεν θα αντλήσουμε σημαντική πρακτική αξία από αυτό, αλλά θα ικανοποιήσουμε την περιέργειά μας για το πόσο καλά η απλή γραμμική εξίσωση παλινδρόμησης χαρακτηρίζει την εξάρτηση των εσόδων από τον μήνα του έτους.

Κωδικός γραφήματος απόκλισης

# определим функцию для формирования массива отклонений в процентах
def error_per_month(ab,x,y):
    sales_c = sales_count(ab,x,y)
    errors_percent = []
    for i in range(len(x)):
        errors_percent.append(100*(sales_c[i]-y[i])/y[i])
    return errors_percent

# построим график
print 'График№3 "Отклонения по-месячно, %"'
plt.gca().bar(x_us, error_per_month(ab_us,x_us,y_us), color='brown')
plt.xlabel('Months', size=16)
plt.ylabel('Calculation error, %', size=16)
plt.show()

Διάγραμμα Νο. 3 «Αποκλίσεις, %»

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Όχι τέλεια, αλλά ολοκληρώσαμε το έργο μας.

Ας γράψουμε μια συνάρτηση που, για να καθορίσουμε τους συντελεστές Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης χρησιμοποιεί τη βιβλιοθήκη μουδιασμένος, πιο συγκεκριμένα, θα γράψουμε δύο συναρτήσεις: τη μία χρησιμοποιώντας ψευδοαντίστροφο πίνακα (δεν συνιστάται στην πράξη, καθώς η διαδικασία είναι υπολογιστικά πολύπλοκη και ασταθής), η άλλη χρησιμοποιώντας μια εξίσωση πίνακα.

Κωδικός αναλυτικής λύσης (NumPy)

# для начала добавим столбец с не изменяющимся значением в 1. 
# Данный столбец нужен для того, чтобы не обрабатывать отдельно коэффицент a
vector_1 = np.ones((x_np.shape[0],1))
x_np = table_zero[['x']].values # на всякий случай приведем в первичный формат вектор x_np
x_np = np.hstack((vector_1,x_np))

# проверим то, что все сделали правильно
print vector_1[0:3]
print x_np[0:3]
print '***************************************'
print

# напишем функцию, которая определяет значения коэффициентов a и b с использованием псевдообратной матрицы
def pseudoinverse_matrix(X, y):
    # задаем явный формат матрицы признаков
    X = np.matrix(X)
    # определяем транспонированную матрицу
    XT = X.T
    # определяем квадратную матрицу
    XTX = XT*X
    # определяем псевдообратную матрицу
    inv = np.linalg.pinv(XTX)
    # задаем явный формат матрицы ответов
    y = np.matrix(y)
    # находим вектор весов
    return (inv*XT)*y

# запустим функцию
ab_np = pseudoinverse_matrix(x_np, y_np)
print ab_np
print '***************************************'
print

# напишем функцию, которая использует для решения матричное уравнение
def matrix_equation(X,y):
    a = np.dot(X.T, X)
    b = np.dot(X.T, y)
    return np.linalg.solve(a, b)

# запустим функцию
ab_np = matrix_equation(x_np,y_np)
print ab_np

Ας συγκρίνουμε τον χρόνο που δαπανάται για τον προσδιορισμό των συντελεστών Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης, σύμφωνα με τις 3 μεθόδους που παρουσιάζονται.

Κωδικός για τον υπολογισμό του χρόνου υπολογισμού

print ' 33[1m' + ' 33[4m' + "Время выполнения расчета коэффициентов без использования библиотеки NumPy:" + ' 33[0m'
% timeit ab_us = Kramer_method(x_us,y_us)
print '***************************************'
print
print ' 33[1m' + ' 33[4m' + "Время выполнения расчета коэффициентов с использованием псевдообратной матрицы:" + ' 33[0m'
%timeit ab_np = pseudoinverse_matrix(x_np, y_np)
print '***************************************'
print
print ' 33[1m' + ' 33[4m' + "Время выполнения расчета коэффициентов с использованием матричного уравнения:" + ' 33[0m'
%timeit ab_np = matrix_equation(x_np, y_np)

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Με έναν μικρό όγκο δεδομένων, εμφανίζεται μια συνάρτηση "αυτογραμμένη", η οποία βρίσκει τους συντελεστές χρησιμοποιώντας τη μέθοδο του Cramer.

Τώρα μπορείτε να προχωρήσετε σε άλλους τρόπους εύρεσης συντελεστών Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης.

Gradient Descent

Αρχικά, ας ορίσουμε τι είναι μια κλίση. Με απλά λόγια, η κλίση είναι ένα τμήμα που υποδεικνύει την κατεύθυνση της μέγιστης ανάπτυξης μιας συνάρτησης. Κατ' αναλογία με την αναρρίχηση σε ένα βουνό, όπου η κλίση βλέπει είναι εκεί που είναι η πιο απότομη ανάβαση στην κορυφή του βουνού. Αναπτύσσοντας το παράδειγμα με το βουνό, θυμόμαστε ότι στην πραγματικότητα χρειαζόμαστε την πιο απότομη κατάβαση για να φτάσουμε στην πεδιάδα όσο το δυνατόν γρηγορότερα, δηλαδή στο ελάχιστο - το μέρος όπου η συνάρτηση δεν αυξάνεται ή μειώνεται. Σε αυτό το σημείο η παράγωγος θα είναι ίση με μηδέν. Επομένως, δεν χρειαζόμαστε μια κλίση, αλλά μια αντιδιαβάθμιση. Για να βρείτε την κλίση χρειάζεται απλώς να πολλαπλασιάσετε την κλίση επί -1 (μείον ένα).

Ας δώσουμε προσοχή στο γεγονός ότι μια συνάρτηση μπορεί να έχει πολλά ελάχιστα, και αφού κατέβουμε σε ένα από αυτά χρησιμοποιώντας τον αλγόριθμο που προτείνουμε παρακάτω, δεν θα μπορέσουμε να βρούμε άλλο ελάχιστο, το οποίο μπορεί να είναι χαμηλότερο από αυτό που βρέθηκε. Ας χαλαρώσουμε, αυτό δεν αποτελεί απειλή για εμάς! Στην περίπτωσή μας έχουμε να κάνουμε με ένα ενιαίο ελάχιστο, αφού η λειτουργία μας Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης στο γράφημα είναι μια κανονική παραβολή. Και όπως όλοι θα έπρεπε να γνωρίζουμε πολύ καλά από το μάθημα των μαθηματικών του σχολείου μας, μια παραβολή έχει μόνο ένα ελάχιστο.

Αφού μάθαμε γιατί χρειαζόμασταν μια κλίση και επίσης ότι η κλίση είναι ένα τμήμα, δηλαδή ένα διάνυσμα με δεδομένες συντεταγμένες, οι οποίες είναι ακριβώς οι ίδιοι συντελεστές Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης μπορούμε να εφαρμόσουμε gradient descent.

Πριν ξεκινήσετε, προτείνω να διαβάσετε μερικές μόνο προτάσεις σχετικά με τον αλγόριθμο καθόδου:

  • Καθορίζουμε με ψευδοτυχαίο τρόπο τις συντεταγμένες των συντελεστών Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης. Στο παράδειγμά μας, θα ορίσουμε συντελεστές κοντά στο μηδέν. Αυτή είναι μια κοινή πρακτική, αλλά κάθε περίπτωση μπορεί να έχει τη δική της πρακτική.
  • Από συντεταγμένη Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης αφαιρέστε την τιμή της μερικής παραγώγου 1ης τάξης στο σημείο Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης. Έτσι, εάν η παράγωγος είναι θετική, τότε η συνάρτηση αυξάνεται. Επομένως, αφαιρώντας την τιμή της παραγώγου, θα κινηθούμε προς την αντίθετη κατεύθυνση της ανάπτυξης, δηλαδή προς την κατεύθυνση της κάθοδος. Αν η παράγωγος είναι αρνητική, τότε η συνάρτηση σε αυτό το σημείο μειώνεται και αφαιρώντας την τιμή της παραγώγου κινούμαστε προς την κατεύθυνση της καθόδου.
  • Κάνουμε παρόμοια επιχείρηση με τη συντεταγμένη Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης: αφαιρέστε την τιμή της μερικής παραγώγου στο σημείο Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης.
  • Για να μην πηδήξετε πάνω από το ελάχιστο και να πετάξετε στο βαθύ διάστημα, είναι απαραίτητο να ρυθμίσετε το μέγεθος του βήματος προς την κατεύθυνση της καθόδου. Γενικά, θα μπορούσατε να γράψετε ένα ολόκληρο άρθρο σχετικά με το πώς να ορίσετε σωστά το βήμα και πώς να το αλλάξετε κατά τη διαδικασία καθόδου, προκειμένου να μειωθεί το υπολογιστικό κόστος. Αλλά τώρα έχουμε ένα ελαφρώς διαφορετικό έργο μπροστά μας και θα καθορίσουμε το μέγεθος του βήματος χρησιμοποιώντας την επιστημονική μέθοδο του «poke» ή, όπως λένε στην κοινή γλώσσα, εμπειρικά.
  • Μόλις είμαστε από τις δεδομένες συντεταγμένες Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης αφαιρούμε τις τιμές των παραγώγων, παίρνουμε νέες συντεταγμένες Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης. Κάνουμε το επόμενο βήμα (αφαίρεση), ήδη από τις υπολογισμένες συντεταγμένες. Και έτσι ο κύκλος ξεκινάει ξανά και ξανά, μέχρι να επιτευχθεί η απαιτούμενη σύγκλιση.

Ολα! Τώρα είμαστε έτοιμοι να αναζητήσουμε το βαθύτερο φαράγγι της τάφρου των Μαριανών. Ας αρχίσουμε.

Κωδικός για κλίση κατάβασης

# напишем функцию градиентного спуска без использования библиотеки NumPy. 
# Функция на вход принимает диапазоны значений x,y, длину шага (по умолчанию=0,1), допустимую погрешность(tolerance)
def gradient_descent_usual(x_us,y_us,l=0.1,tolerance=0.000000000001):
    # сумма значений (все месяца)
    sx = sum(x_us)
    # сумма истинных ответов (выручка за весь период)
    sy = sum(y_us)
    # сумма произведения значений на истинные ответы
    list_xy = []
    [list_xy.append(x_us[i]*y_us[i]) for i in range(len(x_us))]
    sxy = sum(list_xy)
    # сумма квадратов значений
    list_x_sq = []
    [list_x_sq.append(x_us[i]**2) for i in range(len(x_us))]
    sx_sq = sum(list_x_sq)
    # количество значений
    num = len(x_us)
    # начальные значения коэффициентов, определенные псевдослучайным образом
    a = float(random.uniform(-0.5, 0.5))
    b = float(random.uniform(-0.5, 0.5))
    # создаем массив с ошибками, для старта используем значения 1 и 0
    # после завершения спуска стартовые значения удалим
    errors = [1,0]
    # запускаем цикл спуска
    # цикл работает до тех пор, пока отклонение последней ошибки суммы квадратов от предыдущей, не будет меньше tolerance
    while abs(errors[-1]-errors[-2]) > tolerance:
        a_step = a - l*(num*a + b*sx - sy)/num
        b_step = b - l*(a*sx + b*sx_sq - sxy)/num
        a = a_step
        b = b_step
        ab = [a,b]
        errors.append(errors_sq_Kramer_method(ab,x_us,y_us))
    return (ab),(errors[2:])

# запишем массив значений 
list_parametres_gradient_descence = gradient_descent_usual(x_us,y_us,l=0.1,tolerance=0.000000000001)


print ' 33[1m' + ' 33[4m' + "Значения коэффициентов a и b:" + ' 33[0m'
print 'a =', round(list_parametres_gradient_descence[0][0],3)
print 'b =', round(list_parametres_gradient_descence[0][1],3)
print


print ' 33[1m' + ' 33[4m' + "Сумма квадратов отклонений:" + ' 33[0m'
print round(list_parametres_gradient_descence[1][-1],3)
print



print ' 33[1m' + ' 33[4m' + "Количество итераций в градиентном спуске:" + ' 33[0m'
print len(list_parametres_gradient_descence[1])
print

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Βουτήξαμε στον πάτο της τάφρου των Μαριανών και εκεί βρήκαμε όλες τις ίδιες τιμές συντελεστών Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης, το οποίο ακριβώς ήταν αναμενόμενο.

Ας κάνουμε άλλη μια βουτιά, μόνο που αυτή τη φορά, το όχημά μας βαθέων υδάτων θα γεμίσει με άλλες τεχνολογίες, δηλαδή μια βιβλιοθήκη μουδιασμένος.

Κωδικός για gradient descent (NumPy)

# перед тем определить функцию для градиентного спуска с использованием библиотеки NumPy, 
# напишем функцию определения суммы квадратов отклонений также с использованием NumPy
def error_square_numpy(ab,x_np,y_np):
    y_pred = np.dot(x_np,ab)
    error = y_pred - y_np
    return sum((error)**2)

# напишем функцию градиентного спуска с использованием библиотеки NumPy. 
# Функция на вход принимает диапазоны значений x,y, длину шага (по умолчанию=0,1), допустимую погрешность(tolerance)
def gradient_descent_numpy(x_np,y_np,l=0.1,tolerance=0.000000000001):
    # сумма значений (все месяца)
    sx = float(sum(x_np[:,1]))
    # сумма истинных ответов (выручка за весь период)
    sy = float(sum(y_np))
    # сумма произведения значений на истинные ответы
    sxy = x_np*y_np
    sxy = float(sum(sxy[:,1]))
    # сумма квадратов значений
    sx_sq = float(sum(x_np[:,1]**2))
    # количество значений
    num = float(x_np.shape[0])
    # начальные значения коэффициентов, определенные псевдослучайным образом
    a = float(random.uniform(-0.5, 0.5))
    b = float(random.uniform(-0.5, 0.5))
    # создаем массив с ошибками, для старта используем значения 1 и 0
    # после завершения спуска стартовые значения удалим
    errors = [1,0]
    # запускаем цикл спуска
    # цикл работает до тех пор, пока отклонение последней ошибки суммы квадратов от предыдущей, не будет меньше tolerance
    while abs(errors[-1]-errors[-2]) > tolerance:
        a_step = a - l*(num*a + b*sx - sy)/num
        b_step = b - l*(a*sx + b*sx_sq - sxy)/num
        a = a_step
        b = b_step
        ab = np.array([[a],[b]])
        errors.append(error_square_numpy(ab,x_np,y_np))
    return (ab),(errors[2:])

# запишем массив значений 
list_parametres_gradient_descence = gradient_descent_numpy(x_np,y_np,l=0.1,tolerance=0.000000000001)

print ' 33[1m' + ' 33[4m' + "Значения коэффициентов a и b:" + ' 33[0m'
print 'a =', round(list_parametres_gradient_descence[0][0],3)
print 'b =', round(list_parametres_gradient_descence[0][1],3)
print


print ' 33[1m' + ' 33[4m' + "Сумма квадратов отклонений:" + ' 33[0m'
print round(list_parametres_gradient_descence[1][-1],3)
print

print ' 33[1m' + ' 33[4m' + "Количество итераций в градиентном спуске:" + ' 33[0m'
print len(list_parametres_gradient_descence[1])
print

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης
Τιμές συντελεστών Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης αμετάβλητος.

Ας δούμε πώς άλλαξε το σφάλμα κατά την κατάβαση κλίσης, δηλαδή πώς άλλαζε το άθροισμα των τετραγωνικών αποκλίσεων σε κάθε βήμα.

Κωδικός για την απεικόνιση αθροισμάτων τετραγωνικών αποκλίσεων

print 'График№4 "Сумма квадратов отклонений по-шагово"'
plt.plot(range(len(list_parametres_gradient_descence[1])), list_parametres_gradient_descence[1], color='red', lw=3)
plt.xlabel('Steps (Iteration)', size=16)
plt.ylabel('Sum of squared deviations', size=16)
plt.show()

Γράφημα Νο. 4 «Άθροισμα τετραγωνικών αποκλίσεων κατά την κλίση κατάβασης»

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Στο γράφημα βλέπουμε ότι με κάθε βήμα το σφάλμα μειώνεται και μετά από ορισμένο αριθμό επαναλήψεων παρατηρούμε μια σχεδόν οριζόντια γραμμή.

Τέλος, ας υπολογίσουμε τη διαφορά στο χρόνο εκτέλεσης του κώδικα:

Κωδικός για τον προσδιορισμό του χρόνου υπολογισμού της κατάβασης κλίσης

print ' 33[1m' + ' 33[4m' + "Время выполнения градиентного спуска без использования библиотеки NumPy:" + ' 33[0m'
%timeit list_parametres_gradient_descence = gradient_descent_usual(x_us,y_us,l=0.1,tolerance=0.000000000001)
print '***************************************'
print

print ' 33[1m' + ' 33[4m' + "Время выполнения градиентного спуска с использованием библиотеки NumPy:" + ' 33[0m'
%timeit list_parametres_gradient_descence = gradient_descent_numpy(x_np,y_np,l=0.1,tolerance=0.000000000001)

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Ίσως κάνουμε κάτι λάθος, αλλά και πάλι είναι μια απλή "εγγραφή στο σπίτι" συνάρτηση που δεν χρησιμοποιεί τη βιβλιοθήκη μουδιασμένος υπερέχει του χρόνου υπολογισμού μιας συνάρτησης που χρησιμοποιεί τη βιβλιοθήκη μουδιασμένος.

Αλλά δεν μένουμε στάσιμοι, αλλά προχωράμε προς τη μελέτη ενός άλλου συναρπαστικού τρόπου επίλυσης της απλής γραμμικής εξίσωσης παλινδρόμησης. Συναντώ!

Στοχαστική κλίση κάθοδος

Για να κατανοήσουμε γρήγορα την αρχή της λειτουργίας της στοχαστικής κλίσης κάθοδος, είναι καλύτερο να προσδιορίσουμε τις διαφορές της από τη συνηθισμένη κλίση. Εμείς, στην περίπτωση της κλίσης κάθοδος, στις εξισώσεις των παραγώγων του Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης χρησιμοποίησε τα αθροίσματα των τιμών όλων των χαρακτηριστικών και τις αληθινές απαντήσεις που ήταν διαθέσιμες στο δείγμα (δηλαδή τα αθροίσματα όλων Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης). Στην στοχαστική κλίση κάθοδος, δεν θα χρησιμοποιήσουμε όλες τις τιμές που υπάρχουν στο δείγμα, αλλά αντίθετα, θα επιλέξουμε ψευδοτυχαία το λεγόμενο δείκτη δείγματος και θα χρησιμοποιήσουμε τις τιμές του.

Για παράδειγμα, εάν ο δείκτης είναι ο αριθμός 3 (τρία), τότε παίρνουμε τις τιμές Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης, στη συνέχεια αντικαθιστούμε τις τιμές στις εξισώσεις παραγώγων και καθορίζουμε νέες συντεταγμένες. Στη συνέχεια, έχοντας καθορίσει τις συντεταγμένες, προσδιορίζουμε πάλι ψευδοτυχαία τον δείκτη δείγματος, αντικαθιστούμε τις τιμές που αντιστοιχούν στον δείκτη στις μερικές διαφορικές εξισώσεις και προσδιορίζουμε τις συντεταγμένες με νέο τρόπο Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης και τα λοιπά. μέχρι να γίνει πράσινη η σύγκλιση. Με την πρώτη ματιά, μπορεί να μην φαίνεται ότι αυτό θα μπορούσε να λειτουργήσει καθόλου, αλλά λειτουργεί. Είναι αλήθεια ότι αξίζει να σημειωθεί ότι το σφάλμα δεν μειώνεται με κάθε βήμα, αλλά σίγουρα υπάρχει μια τάση.

Ποια είναι τα πλεονεκτήματα της στοχαστικής κλίσης κατάβασης έναντι της συμβατικής; Εάν το μέγεθος του δείγματός μας είναι πολύ μεγάλο και μετριέται σε δεκάδες χιλιάδες τιμές, τότε είναι πολύ πιο εύκολο να επεξεργαστούμε, ας πούμε, μια τυχαία χιλιάδα από αυτές, παρά ολόκληρο το δείγμα. Εδώ μπαίνει στο παιχνίδι η στοχαστική κλίση κάθοδος. Στην περίπτωσή μας, φυσικά, δεν θα παρατηρήσουμε μεγάλη διαφορά.

Ας δούμε τον κώδικα.

Κωδικός για στοχαστική κλίση κάθοδος

# определим функцию стох.град.шага
def stoch_grad_step_usual(vector_init, x_us, ind, y_us, l):
#     выбираем значение икс, которое соответствует случайному значению параметра ind 
# (см.ф-цию stoch_grad_descent_usual)
    x = x_us[ind]
#     рассчитывыаем значение y (выручку), которая соответствует выбранному значению x
    y_pred = vector_init[0] + vector_init[1]*x_us[ind]
#     вычисляем ошибку расчетной выручки относительно представленной в выборке
    error = y_pred - y_us[ind]
#     определяем первую координату градиента ab
    grad_a = error
#     определяем вторую координату ab
    grad_b = x_us[ind]*error
#     вычисляем новый вектор коэффициентов
    vector_new = [vector_init[0]-l*grad_a, vector_init[1]-l*grad_b]
    return vector_new


# определим функцию стох.град.спуска
def stoch_grad_descent_usual(x_us, y_us, l=0.1, steps = 800):
#     для самого начала работы функции зададим начальные значения коэффициентов
    vector_init = [float(random.uniform(-0.5, 0.5)), float(random.uniform(-0.5, 0.5))]
    errors = []
#     запустим цикл спуска
# цикл расчитан на определенное количество шагов (steps)
    for i in range(steps):
        ind = random.choice(range(len(x_us)))
        new_vector = stoch_grad_step_usual(vector_init, x_us, ind, y_us, l)
        vector_init = new_vector
        errors.append(errors_sq_Kramer_method(vector_init,x_us,y_us))
    return (vector_init),(errors)


# запишем массив значений 
list_parametres_stoch_gradient_descence = stoch_grad_descent_usual(x_us, y_us, l=0.1, steps = 800)

print ' 33[1m' + ' 33[4m' + "Значения коэффициентов a и b:" + ' 33[0m'
print 'a =', round(list_parametres_stoch_gradient_descence[0][0],3)
print 'b =', round(list_parametres_stoch_gradient_descence[0][1],3)
print


print ' 33[1m' + ' 33[4m' + "Сумма квадратов отклонений:" + ' 33[0m'
print round(list_parametres_stoch_gradient_descence[1][-1],3)
print

print ' 33[1m' + ' 33[4m' + "Количество итераций в стохастическом градиентном спуске:" + ' 33[0m'
print len(list_parametres_stoch_gradient_descence[1])

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Εξετάζουμε προσεκτικά τους συντελεστές και πιάνουμε τον εαυτό μας να κάνει την ερώτηση "Πώς μπορεί να είναι αυτό;" Πήραμε άλλες τιμές συντελεστών Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης. Ίσως η στοχαστική κλίση να έχει βρει πιο βέλτιστες παραμέτρους για την εξίσωση; Δυστυχώς όχι. Αρκεί να δούμε το άθροισμα των τετραγωνικών αποκλίσεων και να δούμε ότι με νέες τιμές των συντελεστών, το σφάλμα είναι μεγαλύτερο. Δεν βιαζόμαστε να απελπιστούμε. Ας δημιουργήσουμε ένα γράφημα της αλλαγής του σφάλματος.

Κωδικός για την γραφική παράσταση του αθροίσματος των τετραγωνικών αποκλίσεων σε στοχαστική κλίση κάθοδος

print 'График №5 "Сумма квадратов отклонений по-шагово"'
plt.plot(range(len(list_parametres_stoch_gradient_descence[1])), list_parametres_stoch_gradient_descence[1], color='red', lw=2)
plt.xlabel('Steps (Iteration)', size=16)
plt.ylabel('Sum of squared deviations', size=16)
plt.show()

Γράφημα Νο. 5 «Άθροισμα τετραγωνικών αποκλίσεων κατά την κάθοδο στοχαστικής κλίσης»

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Βλέποντας το πρόγραμμα, όλα μπαίνουν στη θέση τους και τώρα θα τα φτιάξουμε όλα.

Λοιπόν τι έγινε? Συνέβη το εξής. Όταν επιλέγουμε τυχαία έναν μήνα, τότε είναι για τον επιλεγμένο μήνα που ο αλγόριθμός μας επιδιώκει να μειώσει το σφάλμα στον υπολογισμό των εσόδων. Στη συνέχεια επιλέγουμε έναν άλλο μήνα και επαναλαμβάνουμε τον υπολογισμό, αλλά μειώνουμε το σφάλμα για τον δεύτερο επιλεγμένο μήνα. Τώρα θυμηθείτε ότι οι δύο πρώτοι μήνες αποκλίνουν σημαντικά από τη γραμμή της απλής γραμμικής εξίσωσης παλινδρόμησης. Αυτό σημαίνει ότι όταν επιλέγεται οποιοσδήποτε από αυτούς τους δύο μήνες, μειώνοντας το σφάλμα καθενός από αυτούς, ο αλγόριθμός μας αυξάνει σοβαρά το σφάλμα για ολόκληρο το δείγμα. Τι να κάνουμε λοιπόν; Η απάντηση είναι απλή: πρέπει να μειώσετε το βήμα καθόδου. Εξάλλου, μειώνοντας το βήμα καθόδου, το σφάλμα θα σταματήσει επίσης να "πηδά" πάνω-κάτω. Ή μάλλον, το σφάλμα "άλμα" δεν θα σταματήσει, αλλά δεν θα το κάνει τόσο γρήγορα :) Ας ελέγξουμε.

Κωδικός για εκτέλεση SGD με μικρότερες προσαυξήσεις

# запустим функцию, уменьшив шаг в 100 раз и увеличив количество шагов соответсвующе 
list_parametres_stoch_gradient_descence = stoch_grad_descent_usual(x_us, y_us, l=0.001, steps = 80000)

print ' 33[1m' + ' 33[4m' + "Значения коэффициентов a и b:" + ' 33[0m'
print 'a =', round(list_parametres_stoch_gradient_descence[0][0],3)
print 'b =', round(list_parametres_stoch_gradient_descence[0][1],3)
print


print ' 33[1m' + ' 33[4m' + "Сумма квадратов отклонений:" + ' 33[0m'
print round(list_parametres_stoch_gradient_descence[1][-1],3)
print



print ' 33[1m' + ' 33[4m' + "Количество итераций в стохастическом градиентном спуске:" + ' 33[0m'
print len(list_parametres_stoch_gradient_descence[1])

print 'График №6 "Сумма квадратов отклонений по-шагово"'
plt.plot(range(len(list_parametres_stoch_gradient_descence[1])), list_parametres_stoch_gradient_descence[1], color='red', lw=2)
plt.xlabel('Steps (Iteration)', size=16)
plt.ylabel('Sum of squared deviations', size=16)
plt.show()

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Γράφημα Νο. 6 «Άθροισμα τετραγωνικών αποκλίσεων κατά την κάθοδο στοχαστικής κλίσης (80 χιλιάδες βήματα)»

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Οι συντελεστές έχουν βελτιωθεί, αλλά δεν είναι ακόμα ιδανικοί. Υποθετικά, αυτό μπορεί να διορθωθεί με αυτόν τον τρόπο. Επιλέγουμε, για παράδειγμα, στις τελευταίες 1000 επαναλήψεις τις τιμές των συντελεστών με τους οποίους έγινε το ελάχιστο σφάλμα. Είναι αλήθεια ότι για αυτό θα πρέπει επίσης να γράψουμε τις τιμές των ίδιων των συντελεστών. Δεν θα το κάνουμε αυτό, αλλά μάλλον θα προσέξουμε το χρονοδιάγραμμα. Φαίνεται ομαλό και το σφάλμα φαίνεται να μειώνεται ομοιόμορφα. Στην πραγματικότητα αυτό δεν είναι αλήθεια. Ας δούμε τις πρώτες 1000 επαναλήψεις και ας τις συγκρίνουμε με τις τελευταίες.

Κωδικός για γράφημα SGD (πρώτα 1000 βήματα)

print 'График №7 "Сумма квадратов отклонений по-шагово. Первые 1000 итераций"'
plt.plot(range(len(list_parametres_stoch_gradient_descence[1][:1000])), 
         list_parametres_stoch_gradient_descence[1][:1000], color='red', lw=2)
plt.xlabel('Steps (Iteration)', size=16)
plt.ylabel('Sum of squared deviations', size=16)
plt.show()

print 'График №7 "Сумма квадратов отклонений по-шагово. Последние 1000 итераций"'
plt.plot(range(len(list_parametres_stoch_gradient_descence[1][-1000:])), 
         list_parametres_stoch_gradient_descence[1][-1000:], color='red', lw=2)
plt.xlabel('Steps (Iteration)', size=16)
plt.ylabel('Sum of squared deviations', size=16)
plt.show()

Γράφημα Νο. 7 «Άθροισμα τετραγωνικών αποκλίσεων SGD (πρώτα 1000 βήματα)»

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Γράφημα Νο. 8 «Άθροισμα τετραγωνικών αποκλίσεων SGD (τελευταία 1000 βήματα)»

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Στην αρχή της κατάβασης παρατηρούμε μια αρκετά ομοιόμορφη και απότομη μείωση του σφάλματος. Στις τελευταίες επαναλήψεις, βλέπουμε ότι το σφάλμα περιστρέφεται γύρω από την τιμή του 1,475 και σε ορισμένες στιγμές ισούται ακόμη και με αυτήν τη βέλτιστη τιμή, αλλά μετά εξακολουθεί να ανεβαίνει... Επαναλαμβάνω, μπορείτε να γράψετε τις τιμές του συντελεστές Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης и Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησηςκαι, στη συνέχεια, επιλέξτε εκείνα για τα οποία το σφάλμα είναι ελάχιστο. Ωστόσο, είχαμε ένα πιο σοβαρό πρόβλημα: έπρεπε να κάνουμε 80 χιλιάδες βήματα (βλ. κώδικα) για να φτάσουν οι τιμές κοντά στο βέλτιστο. Και αυτό ήδη έρχεται σε αντίθεση με την ιδέα της εξοικονόμησης υπολογιστικού χρόνου με στοχαστική κάθοδο διαβάθμισης σε σχέση με την κάθοδο κλίσης. Τι μπορεί να διορθωθεί και να βελτιωθεί; Δεν είναι δύσκολο να παρατηρήσουμε ότι στις πρώτες επαναλήψεις κατεβαίνουμε με σιγουριά και, επομένως, θα πρέπει να αφήσουμε ένα μεγάλο βήμα στις πρώτες επαναλήψεις και να μειώσουμε το βήμα καθώς προχωράμε. Δεν θα το κάνουμε αυτό σε αυτό το άρθρο - είναι ήδη πάρα πολύ καιρό. Όσοι επιθυμούν μπορούν να σκεφτούν μόνοι τους πώς να το κάνουν αυτό, δεν είναι δύσκολο :)

Τώρα ας εκτελέσουμε στοχαστική ντεγκραντέ κάθοδο χρησιμοποιώντας τη βιβλιοθήκη μουδιασμένος (και ας μην σκοντάφτουμε στις πέτρες που εντοπίσαμε νωρίτερα)

Κωδικός για στοχαστική κλίση κάθοδος (NumPy)

# для начала напишем функцию градиентного шага
def stoch_grad_step_numpy(vector_init, X, ind, y, l):
    x = X[ind]
    y_pred = np.dot(x,vector_init)
    err = y_pred - y[ind]
    grad_a = err
    grad_b = x[1]*err
    return vector_init - l*np.array([grad_a, grad_b])

# определим функцию стохастического градиентного спуска
def stoch_grad_descent_numpy(X, y, l=0.1, steps = 800):
    vector_init = np.array([[np.random.randint(X.shape[0])], [np.random.randint(X.shape[0])]])
    errors = []
    for i in range(steps):
        ind = np.random.randint(X.shape[0])
        new_vector = stoch_grad_step_numpy(vector_init, X, ind, y, l)
        vector_init = new_vector
        errors.append(error_square_numpy(vector_init,X,y))
    return (vector_init), (errors)

# запишем массив значений 
list_parametres_stoch_gradient_descence = stoch_grad_descent_numpy(x_np, y_np, l=0.001, steps = 80000)

print ' 33[1m' + ' 33[4m' + "Значения коэффициентов a и b:" + ' 33[0m'
print 'a =', round(list_parametres_stoch_gradient_descence[0][0],3)
print 'b =', round(list_parametres_stoch_gradient_descence[0][1],3)
print


print ' 33[1m' + ' 33[4m' + "Сумма квадратов отклонений:" + ' 33[0m'
print round(list_parametres_stoch_gradient_descence[1][-1],3)
print



print ' 33[1m' + ' 33[4m' + "Количество итераций в стохастическом градиентном спуске:" + ' 33[0m'
print len(list_parametres_stoch_gradient_descence[1])
print

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Οι τιμές αποδείχθηκαν σχεδόν οι ίδιες με αυτές που κάνατε κατά την πτώση χωρίς χρήση μουδιασμένος. Ωστόσο, αυτό είναι λογικό.

Ας μάθουμε πόσο χρόνο μας πήρε οι στοχαστικές διαβαθμίσεις.

Κωδικός για τον προσδιορισμό του χρόνου υπολογισμού SGD (80 χιλιάδες βήματα)

print ' 33[1m' + ' 33[4m' +
"Время выполнения стохастического градиентного спуска без использования библиотеки NumPy:"
+ ' 33[0m'
%timeit list_parametres_stoch_gradient_descence = stoch_grad_descent_usual(x_us, y_us, l=0.001, steps = 80000)
print '***************************************'
print

print ' 33[1m' + ' 33[4m' +
"Время выполнения стохастического градиентного спуска с использованием библиотеки NumPy:"
+ ' 33[0m'
%timeit list_parametres_stoch_gradient_descence = stoch_grad_descent_numpy(x_np, y_np, l=0.001, steps = 80000)

Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης

Όσο πιο μέσα στο δάσος, τόσο πιο σκούρα είναι τα σύννεφα: και πάλι, η φόρμουλα «αυτογραμμένη» δείχνει το καλύτερο αποτέλεσμα. Όλα αυτά υποδηλώνουν ότι πρέπει να υπάρχουν ακόμη πιο λεπτοί τρόποι χρήσης της βιβλιοθήκης μουδιασμένος, που επιταχύνουν πραγματικά τις υπολογιστικές λειτουργίες. Σε αυτό το άρθρο δεν θα μάθουμε γι 'αυτούς. Θα έχετε κάτι να σκεφτείτε στον ελεύθερο χρόνο σας :)

Συνοψίζουμε

Πριν συνοψίσω, θα ήθελα να απαντήσω σε μια ερώτηση που πιθανότατα προέκυψε από τον αγαπητό μας αναγνώστη. Γιατί, στην πραγματικότητα, τέτοια «βασανιστήρια» με καταβάσεις, γιατί χρειάζεται να περπατάμε πάνω-κάτω στο βουνό (κυρίως κάτω) για να βρούμε την πολύτιμη πεδιάδα, αν έχουμε στα χέρια μας μια τόσο δυνατή και απλή συσκευή, στο μορφή αναλυτικής λύσης, που μας τηλεμεταφέρει αμέσως στο σωστό μέρος;

Η απάντηση σε αυτό το ερώτημα βρίσκεται στην επιφάνεια. Τώρα εξετάσαμε ένα πολύ απλό παράδειγμα, στο οποίο βρίσκεται η αληθινή απάντηση Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης εξαρτάται από ένα σημάδι Επίλυση της εξίσωσης της απλής γραμμικής παλινδρόμησης. Δεν το βλέπετε συχνά στη ζωή, οπότε ας φανταστούμε ότι έχουμε 2, 30, 50 ή περισσότερα ζώδια. Ας προσθέσουμε σε αυτό χιλιάδες, ή ακόμα και δεκάδες χιλιάδες τιμές για κάθε χαρακτηριστικό. Σε αυτή την περίπτωση, το αναλυτικό διάλυμα μπορεί να μην αντέξει τη δοκιμή και να αποτύχει. Με τη σειρά του, η ντεγκραντέ κάθοδος και οι παραλλαγές της θα μας φέρουν αργά αλλά σίγουρα πιο κοντά στον στόχο - το ελάχιστο της συνάρτησης. Και μην ανησυχείτε για την ταχύτητα - πιθανότατα θα εξετάσουμε τρόπους που θα μας επιτρέψουν να ορίσουμε και να ρυθμίσουμε το μήκος του βήματος (δηλαδή την ταχύτητα).

Και τώρα η πραγματική σύντομη περίληψη.

Πρώτον, ελπίζω ότι το υλικό που παρουσιάζεται στο άρθρο θα βοηθήσει τους αρχάριους «επιστήμονες δεδομένων» στην κατανόηση του τρόπου επίλυσης απλών (και όχι μόνο) εξισώσεων γραμμικής παλινδρόμησης.

Δεύτερον, εξετάσαμε διάφορους τρόπους επίλυσης της εξίσωσης. Τώρα, ανάλογα με την κατάσταση, μπορούμε να επιλέξουμε αυτό που είναι καταλληλότερο για την επίλυση του προβλήματος.

Τρίτον, είδαμε τη δύναμη των πρόσθετων ρυθμίσεων, δηλαδή το μήκος του βήματος κατάβασης με κλίση. Αυτή η παράμετρος δεν μπορεί να αγνοηθεί. Όπως σημειώθηκε παραπάνω, για να μειωθεί το κόστος των υπολογισμών, το μήκος του βήματος θα πρέπει να αλλάξει κατά την κάθοδο.

Τέταρτον, στην περίπτωσή μας, οι «εγγραφές στο σπίτι» συναρτήσεις έδειξαν τα καλύτερα αποτελέσματα χρόνου για τους υπολογισμούς. Αυτό οφείλεται πιθανώς στη μη πιο επαγγελματική χρήση των δυνατοτήτων της βιβλιοθήκης μουδιασμένος. Αλλά όπως και να έχει, το ακόλουθο συμπέρασμα φαίνεται από μόνο του. Από τη μια πλευρά, μερικές φορές αξίζει να αμφισβητήσετε τις καθιερωμένες απόψεις και από την άλλη, δεν αξίζει πάντα να περιπλέκετε τα πάντα - αντίθετα, μερικές φορές ένας απλούστερος τρόπος επίλυσης ενός προβλήματος είναι πιο αποτελεσματικός. Και δεδομένου ότι ο στόχος μας ήταν να αναλύσουμε τρεις προσεγγίσεις για την επίλυση μιας απλής γραμμικής εξίσωσης παλινδρόμησης, η χρήση των «αυτογραμμένων» συναρτήσεων ήταν αρκετά αρκετή για εμάς.

Λογοτεχνία (ή κάτι τέτοιο)

1. Γραμμική παλινδρόμηση

http://statistica.ru/theory/osnovy-lineynoy-regressii/

2. Μέθοδος ελαχίστων τετραγώνων

mathprofi.ru/metod_naimenshih_kvadratov.html

3. Παράγωγο

www.mathprofi.ru/chastnye_proizvodnye_primery.html

4. Διαβάθμιση

mathprofi.ru/proizvodnaja_po_napravleniju_i_gradient.html

5. Κλίση κατάβασης

habr.com/en/post/471458

habr.com/en/post/307312

artemarakcheev.com//2017-12-31/linear_regression

6. Βιβλιοθήκη NumPy

docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.linalg.solve.html

docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.linalg.pinv.html

pythonworld.ru/numpy/2.html

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο