Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Greinin fjallar um nokkrar leiðir til að ákvarða stærðfræðilega jöfnu einfaldrar (pörðrar) aðhvarfslínu.

Allar aðferðir við að leysa jöfnuna sem fjallað er um hér eru byggðar á minnstu ferningaaðferðinni. Við skulum tákna aðferðirnar sem hér segir:

  • Greiningarlausn
  • Gradient Descent
  • Stókastísk hallafall

Fyrir hverja aðferð til að leysa jöfnu beinnar línu gefur greinin ýmsar aðgerðir, sem eru aðallega skipt í þær sem eru skrifaðar án þess að nota bókasafnið Numpy og þeir sem nota fyrir útreikninga Numpy. Það er talið að kunnátta notkun Numpy mun draga úr tölvukostnaði.

Allur kóði sem gefinn er upp í greininni er skrifaður á tungumálinu Python 2.7 að nota Jupyter minnisbók. Frumkóði og skrá með sýnishornsgögnum er birt á Github

Greinin er frekar ætluð bæði byrjendum og þeim sem þegar eru smám saman farnir að ná tökum á náminu á mjög breiðum kafla í gervigreind - vélanám.

Til að útskýra efnið notum við mjög einfalt dæmi.

Dæmi um skilyrði

Við höfum fimm gildi sem einkenna ósjálfstæði Y frá X (Tafla nr. 1):

Tafla nr. 1 „Dæmi um skilyrði“

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Við munum gera ráð fyrir að gildin Að leysa jöfnu einfaldrar línulegrar aðhvarfs er mánuður ársins, og Að leysa jöfnu einfaldrar línulegrar aðhvarfs — tekjur í þessum mánuði. Með öðrum orðum, tekjur ráðast af mánuði ársins, og Að leysa jöfnu einfaldrar línulegrar aðhvarfs - eina merkið sem tekjur eru háðar.

Dæmið er svo sem svo, bæði frá sjónarhóli skilyrtrar háðar tekna á mánuði ársins og frá sjónarhóli fjölda gilda - þau eru mjög fá. Hins vegar mun slík einföldun gera það mögulegt, eins og sagt er, að útskýra, ekki alltaf með auðveldum hætti, efnið sem byrjendur tileinka sér. Og einnig mun einfaldleiki talnanna leyfa þeim sem vilja leysa dæmið á pappír án verulegs launakostnaðar.

Gefum okkur að hægt sé að nálgast ósjálfstæðina sem gefin er upp í dæminu nokkuð vel með stærðfræðilegri jöfnu einfaldrar (pörðrar) aðhvarfslínu formsins:

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

þar sem Að leysa jöfnu einfaldrar línulegrar aðhvarfs er mánuðurinn sem tekjur fengust, Að leysa jöfnu einfaldrar línulegrar aðhvarfs — tekjur sem samsvara mánuðinum, Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs eru aðhvarfsstuðlar áætlaðrar línu.

Athugið að stuðullinn Að leysa jöfnu einfaldrar línulegrar aðhvarfs oft kallaður halli eða halli áætlaðrar línu; táknar þá upphæð sem Að leysa jöfnu einfaldrar línulegrar aðhvarfs þegar það breytist Að leysa jöfnu einfaldrar línulegrar aðhvarfs.

Augljóslega er verkefni okkar í dæminu að velja slíka stuðla í jöfnuna Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs, þar sem frávik reiknaðra tekjugilda okkar eftir mánuði frá sönnum svörum, þ.e. gildi sem fram koma í úrtakinu verða í lágmarki.

Minnsta ferningur aðferð

Samkvæmt minnstu ferningaaðferðinni á að reikna frávikið með því að setja það í veldi. Þessi tækni gerir þér kleift að forðast gagnkvæma niðurfellingu frávika ef þau hafa gagnstæð merki. Til dæmis, ef í einu tilviki er frávikið +5 (plús fimm), og í hinum -5 (mínus fimm), þá mun summa frávikanna hætta við hvert annað og verða 0 (núll). Það er ekki hægt að setja frávikið í veldi heldur að nota eiginleika stuðulsins og þá verða öll frávik jákvæð og safnast upp. Við munum ekki staldra við þetta atriði í smáatriðum, heldur einfaldlega gefa til kynna að til þæginda við útreikninga er venja að velda frávikinu.

