Den Artikel diskutéiert verschidde Weeër fir d'mathematesch Equatioun vun enger einfacher (paarter) Regressiounslinn ze bestëmmen.
All Methode fir d'Léisung vun der Equatioun hei diskutéiert baséieren op d'mannst Quadratmethod. Loosst eis d'Methoden wéi follegt bezeechnen:
- Analytesch Léisung
- Gradient Ofstamung
- Stochastic Gradient Ofstamung
Fir all Method fir d'Gleichung vun enger riichter Linn ze léisen, gëtt den Artikel verschidde Funktiounen, déi haaptsächlech opgedeelt sinn an déi, déi geschriwwe sinn ouni d'Bibliothéik ze benotzen NummPy an déi, déi fir Berechnungen benotzen NummPy. Et gëtt ugeholl datt e kompetente Gebrauch NummPy wäert Rechenzäit Käschten reduzéieren.
All Code deen am Artikel gëtt ass an der Sprooch geschriwwen Python 2.7 benotzen Jupyter Notizbuch. De Quellcode an de Fichier mat Proufdaten ginn op gepost
Den Artikel riicht sech méi un Ufänger an déi, déi scho lues a lues ugefaang hunn d'Studie vun enger ganz breet Sektioun an der kënschtlecher Intelligenz ze beherrschen - Maschinnléieren.
Fir d'Material ze illustréieren, benotze mir e ganz einfacht Beispill.
Beispill Konditiounen
Mir hu fënnef Wäerter déi d'Ofhängegkeet charakteriséieren Y от X (Tabell Nummer 1):
Tabell Nummer 1 "Beispill Konditiounen"
Mir wäerten dovun ausgoen, datt d'Wäerter ass de Mount vum Joer, an - Akommes dëse Mount. An anere Wierder, Recetten hänkt op de Mount vum Joer, an - dat eenzegt Zeechen op deem Recetten hänkt.
D'Beispill ass sou-sou, souwuel aus der Siicht vun der bedingter Ofhängegkeet vun de Recetten op de Mount vum Joer, an aus der Siicht vun der Unzuel vun de Wäerter - et gi ganz wéineg vun hinnen. Wéi och ëmmer, sou eng Vereinfachung wäert et méiglech maachen, wéi se soen, d'Material ze erklären, net ëmmer mat Liichtegkeet, déi Ufänger assimiléieren. An och d'Einfachheet vun den Zuelen erlaabt déi, déi d'Beispill op Pabeier ouni bedeitend Aarbechtskäschte léisen wëllen.
Loosst eis unhuelen datt d'Ofhängegkeet, déi am Beispill uginn ass, ganz gutt duerch d'mathematesch Equatioun vun enger einfacher (paarter) Regressiounslinn vun der Form ugesi ka ginn:
wou ass de Mount an deem d'Recetten kritt goufen, - Recetten entspriechend dem Mount, и sinn d'Regressiounskoeffizienten vun der geschätzter Linn.
Bedenkt datt de Koeffizient dacks den Hang oder Gradient vun der geschätzter Linn genannt; stellt de Betrag duer mat deem de wann et Ännerungen .
Natierlech ass eis Aufgab am Beispill esou Koeffizienten an der Equatioun ze wielen и , bei deenen d'Ofwäichunge vun eise berechente Recettenwäerter pro Mount vun de richtegen Äntwerten, d.h. Wäerter presentéiert an der Probe wäert minimal sinn.
Mannste Quadrat Method
No der Methode vun de Klengste Quadrat soll d'Ofwäichung berechent ginn andeems se se quadratéiert. Dës Technik erlaabt Iech géigesäitege Kënnegung vun deviations ze vermeiden wann se Géigendeel Schëlder hunn. Zum Beispill, wann an engem Fall d'Deviatioun ass +5 (plus fënnef), an déi aner -5 (Minus fënnef), da wäert d'Zomm vun den Ofwäichunge sech géigesäiteg annuléieren an op 0 (null) belafen. Et ass méiglech net d'Ofwäichung ze quadratéieren, awer d'Eegeschafte vum Modulus ze benotzen an dann all d'Ofwäichunge positiv sinn a accumuléieren. Mir wäerten net op dësem Punkt am Detail wunnen, awer einfach uginn datt et fir d'Bequemlechkeet vun de Berechnungen üblech ass d'Ofwäichung ze quadrateschen.
Dëst ass wéi d'Formel ausgesäit, mat där mir déi mannst Zomm vu quadrateschen Ofwäichungen (Feeler) bestëmmen:
wou ass eng Funktioun vun der Approximatioun vu richtegen Äntwerten (dat ass d'Recetten déi mir berechent hunn),
sinn déi richteg Äntwerten (Recetten an der Probe geliwwert),
ass de Probeindex (Nummer vum Mount an deem d'Ofwäichung bestëmmt gëtt)
Loosst eis d'Funktioun differenzéieren, déi partiell Differentialgleichungen definéieren, a si prett fir op d'analytesch Léisung weiderzekommen. Awer als éischt, loosst eis e kuerzen Ausfluch iwwer wat Differenzéierung ass an erënneren un déi geometresch Bedeitung vun der Derivat.
Differenzéierung
Differenzéierung ass d'Operatioun fir d'Derivat vun enger Funktioun ze fannen.
Fir wat gëtt d'Derivat benotzt? D'Derivat vun enger Funktioun charakteriséiert den Taux vun der Ännerung vun der Funktioun a seet eis seng Richtung. Wann d'Derivat op engem bestëmmte Punkt positiv ass, da geet d'Funktioun erop; soss geet d'Funktioun erof. A wat méi de Wäert vun der absoluter Derivat ass, dest méi héich ass den Taux vun der Verännerung vun de Funktiounswäerter, wéi och de méi steiler den Hang vun der Funktiounsgrafik.
Zum Beispill, ënner de Bedéngungen vun engem kartesesche Koordinatesystem, ass de Wäert vun der Derivat um Punkt M(0,0) gläich wéi 25 + heescht, datt op engem bestëmmte Punkt, wann de Wäert verréckelt ass no riets duerch eng konventionell Eenheet, Wäert Erhéijunge vun 25 konventionell Unitéiten. Op der Grafik gesäit et no engem zimlech steile Wäerterhéijung aus vun engem bestëmmte Punkt.
En anert Beispill. Den Derivatwäert ass gläich -0,1 heescht, datt wann déplacéiert pro eng konventionell Eenheet, Wäert reduzéiert nëmmen 0,1 konventionell Eenheet. Zur selwechter Zäit, op der Grafik vun der Funktioun, kënne mir e kaum bemierkenswäerten Downward Hang beobachten. Eng Analogie mat engem Bierg ze zéien, ass et wéi wa mir ganz lues e sanften Hang vun engem Bierg erofgeet, am Géigesaz zum Beispill virdrun, wou mir op ganz géi Peaks hu missen eropklammen :)
Also, no der Funktioun differenzéiert duerch Chance и , mir definéieren 1. Uerdnung partiell Differentialgleichungen. No der Bestëmmung vun den Equatiounen kréie mir e System vun zwou Equatiounen, andeems mir léisen, déi mir fäeg sinn esou Wäerter vun de Koeffizienten auswielen и , fir déi d'Wäerter vun den entspriechende Derivate op bestëmmte Punkte mat engem ganz, ganz klenge Betrag änneren, an am Fall vun enger analytescher Léisung guer net änneren. An anere Wierder, d'Feelerfunktioun bei de fonnte Koeffizienten wäert e Minimum erreechen, well d'Wäerter vun de partiellen Derivate op dëse Punkte gläich Null sinn.
Also, no de Regele vun der Differenzéierung, ass déi partiell derivativ Equatioun vun der 1. Uerdnung mat Respekt zum Koeffizient wäert d'Form huelen:
1. Uerdnung partiell Derivat Equatioun mat Respekt fir wäert d'Form huelen:
Als Resultat hu mir e System vun Equatioune kritt, déi eng zimlech einfach analytesch Léisung huet:
ufänken {Equatioun*}
ufänken {Fäll}
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
Enn {Fäll}
Enn {Equatioun*}
Ier Dir d'Gleichung léist, loosst eis virlueden, kontrolléieren ob d'Luede richteg ass, an d'Daten formatéieren.
Lueden an formatéieren Daten
Et sollt bemierkt datt wéinst der Tatsaach datt fir d'analytesch Léisung, an duerno fir Gradient a stochastesch Gradient Ofstamung, mir de Code an zwou Variatiounen benotzen: d'Bibliothéik benotzen NummPy an ouni et ze benotzen, da brauche mir entspriechend Dateformatéierung (kuckt Code).
Daten Luede a Veraarbechtung Code
# импортируем все нужные нам библиотеки
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 '********************************************'
Visualiséierung
Elo, nodeems mir als éischt d'Donnéeën gelueden hunn, zweetens d'Korrektheet vun der Luede gepréift hunn a schliisslech d'Daten formatéiert hunn, maache mir déi éischt Visualiséierung. D'Method déi dacks fir dëst benotzt gëtt ass Pairplot Bibliothéiken seaborn. An eisem Beispill, wéinst der limitéierter Zuel, ass et kee Sënn fir d'Bibliothéik ze benotzen seaborn. Mir wäerten déi regulär Bibliothéik benotzen matplotlib a kuckt just op d'Scatterplot.
Scatterplot Code
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()
Diagramm Nr 1 "Ofhängegkeet vum Akommes vum Mount vum Joer"
Analytesch Léisung
Loosst eis déi allgemeng Tools benotzen Python an léisen de System vun Equatioune:
ufänken {Equatioun*}
ufänken {Fäll}
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
Enn {Fäll}
Enn {Equatioun*}
Dem Cramer seng Regel no mir wäerten déi allgemeng Determinant fannen, souwéi Determinanten duerch an vum , duerno deelt de Determinant duerch zum allgemenge Determinant - fannen de Koeffizient , ähnlech fanne mir de Koeffizient .
Analytesch Léisung Code
# определим функцию для расчета коэффициентов 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)
Hei ass wat mir kruten:
Also, d'Wäerter vun de Koeffizienten goufen fonnt, d'Zomm vun de quadrateschen Ofwäichunge gouf festgeluecht. Loosst eis eng riicht Linn op de Streuungshistogramm am Aklang mat de fonnte Koeffizienten zéien.
Regressioun Linn Code
# определим функцию для формирования массива рассчетных значений выручки
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()
Diagramm Nr 2 "Korrekt a berechent Äntwerten"
Dir kënnt d'Ofwäichungsgrafik fir all Mount kucken. An eisem Fall wäerte mir kee bedeitende praktesche Wäert dovun ofginn, awer mir wäerten eis Virwëtz zefridden iwwer wéi gutt déi einfach linear Regressioungleichung d'Ofhängegkeet vum Akommes vum Mount vum Joer charakteriséiert.
Deviation Chart Code
# определим функцию для формирования массива отклонений в процентах
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()
Diagramm Nr. 3 "Ofwäichungen, %"
Net perfekt, awer mir hunn eis Aufgab fäerdeg gemaach.
Loosst eis eng Funktioun schreiwen, déi d'Koeffizienten bestëmmen и benotzt d'Bibliothéik NummPy, méi präzis wäerte mir zwou Funktiounen schreiwen: eng mat enger pseudoinverse Matrix (net an der Praxis recommandéiert, well de Prozess computationally komplex an onbestänneg ass), déi aner mat enger Matrixentgasung.
Analytesch Léisungscode (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
Loosst eis d'Zäit vergläichen fir d'Koeffizienten ze bestëmmen и , am Aklang mat den 3 presentéiert Methoden.
Code fir Berechnung Zäit
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)
Mat enger klenger Quantitéit un Daten kënnt eng "selbstgeschriwwe" Funktioun viraus, déi d'Koeffizienten mat der Cramer Method fënnt.
Elo kënnt Dir weider op aner Weeër goen fir Koeffizienten ze fannen и .
Gradient Ofstamung
Als éischt, loosst eis definéieren wat e Gradient ass. Einfach gesot, de Gradient ass e Segment deen d'Richtung vum maximale Wuesstum vun enger Funktioun uginn. Analogie mam Bierg eropklammen, wou de Gradient Gesiichter ass, wou de géiste klammen op d'Spëtzt vum Bierg ass. D'Beispill mam Bierg entwéckelen, erënnere mer datt mir tatsächlech déi steilst Ofstamung brauchen fir d'Tiefland sou séier wéi méiglech z'erreechen, dat ass de Minimum - d'Plaz wou d'Funktioun net eropgeet oder erofgeet. Zu dësem Zäitpunkt wäert d'Derivat gläich Null sinn. Dofir brauche mir keen Gradient, mee en Antigradient. Fir den Antigradient ze fannen, musst Dir just den Gradient multiplizéieren mat -1 (Minus eent).
Loosst eis oppassen op d'Tatsaach datt eng Funktioun e puer Minima kann hunn, a wann Dir an ee vun hinnen erofgaang ass mat dem Algorithmus hei ënnendrënner, kënne mir keen anere Minimum fannen, dee méi niddereg ass wéi dee fonnt. Loosst eis entspanen, dëst ass keng Gefor fir eis! An eisem Fall hu mir mat engem eenzege Minimum ze dinn, well eis Funktioun op der Grafik ass eng regulär Parabol. A wéi mir alleguerten aus eisem Schoul Mathematikcours ganz gutt wësse sollen, huet eng Parabol nëmmen ee Minimum.
Nodeems mir erausfonnt hunn firwat mir e Gradient brauche, an och datt de Gradient e Segment ass, dat heescht e Vektor mat bestëmmte Koordinaten, déi genee déiselwecht Koeffizienten sinn и mir kënnen Gradient Ofstamung ëmsetzen.
Ier Dir ufänkt, proposéiere ech just e puer Sätz iwwer den Ofstamung Algorithmus ze liesen:
- Mir bestëmmen op pseudo-zoufälleg Manéier d'Koordinate vun de Koeffizienten и . An eisem Beispill wäerte mir Koeffizienten no Null bestëmmen. Dëst ass eng gemeinsam Praxis, awer all Fall kann seng eege Praxis hunn.
- Vun Koordinaten subtrahéieren de Wäert vun der 1. Uerdnung partiell Derivat um Punkt . Also, wann d'Derivat positiv ass, da geet d'Funktioun erop. Dofir, andeems mir de Wäert vun der Derivat subtrahéieren, wäerte mir an déi entgéintgesate Richtung vum Wuesstum bewegen, dat heescht an der Ofstamungsrichtung. Wann d'Derivat negativ ass, da geet d'Funktioun op dësem Punkt erof an andeems mir de Wäert vun der Derivat subtrahéieren, beweege mir a Richtung Ofstamung.
- Mir maachen eng ähnlech Operatioun mat der Koordinate : subtract de Wäert vun der partiell Derivat um Punkt .
- Fir net iwwer de Minimum ze sprangen an an déiwe Raum ze fléien, ass et néideg d'Schrëttgréisst a Richtung Ofstamung ze setzen. Am Allgemengen, kënnt Dir e ganzen Artikel schreiwen iwwer wéi Dir de Schrëtt richteg setzt a wéi Dir et während dem Ofstamungsprozess ännert fir d'Berechnungskäschte ze reduzéieren. Awer elo hu mir eng liicht aner Aufgab virun eis, a mir wäerten d'Schrëttgréisst festleeën mat der wëssenschaftlecher Method vu "poke" oder, wéi se am allgemenge Sproch soen, empiresch.
- Eemol si mir vun de gegebene Koordinaten и d'Wäerter vun den Derivate subtrahéieren, mir kréien nei Koordinaten и . Mir huelen den nächste Schrëtt (Subtraktioun), scho vun de berechent Koordinaten. An esou fänkt den Zyklus ëmmer erëm un, bis déi erfuerderlech Konvergenz erreecht gëtt.
Alles! Elo si mir prett fir op d'Sich no der déifste Klamm vum Mariana Trench ze goen. Loosst eis ufänken.
Code fir Gradient Ofstamung
# напишем функцию градиентного спуска без использования библиотеки 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
Mir daucht bis ganz ënnen vum Marianen Trench an do hu mir all déiselwecht Koeffizientwäerter fonnt и , dat ass genee wat ze erwaarden war.
Loosst eis en aneren Tauchen huelen, nëmmen dës Kéier wäert eist Déifseefahrt mat aneren Technologien gefëllt sinn, nämlech eng Bibliothéik NummPy.
Code fir Gradient Ofstamung (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
Koeffizient Wäerter и onverännerbar.
Loosst eis kucken wéi de Feeler während der Gradient Ofstamung geännert huet, dat ass, wéi d'Zomm vun de quadrateschen Ofwäichunge mat all Schrëtt geännert huet.
Code fir Zomme vu quadrateschen Ofwäichungen ze plotten
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()
Grafik Nr.
Op der Grafik gesi mir datt mat all Schrëtt de Feeler erofgeet, an no enger gewësser Unzuel vun Iteratiounen beobachten mir eng bal horizontal Linn.
Schlussendlech schätze mer den Ënnerscheed an der Code Ausféierungszäit:
Code fir Gradient Ofstamungsberechnungszäit ze bestëmmen
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)
Vläicht maache mir eppes falsch, awer erëm ass et eng einfach "heemgeschriwwe" Funktioun déi d'Bibliothéik net benotzt NummPy outperforms der Berechnung Zäit vun enger Funktioun mat der Bibliothéik NummPy.
Awer mir stinn net stoen, awer fuere fir eng aner spannend Manéier ze studéieren fir déi einfach linear Regressiounsgleichung ze léisen. Treffen!
Stochastic Gradient Ofstamung
Fir de Prinzip vun der Operatioun vun stochastic Gradient Ofstamung séier ze verstoen, ass et besser seng Differenzen aus normal Gradient Ofstamung ze bestëmmen. Mir, am Fall vun Gradient Ofstamung, an der Equatioune vun Derivate vun и benotzt d'Zomm vun de Wäerter vun alle Funktiounen a richteg Äntwerten, déi an der Probe verfügbar sinn (dat ass, d'Zomm vun all и ). Am stochastesche Gradient Ofstamung benotze mir net all Wäerter, déi an der Probe präsent sinn, awer amplaz pseudo-zoufälleg de sougenannte Probeindex auswielen a seng Wäerter benotzen.
Zum Beispill, wann den Index als Nummer 3 (dräi) bestëmmt ass, da huelen mir d'Wäerter и , da ersetzen mir d'Wäerter an d'Derivatgleichungen a bestëmmen nei Koordinaten. Dann, nodeems mir d'Koordinate bestëmmt hunn, bestëmmen mir erëm pseudo-zoufälleg de Probeindex, ersetzen d'Wäerter, déi dem Index entspriechen, an déi partiell Differentialgleichungen, a bestëmmen d'Koordinaten op eng nei Manéier и etc. bis d'Konvergenz gréng gëtt. Op den éischte Bléck schéngt et vläicht net wéi wann dëst guer net funktionnéiert, awer et mécht. Et ass richteg datt et derwäert ass ze bemierken datt de Feeler net mat all Schrëtt erofgeet, awer et ass sécher eng Tendenz.
Wat sinn d'Virdeeler vum stochastesche Gradient Ofstamung iwwer konventionell? Wann eis Probegréisst ganz grouss ass an an Zéngdausende vu Wäerter gemooss gëtt, ass et vill méi einfach ze veraarbecht, soen, eng zoufälleg Dausend vun hinnen, anstatt déi ganz Probe. Dëst ass wou stochastesch Gradient Ofstamung an d'Spill kënnt. An eisem Fall wäerte mir natierlech net vill vun engem Ënnerscheed bemierken.
Loosst eis de Code kucken.
Code fir stochastic Gradient Ofstamung
# определим функцию стох.град.шага
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])
Mir kucken suergfälteg op d'Koeffizienten a fänken eis d'Fro ze stellen "Wéi kann dat sinn?" Mir hunn aner Koeffizientwäerter и . Vläicht huet stochastic Gradient Ofstamung méi optimal Parameteren fir d'Gleichung fonnt? Leider nee. Et ass genuch fir d'Zomm vun de quadrateschen Ofwäichungen ze kucken an ze gesinn datt mat neie Wäerter vun de Koeffizienten de Feeler méi grouss ass. Mir sinn net presséiert ze verzweifelen. Loosst eis eng Grafik vun der Feeler änneren.
Code fir d'Zomm vun de quadrateschen Ofwäichungen an der stochastescher Gradient Ofstamung ze plotten
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()
Grafik Nr.
Wann een den Zäitplang kuckt, fällt alles op der Plaz an elo flécke mir alles.
Also wat ass geschitt? Déi folgend ass geschitt. Wa mir zoufälleg e Mount auswielen, dann ass et fir de gewielte Mount datt eisen Algorithmus probéiert de Feeler beim Berechnung vun Einnahmen ze reduzéieren. Da wielt en anere Mount a widderhuelen d'Berechnung, awer mir reduzéieren de Feeler fir den zweete gewielte Mount. Denkt elo drun datt déi éischt zwee Méint wesentlech vun der Linn vun der einfacher linearer Regressioungleichung ofwäichen. Dëst bedeit datt wann ee vun dësen zwee Méint ausgewielt gëtt, andeems de Feeler vun all eenzel vun hinnen reduzéiert gëtt, erhéicht eisen Algorithmus de Feeler fir déi ganz Probe eescht. Also wat ze maachen? D'Äntwert ass einfach: Dir musst den Ofstamungsschrëtt reduzéieren. No all, duerch d'Reduktioun vun der Ofstamung Schrëtt, wäert de Feeler och ophalen "sprangen" an erof. Oder éischter, de "sprangen" Feeler wäert net ophalen, awer et wäert et net sou séier maachen :) Loosst eis kucken.
Code fir SGD mat méi klengen Inkremente ze lafen
# запустим функцию, уменьшив шаг в 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()
Grafik Nr.
D'Koeffizienten hu sech verbessert, awer sinn nach ëmmer net ideal. Hypothetesch kann dëst esou korrigéiert ginn. Mir wielen, zum Beispill, an de leschten 1000 Iteratiounen d'Wäerter vun de Koeffizienten mat deenen de Minimum Feeler gemaach gouf. Richteg, dofir musse mir och d'Wäerter vun de Koeffizienten selwer opschreiwen. Mir wäerten dat net maachen, mä éischter op den Zäitplang oppassen. Et gesäit glat aus an de Feeler schéngt gläichméisseg ze reduzéieren. Eigentlech ass dëst net wouer. Loosst eis déi éischt 1000 Iteratiounen kucken a se mat de leschte vergläichen.
Code fir SGD Chart (éischt 1000 Schrëtt)
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()
Grafik Nr 7 "Zomm vun de Quadratabweichungen SGD (éischt 1000 Schrëtt)"
Grafik Nr.
Ganz am Ufank vun der Ofstamung beobachten mir eng zimlech eenheetlech a steil Ofsenkung vum Feeler. An de leschten Iteratiounen gesi mir datt de Feeler ronderëm a ronderëm de Wäert vun 1,475 geet an e puer Momenter souguer dësen optimale Wäert entsprécht, awer da geet et ëmmer nach erop ... Ech widderhuelen, Dir kënnt d'Wäerter vun der opschreiwen Koeffizienten и , a wielt dann déi fir déi de Feeler minimal ass. Wéi och ëmmer, mir haten e méi eeschte Problem: mir hu misse 80 Tausend Schrëtt maachen (kuckt Code) fir Wäerter no bei optimal ze kréien. An dëst widdersprécht schonn d'Iddi vun der Rechenzäit mat stochastesche Gradient Ofstamung relativ zum Gradient Ofstamung ze spueren. Wat kann korrigéiert a verbessert ginn? Et ass net schwéier ze bemierken datt mir an den éischten Iteratiounen zouversiichtlech erofgoen an dofir sollte mir e grousse Schrëtt an den éischten Iteratiounen verloossen an de Schrëtt reduzéieren wéi mir virukommen. Mir wäerten dat net an dësem Artikel maachen - et ass schonn ze laang. Déi, déi wëllen, kënne selwer iwwerdenken, wéi dat ze maachen, et ass net schwéier :)
Loosst eis elo stochastesch Gradient Ofstamung mat der Bibliothéik ausféieren NummPy (a loosst eis net iwwer d'Steng stousse, déi mir virdru identifizéiert hunn)
Code fir Stochastic Gradient Descent (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
D'Wäerter hu sech bal d'selwecht gewisen wéi wann se erofgaange sinn ouni ze benotzen NummPy. Allerdéngs ass dëst logesch.
Loosst eis erausfannen wéi laang stochastesch Gradient Ofstigen eis gedauert hunn.
Code fir SGD Berechnungszäit ze bestëmmen (80 Tausend Schrëtt)
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)
Wat méi wäit an de Bësch sinn, wat d'Wolleken méi däischter sinn: erëm weist déi "selwer geschriwwen" Formel dat bescht Resultat. All dëst hindeit datt et nach méi subtile Weeër musse ginn fir d'Bibliothéik ze benotzen NummPy, déi d'Rechnungsoperatioune wierklech beschleunegen. An dësem Artikel wäerte mir net iwwer si léieren. An Ärer Fräizäit gëtt et eppes ze denken :)
Mir zesummefaassen
Ier ech zesummefaassen, wëll ech eng Fro beäntweren, déi héchstwahrscheinlech vun eisem léiwe Lieser entstanen ass. Firwat eigentlech esou "Folter" mat Ofstigen, firwat musse mir de Bierg erop an erof goen (haaptsächlech erof) fir dat geschätzte Déifland ze fannen, wa mir esou e mächtegt an einfacht Apparat an den Hänn hunn, an der Form vun enger analytescher Léisung, déi eis direkt op déi richteg Plaz teleportéiert?
D'Äntwert op dës Fro läit op der Uewerfläch. Elo hu mir e ganz einfacht Beispill gekuckt, an deem déi richteg Äntwert ass hänkt vun engem Zeechen of . Dir gesitt dat net dacks am Liewen, also loosst eis virstellen datt mir 2, 30, 50 oder méi Schëlder hunn. Loosst eis dëst Dausende addéieren, oder souguer Zéngdausende vu Wäerter fir all Attribut. An dësem Fall kann d'analytesch Léisung den Test net widderstoen a versoen. Am Tour, Gradient Ofstamung a seng Variatiounen wäerten eis lues awer sécher méi no un d'Zil bréngen - de Minimum vun der Funktioun. A maach der keng Suergen iwwer d'Geschwindegkeet - mir wäerte méiglecherweis Weeër kucken, déi eis erlaben d'Schrëttlängt ze setzen an ze reguléieren (dat ass Geschwindegkeet).
An elo den eigentleche kuerze Resumé.
Als éischt hoffen ech datt d'Material, dat am Artikel presentéiert gëtt, hëlleft "Datewëssenschaftler" unzefänken fir ze verstoen wéi einfach (an net nëmmen) linear Regressiounsgleichungen ze léisen.
Zweetens hu mir verschidde Weeër gekuckt fir d'Gleichung ze léisen. Elo, ofhängeg vun der Situatioun, kënne mir deen wielen deen am Beschten passt fir de Problem ze léisen.
Drëttens hu mir d'Kraaft vun zousätzlechen Astellungen gesinn, nämlech d'Gradient Ofstamungsschrëttlängt. Dëse Parameter kann net vernoléissegt ginn. Wéi uewen uginn, fir d'Käschte vun de Berechnungen ze reduzéieren, sollt d'Schrëttlängt während der Ofstamung geännert ginn.
Véiertens, an eisem Fall, hunn "heemgeschriwwe" Funktiounen déi bescht Zäitresultater fir Berechnungen gewisen. Dëst ass wahrscheinlech wéinst net déi professionell Notzung vun de Fäegkeeten vun der Bibliothéik NummPy. Awer sief et wéi et ass, déi folgend Conclusioun proposéiert sech selwer. Engersäits ass et heiansdo derwäert etabléiert Meenungen a Fro ze stellen, an op der anerer Säit ass et net ëmmer derwäert alles ze komplizéieren - am Géigendeel, heiansdo ass eng méi einfach Manéier fir e Problem ze léisen méi effektiv. A well eist Zil war dräi Approche ze analyséieren fir eng einfach linear Regressiounsgleichung ze léisen, war d'Benotzung vu "selbstgeschriwwene" Funktiounen fir eis ganz genuch.
Literatur (oder sou eppes)
1. Linearschrëft Réckgang
2. mannst Plaze Method
3. Derivat
4. Gradient
5. Gradient Ofstamung
6. NumPy Bibliothéik
Source: will.com