Svona lítur formúlan út þar sem við munum ákvarða minnstu summu kvaðratfrávika (villur):

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

þar sem Að leysa jöfnu einfaldrar línulegrar aðhvarfs er fall af nálgun sannra svara (þ.e. tekjur sem við reiknuðum),

Að leysa jöfnu einfaldrar línulegrar aðhvarfs eru réttu svörin (tekjur gefnar upp í úrtakinu),

Að leysa jöfnu einfaldrar línulegrar aðhvarfs er úrtaksvísitalan (fjöldi mánaðarins sem frávikið er ákvarðað)

Við skulum aðgreina fallið, skilgreina hlutadiffurjöfnur og vera tilbúin til að halda áfram í greiningarlausnina. En fyrst skulum við fara í stutta skoðunarferð um hvað aðgreining er og muna rúmfræðilega merkingu afleiðunnar.

Aðgreining

Aðgreining er sú aðgerð að finna afleiðu falls.

Til hvers er afleiðan notuð? Afleiða falls einkennir breytingahraða fallsins og segir okkur stefnu þess. Ef afleiðan á tilteknum stað er jákvæð þá eykst fallið, annars minnkar fallið. Og því hærra sem gildi algildu afleiðunnar er, því hærra er breytingahraði fallgildanna, sem og því brattari halli fallgrafitsins.

Til dæmis, við skilyrði kartesísks hnitakerfis, er gildi afleiðunnar í punktinum M(0,0) jafnt og 25 + þýðir að á tilteknum tímapunkti, þegar gildið er fært til Að leysa jöfnu einfaldrar línulegrar aðhvarfs til hægri með hefðbundinni einingu, gildi Að leysa jöfnu einfaldrar línulegrar aðhvarfs hækkar um 25 hefðbundnar einingar. Á línuritinu lítur út fyrir að vera nokkuð mikil hækkun á gildum Að leysa jöfnu einfaldrar línulegrar aðhvarfs frá tilteknum stað.

Annað dæmi. Afleiðugildið er jafnt -0,1 þýðir að þegar flutt er Að leysa jöfnu einfaldrar línulegrar aðhvarfs á eina hefðbundna einingu, verðmæti Að leysa jöfnu einfaldrar línulegrar aðhvarfs lækkar aðeins um 0,1 hefðbundna einingu. Á sama tíma, á línuriti fallsins, getum við fylgst með varla áberandi halla niður á við. Með hliðstæðu við fjall, þá er eins og við séum mjög hægt niður hæga brekku af fjalli, ólíkt fyrra dæminu, þar sem við þurftum að klífa mjög bratta tinda :)

Svona, eftir aðgreining á aðgerðinni Að leysa jöfnu einfaldrar línulegrar aðhvarfs með ólíkindum Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs, skilgreinum við 1. stigs hlutadiffurjöfnur. Eftir að hafa ákvarðað jöfnurnar fáum við kerfi tveggja jöfnur, með því að leysa þær munum við geta valið slík gildi á stuðlunum Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs, þar sem gildi samsvarandi afleiðna á gefnum punktum breytast um mjög, mjög lítið magn og þegar um greiningarlausn er að ræða breytast alls ekki. Með öðrum orðum, villufallið á fundnum stuðlum mun ná lágmarki, þar sem gildi hlutaafleiðnanna á þessum punktum verða jöfn núlli.

Þannig að samkvæmt aðgreiningarreglunum er hlutafleiðujöfnan af 1. röð með tilliti til stuðulsins Að leysa jöfnu einfaldrar línulegrar aðhvarfs mun taka á sig form:

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

1. stigs hlutafleiðujöfnu með tilliti til Að leysa jöfnu einfaldrar línulegrar aðhvarfs mun taka á sig form:

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Fyrir vikið fengum við jöfnukerfi sem hefur frekar einfalda greiningarlausn:

byrja{jöfnu*}
byrja{tilfelli}
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
enda{tilfelli}
enda{jöfnu*}

Áður en jöfnuna er leyst skulum við forhlaða, athuga hvort hleðslan sé rétt og forsníða gögnin.

Hleður og forsníða gögn

Það skal tekið fram að vegna þeirrar staðreyndar að fyrir greiningarlausnina, og í kjölfarið fyrir halla og stochastic halla, munum við nota kóðann í tveimur afbrigðum: með því að nota bókasafnið Numpy og án þess að nota það, þá þurfum við viðeigandi gagnasnið (sjá kóða).

Gagnahleðsla og vinnsla kóða

# импортируем все нужные нам библиотеки
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 '********************************************'

Sjónræn

Nú, eftir að við höfum í fyrsta lagi hlaðið gögnunum, í öðru lagi, athugað réttmæti hleðslunnar og að lokum forsniðið gögnin, munum við framkvæma fyrstu sjónmyndina. Aðferðin sem oft er notuð við þetta er parmynd bókasöfn Sjófæddur. Í okkar dæmi, vegna takmarkaðs fjölda, þýðir ekkert að nota bókasafnið Sjófæddur. Við munum nota venjulegt bókasafn matplotlib og líttu bara á dreifingarmyndina.

Dreifingarkóði

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()

Mynd nr. 1 „Tekjuháð ársmánuði“

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Greiningarlausn

Við skulum nota algengustu verkfærin í python og leysa jöfnukerfið:

byrja{jöfnu*}
byrja{tilfelli}
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
enda{tilfelli}
enda{jöfnu*}

Samkvæmt reglu Cramers við finnum almenna ákvörðunarþáttinn, sem og ákvarðanir eftir Að leysa jöfnu einfaldrar línulegrar aðhvarfs og eftir Að leysa jöfnu einfaldrar línulegrar aðhvarfs, eftir það, deilt ákvarðandi með Að leysa jöfnu einfaldrar línulegrar aðhvarfs að almenna ákvörðunarvaldinu - finndu stuðulinn Að leysa jöfnu einfaldrar línulegrar aðhvarfs, á sama hátt finnum við stuðulinn Að leysa jöfnu einfaldrar línulegrar aðhvarfs.

Kóði fyrir greiningarlausn

# определим функцию для расчета коэффициентов 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)

Hér er það sem við fengum:

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Svo, gildi stuðlanna hafa fundist, summan af kvaðratfrávikum hefur verið staðfest. Drögum beina línu á dreifingarstuðlinum í samræmi við fundna stuðlana.

Aðhvarfslínukóði

# определим функцию для формирования массива рассчетных значений выручки
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()

Mynd nr. 2 „Rétt og útreiknuð svör“

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Hægt er að skoða fráviksgrafið fyrir hvern mánuð. Í okkar tilviki munum við ekki draga neitt marktækt hagnýtt gildi af því, en við munum seðja forvitni okkar um hversu vel einfalda línulega aðhvarfsjöfnan einkennir háð tekna á mánuði ársins.

Frávikstöflukóði

# определим функцию для формирования массива отклонений в процентах
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()

Mynd nr. 3 „Frávik, %“

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Ekki fullkomið, en við kláruðum verkefnið okkar.

Við skulum skrifa fall sem, til að ákvarða stuðlana Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs notar bókasafnið NumpyNánar tiltekið munum við skrifa tvær aðgerðir: önnur með gerviöfugum fylki (ekki mælt með því í reynd, þar sem ferlið er flókið og óstöðugt reikningslega séð), hina með fylkisjöfnu.

Kóði fyrir greiningarlausn (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

Berum saman þann tíma sem fer í að ákvarða stuðlana Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs, í samræmi við 3 kynntar aðferðir.

Kóði til að reikna út útreikningstíma

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)

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Með litlu magni af gögnum kemur fram „sjálfskrifuð“ aðgerð sem finnur stuðlana með aðferð Cramer.

Nú er hægt að fara yfir á aðrar leiðir til að finna stuðla Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs.

Gradient Descent

Fyrst skulum við skilgreina hvað halli er. Einfaldlega sagt, hallinn er hluti sem gefur til kynna stefnu hámarksvaxtar falls. Á hliðstæðan hátt við að klífa fjall, þar sem hallinn snýr að því þar sem brattasta klifur upp á topp fjallsins er. Þegar við þróum dæmið með fjallinu, munum við að í raun þurfum við bröttustu lækkunina til að komast á láglendið eins fljótt og auðið er, það er lágmarkið - staðurinn þar sem virknin eykst ekki eða minnkar. Á þessum tímapunkti verður afleiðan jöfn núlli. Þess vegna þurfum við ekki halla heldur andhalla. Til að finna andstigann þarftu bara að margfalda hallann með -1 (mínus einn).

Við skulum gefa gaum að því að fall getur haft nokkur lágmörk og eftir að hafa farið niður í eitt þeirra með því að nota reikniritið sem lagt er til hér að neðan, munum við ekki geta fundið annað lágmark sem gæti verið lægra en það sem fannst. Við skulum slaka á, þetta er ekki ógn við okkur! Í okkar tilviki erum við að fást við eitt lágmark, þar sem hlutverk okkar Að leysa jöfnu einfaldrar línulegrar aðhvarfs á línuritinu er venjuleg fleyga. Og eins og við ættum öll að vita mjög vel úr skólastærðfræðinámskeiðinu okkar, þá hefur fleygboga aðeins eitt lágmark.

Eftir að við komumst að því hvers vegna við þurftum halla, og líka að hallinn er hluti, það er vigur með tilteknum hnitum, sem eru nákvæmlega sömu stuðlar Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs við getum innleitt hallafall.

Áður en þú byrjar legg ég til að þú lesir aðeins nokkrar setningar um niðurgöngualgrímið:

  • Við ákveðum með gervi-slembihnit hnit stuðlanna Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs. Í dæminu okkar munum við skilgreina stuðla nálægt núlli. Þetta er algeng venja, en hvert mál getur haft sína eigin venju.
  • Frá hnit Að leysa jöfnu einfaldrar línulegrar aðhvarfs draga frá gildi 1. stigs hlutaafleiðu á punktinum Að leysa jöfnu einfaldrar línulegrar aðhvarfs. Þannig að ef afleiðan er jákvæð þá eykst fallið. Þess vegna, með því að draga frá gildi afleiðunnar, munum við færa okkur í gagnstæða átt vaxtar, það er að segja í átt að niðurfærslu. Ef afleiðan er neikvæð þá lækkar fallið á þessum tímapunkti og með því að draga frá gildi afleiðunnar færum við okkur í lækkandi átt.
  • Við gerum svipaða aðgerð með hnitinu Að leysa jöfnu einfaldrar línulegrar aðhvarfs: Dragðu frá gildi hlutaafleiðunnar í punktinum Að leysa jöfnu einfaldrar línulegrar aðhvarfs.
  • Til þess að hoppa ekki yfir lágmarkið og fljúga út í djúpt geim er nauðsynlegt að stilla þrepa stærð í átt að niðurgöngu. Almennt séð gætirðu skrifað heila grein um hvernig á að stilla skrefið rétt og hvernig á að breyta því á meðan á niðurgöngu stendur til að draga úr reiknikostnaði. En nú höfum við aðeins annað verkefni framundan og við munum ákvarða skrefstærðina með því að nota vísindalega aðferðina „pota“ eða, eins og þeir segja í venjulegu tali, reynslu.
  • Þegar við erum frá gefnum hnitum Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs draga gildi afleiðanna frá, við fáum ný hnit Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs. Við tökum næsta skref (frádráttur), þegar frá útreiknuðum hnitum. Og þannig byrjar hringrásin aftur og aftur, þar til nauðsynlegri samleitni er náð.

Allt! Nú erum við tilbúin að fara í leit að dýpsta gilinu í Maríuskurðinum. Byrjum.

Kóði fyrir halla niður

# напишем функцию градиентного спуска без использования библиотеки 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

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Við köfuðum alveg neðst í Mariana-skurðinum og þar fundum við öll sömu stuðullgildin Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs, sem er nákvæmlega það sem búast mátti við.

Tökum aðra köfun, aðeins í þetta skiptið mun djúpsjávarfarartækið okkar fyllast af annarri tækni, nefnilega bókasafni Numpy.

Kóði fyrir hallafall (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

Að leysa jöfnu einfaldrar línulegrar aðhvarfs
Stuðlagildi Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs óbreytanlegt.

Við skulum skoða hvernig villan breyttist við hallafall, það er hvernig summan af kvaðratfrávikum breyttist með hverju skrefi.

Kóði til að teikna upp upphæðir í veldi frávikum

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()

Mynd nr. 4 „Summa af kvaðratfrávikum við hallafall“

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Á línuritinu sjáum við að með hverju skrefi minnkar skekkjan og eftir ákveðinn fjölda endurtekningar sjáum við næstum lárétta línu.

Að lokum skulum við áætla muninn á keyrslutíma kóða:

Kóði til að ákvarða útreikningstíma halla

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)

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Kannski erum við að gera eitthvað rangt, en aftur er þetta einföld „heimaskrifuð“ aðgerð sem notar ekki bókasafnið Numpy er betri en útreikningstími falls sem notar bókasafnið Numpy.

En við stöndum ekki í stað, heldur erum að fara að rannsaka aðra spennandi leið til að leysa hina einföldu línulegu aðhvarfsjöfnu. Hittumst!

Stókastísk hallafall

Til þess að skilja fljótt meginregluna um starfsemi stochastic hallafalls, er betra að ákvarða muninn á því frá venjulegu hallafalli. Við, þegar um er að ræða hallafall, í jöfnum afleiða af Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs notaði summan af gildum allra eiginleika og sönn svör sem eru tiltæk í úrtakinu (þ.e. summan af öllum Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs). Í stochastic hallafalli, munum við ekki nota öll gildin sem eru til staðar í úrtakinu, en í staðinn veljum við gervi-handahófi svokallaðan úrtaksvísitölu og notum gildi hans.

Til dæmis, ef vísitalan er ákveðin í að vera númer 3 (þrír), þá tökum við gildin Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs, þá setjum við gildin í afleiðujöfnurnar og ákveðum ný hnit. Síðan, eftir að hafa ákvarðað hnitin, ákveðum við aftur sýnishornsvísitöluna af handahófi, setjum gildin sem samsvara vísitölunni í hlutadiffurjöfnur og ákveðum hnitin á nýjan hátt Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs o.s.frv. þar til samruninn verður grænn. Við fyrstu sýn virðist kannski ekki eins og þetta gæti virkað yfirleitt, en það gerir það. Það er að vísu rétt að taka fram að skekkjan minnkar ekki með hverju skrefi, en það er vissulega tilhneiging.

Hverjir eru kostir stokastískrar hallarlækkunar fram yfir hefðbundna? Ef úrtaksstærðin okkar er mjög stór og mæld í tugþúsundum gilda, þá er miklu auðveldara að vinna úr, segjum, þúsund þeirra af handahófi, frekar en allt úrtakið. Þetta er þar sem stochastic hallafall kemur við sögu. Í okkar tilviki munum við auðvitað ekki taka eftir miklum mun.

Við skulum skoða kóðann.

Kóði fyrir stochastic hallafall

# определим функцию стох.град.шага
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])

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Við lítum vandlega á stuðlana og grípum okkur í að spyrja spurningarinnar „Hvernig getur þetta verið?“ Við fengum önnur stuðlagildi Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs. Kannski hefur stochastic gradient decent fundið betri færibreytur fyrir jöfnuna? Nei, því miður. Það er nóg að skoða summan af kvaðratfrávikum og sjá að með nýjum gildum stuðlanna er skekkjan meiri. Við erum ekki að flýta okkur að örvænta. Við skulum byggja línurit af villubreytingunni.

Kóði til að teikna upp summan af kvaðratfrávikum í stochastic hallafalli

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()

Gröf nr. 5 „Summa af kvaðratfrávikum við stochastic hallafall“

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Þegar horft er á áætlunina þá fellur allt á sinn stað og nú ætlum við að laga allt.

Hvað gerðist? Eftirfarandi gerðist. Þegar við veljum mánuð af handahófi, þá er það fyrir þann mánuð sem reiknirit okkar leitast við að draga úr villunni í útreikningi tekna. Síðan veljum við annan mánuð og endurtökum útreikninginn, en við lækkum skekkjuna fyrir seinni valda mánuðinn. Mundu nú að fyrstu tveir mánuðirnir víkja verulega frá línunni í einföldu línulegu aðhvarfsjöfnunni. Þetta þýðir að þegar einhver þessara tveggja mánaða er valinn, með því að draga úr skekkju hvers þeirra, eykur reiknirit okkar villuna fyrir allt úrtakið verulega. Svo hvað á að gera? Svarið er einfalt: þú þarft að minnka niðurstigið. Þegar öllu er á botninn hvolft, með því að minnka stigið, hættir villan líka að „hoppa“ upp og niður. Eða réttara sagt, „stökk“ villan hættir ekki, en hún mun ekki gera það svo fljótt :) Við skulum athuga.

Kóði til að keyra SGD með smærri þrepum

# запустим функцию, уменьшив шаг в 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()

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Mynd nr. 6 „Summa frávika í veldi við lækkandi halla (80 þúsund skref)“

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Stuðlarnir hafa batnað en eru samt ekki ákjósanlegir. Tilgáta er hægt að leiðrétta þetta með þessum hætti. Við veljum, til dæmis, í síðustu 1000 endurtekningunum gildin á stuðlunum sem lágmarksvillan var gerð með. Að vísu verðum við líka að skrifa niður gildi stuðlanna sjálfra. Við munum ekki gera þetta, heldur huga að dagskránni. Það lítur vel út og villan virðist minnka jafnt og þétt. Reyndar er þetta ekki satt. Skoðum fyrstu 1000 endurtekningarnar og berum þær saman við þær síðustu.

Kóði fyrir SGD graf (fyrstu 1000 skrefin)

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()

Mynd nr. 7 „Summa af kvaðratfrávikum SGD (fyrstu 1000 skrefin)“

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Gröf nr. 8 „Summa af kvaðratfrávikum SGD (síðustu 1000 skrefin)“

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Strax í upphafi niðurgöngunnar sjáum við nokkuð jafna og brötta fækkun skekkju. Í síðustu endurtekningum sjáum við að villan fer um og í kringum gildið 1,475 og jafngildir jafnvel þessu kjörgildi á sumum augnablikum, en þá hækkar hún samt... Ég endurtek, þú getur skrifað niður gildi stuðlar Að leysa jöfnu einfaldrar línulegrar aðhvarfs и Að leysa jöfnu einfaldrar línulegrar aðhvarfs, og veldu síðan þá sem villan er í lágmarki fyrir. Hins vegar áttum við við alvarlegra vandamál að stríða: við þurftum að taka 80 þúsund skref (sjá kóða) til að ná gildum nálægt bestu. Og þetta stangast nú þegar á við hugmyndina um að spara útreikningstíma með stokastískum hallafalli miðað við hallafall. Hvað er hægt að laga og bæta? Það er ekki erfitt að taka eftir því að í fyrstu endurtekningunum erum við sjálfsörugg að fara niður og því ættum við að skilja eftir stórt skref í fyrstu endurtekningunum og minnka skrefið eftir því sem við höldum áfram. Við munum ekki gera þetta í þessari grein - það er nú þegar of langt. Þeir sem vilja geta hugsað sjálfir hvernig á að gera þetta, það er ekki erfitt :)

Nú skulum við framkvæma stochastic hallafall með því að nota bókasafnið Numpy (og við skulum ekki hrasa yfir steinunum sem við greindum áðan)

Kóði fyrir Stóchastic 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

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Gildin reyndust vera nánast þau sömu og þegar farið var niður án þess að nota Numpy. Hins vegar er þetta rökrétt.

Við skulum komast að því hversu langan langan stigahallalækkana tók okkur.

Kóði til að ákvarða SGD útreikningstíma (80 þúsund skref)

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)

Að leysa jöfnu einfaldrar línulegrar aðhvarfs

Því lengra inn í skóginn, því dekkri eru skýin: aftur sýnir „sjálfskrifaða“ formúlan bestu niðurstöðuna. Allt þetta bendir til þess að það hljóti að vera enn lúmskari leiðir til að nota bókasafnið Numpy, sem hraðar raunverulega útreikningsaðgerðum. Í þessari grein munum við ekki læra um þá. Það verður eitthvað til að hugsa um í frítíma þínum :)

Við tökum saman

Áður en ég dreg saman í stuttu máli langar mig að svara spurningu sem að öllum líkindum vaknaði frá okkar kæru lesanda. Af hverju, í raun, svona „pyntingar“ með niðurleiðum, hvers vegna þurfum við að ganga upp og niður fjallið (aðallega niður) til að finna hið dýrmæta láglendi, ef við höfum í höndum okkar svo öflugt og einfalt tæki, í formi greiningarlausnar sem sendir okkur samstundis á réttan stað?

Svarið við þessari spurningu liggur á yfirborðinu. Nú höfum við skoðað mjög einfalt dæmi, þar sem hið sanna svar er Að leysa jöfnu einfaldrar línulegrar aðhvarfs fer eftir einu merki Að leysa jöfnu einfaldrar línulegrar aðhvarfs. Þú sérð þetta ekki oft í lífinu, svo við skulum ímynda okkur að við höfum 2, 30, 50 eða fleiri merki. Við skulum bæta við þetta þúsundum, eða jafnvel tugum þúsunda gilda fyrir hvern eiginleika. Í þessu tilviki getur verið að greiningarlausnin standist ekki prófið og mistekst. Aftur á móti mun halli og afbrigði hennar hægt en örugglega færa okkur nær markmiðinu - lágmarki fallsins. Og ekki hafa áhyggjur af hraða - við munum líklega skoða leiðir sem gera okkur kleift að stilla og stilla skreflengd (það er hraða).

Og nú í raun stutt samantekt.

Í fyrsta lagi vona ég að efnið sem kynnt er í greininni muni hjálpa byrjendum „gagnafræðingum“ við að skilja hvernig eigi að leysa einfaldar (en ekki aðeins) línulegar aðhvarfsjöfnur.

Í öðru lagi skoðuðum við nokkrar leiðir til að leysa jöfnuna. Núna, eftir aðstæðum, getum við valið þann sem er best til þess fallinn að leysa vandamálið.

Í þriðja lagi sáum við kraftinn í viðbótarstillingum, þ.e. þrepalengd hallarlækkunar. Ekki er hægt að hunsa þessa breytu. Eins og fram kemur hér að ofan, til að draga úr kostnaði við útreikninga, ætti að breyta skrefalengdinni á meðan á niðurleiðinni stendur.

Í fjórða lagi, í okkar tilviki, sýndu „heimskrifaðar“ aðgerðir bestu tímaniðurstöður fyrir útreikninga. Þetta er líklega vegna þess að ekki er fagmannlegasta notkun á getu bókasafnsins Numpy. En hvernig sem á það er litið, þá bendir eftirfarandi ályktun til sjálfs sín. Annars vegar er stundum þess virði að efast um viðurkenndar skoðanir og hins vegar er ekki alltaf þess virði að flækja allt - þvert á móti, stundum er einfaldari leið til að leysa vandamál skilvirkari. Og þar sem markmið okkar var að greina þrjár aðferðir til að leysa einfalda línulega aðhvarfsjöfnu, var notkun „sjálfskrifaðra“ aðgerða alveg nóg fyrir okkur.

Bókmenntir (eða eitthvað svoleiðis)

1. Línuleg aðhvarf

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

2. Aðferð minnstu ferninga

mathprofi.ru/metod_naimenshih_kvadratov.html

3. Afleiða

www.mathprofi.ru/chastnye_proizvodnye_primery.html

4. Halli

mathprofi.ru/proizvodnaja_po_napravleniju_i_gradient.html

5. Halli niður

habr.com/en/post/471458

habr.com/en/post/307312

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

6. NumPy bókasafn

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

Heimild: www.habr.com

Bæta við athugasemd