Gotar çend awayan ji bo destnîşankirina hevkêşeya matematîkî ya xêzek regresyonê ya hêsan (hevdanî) nîqaş dike.
Hemî rêbazên çareserkirina hevkêşeya ku li vir hatî nîqaş kirin li ser bingeha rêbaza çarçikên herî kêm in. Ka em rêbazan wiha destnîşan bikin:
- Çareseriya analîtîk
- Gradient Descent
- Daketina gradient Stochastic
Ji bo her awayê çareserkirina hevkêşeya rêzek rast, gotar fonksiyonên cihêreng peyda dike, ku bi giranî li yên ku bêyî karanîna pirtûkxaneyê têne nivîsandin têne dabeş kirin. numpy û yên ku ji bo hesaban bikar tînin numpy. Tê bawer kirin ku karanîna jêhatî ye numpy dê lêçûnên komputerê kêm bike.
Hemî kodên ku di gotarê de têne dayîn bi zimanî têne nivîsandin python-2.7 bikar anîn Jupyter Notebook. Koda çavkaniyê û pelê bi daneyên nimûneyê li ser têne şandin
Gotar bêtir hem ji destpêkeran re û hem jî ji bo kesên ku berê hêdî hêdî dest bi xwendina beşa pir berfireh a di îstîxbarata sûnî de - fêrbûna makîneyê - master kirine.
Ji bo ronîkirina materyalê, em mînakek pir hêsan bikar tînin.
Şertên mînak
Pênc nirxên me hene ku girêdayîbûnê diyar dikin Y ji X (Tablo No. 1):
Tabloya Hejmar 1 "Şertên Mînak"
Em ê texmîn bikin ku nirxên meha salê ye, û - hatina vê mehê. Bi gotineke din, hatina bi meha salê ve girêdayî ye, û - yekane nîşana ku dahat pê ve girêdayî ye.
Nimûne wusa ye, hem ji hêla girêdayîbûna şertî ya dahatê ya meha salê, hem jî ji hêla hejmara nirxan ve - ji wan pir hindik in. Lêbelê, hêsankirinek wusa dê gengaz bike, wekî ku ew dibêjin, ne her gav bi hêsanî, materyalê ku destpêk asîmîle dikin rave bikin. Û di heman demê de sadebûna jimareyan dê rê bide kesên ku dixwazin nimûneyê li ser kaxezê bêyî lêçûnên girîng ên kedê çareser bikin.
Ka em bihesibînin ku girêdayîbûna ku di nimûneyê de hatî dayîn dikare bi hevkêşeya matematîkî ya xêzek regresyonê ya sade (hevdanî) ya formê pir baş were nêzîk kirin:
ko meha ku tê de hatin wergirtin e, - hatina li gorî mehê, и jimareyên paşveçûnê yên rêza texmînkirî ne.
Bala xwe bidin hevsere pir caran jê re slope an gradient xêza texmînkirî tê gotin; nîşan dide mîqdara ku bi dema ku ew diguhere .
Diyar e, peywira me di nimûneyê de ev e ku em hevkêşeyên weha di hevkêşeyê de hilbijêrin и , ku li gorî mehê ji bersivên rastîn veqetînên nirxên dahata me yên hesabkirî, yanî. nirxên ku di nimûneyê de têne pêşkêş kirin dê hindik be.
Rêbaza herî kêm çargoşe
Li gorî rêbaza çarçikên herî hindik, divê veqetîn bi çargoşekirina wê were hesibandin. Ev teknîk dihêle hûn ji betalkirina hevûdu ya devjêberan dûr bixin ger nîşanên berevajî wan hebin. Mînakî, heke di rewşekê de, dehfdan hebe +5 (zêde pênc), û di ya din de -5 (minus pênc), wê hingê dê berhevoka devjêberan hevûdu betal bike û bibe 0 (sifir). Mimkûn e ku devjêberdanê neyê çargoşekirin, lê meriv taybetmendiya modulusê bikar bîne û wê hingê hemî vekêşî dê erênî bin û dê kom bibin. Em ê li ser vê xalê bi hûrgulî nesekinin, lê bi tenê destnîşan dikin ku ji bo rehetiya hesaban, adetî ye ku devjêberdanê çargoşe bikin.
Formula bi vî rengî xuya dike ku em ê herî hindik berhevokên çargoşeyan (çewtiyan) diyar bikin:
ko fonksiyonek nêzîkbûna bersivên rastîn e (ango, dahata ku me hesab kiriye),
bersivên rastîn in (hatina ku di nimûneyê de hatî peyda kirin),
nîşana nimûneyê ye (hejmara meha ku tê de veqetîn tê destnîşankirin)
Werin em fonksiyonê ji hev cuda bikin, hevokên cudahiya qismî diyar bikin û amade bin ku biçin çareseriya analîtîk. Lê pêşî, bila em gerokek kurt li ser çi cihêrengiyê bikin û wateya geometrîkî ya deravê bi bîr bînin.
Cûdahîkirin
Cûdahî operasiyona dîtina dergûşa fonksiyonekê ye.
Berhem ji bo çi tê bikaranîn? Berhevoka fonksiyonê rêjeya guherîna fonksiyonê diyar dike û rêça wê ji me re vedibêje. Heger di xaleke diyarkirî de derîvan erênî be, wê demê fonksiyon zêde dibe, wekî din, fonksiyon kêm dibe. Û her ku nirxa dervayê mutlaq mezintir bibe, rêjeya guherîna nirxên fonksiyonê jî ew qas bilindtir dibe, û her weha xêzbûna grafika fonksiyonê ew qas zêde dibe.
Mînakî, di bin şert û mercên pergala hevrêzî ya Kartezî de, nirxa hilberê li xala M(0,0) wekhev e. + 25 tê wê wateyê ku di xalek diyar de, dema ku nirx tê guheztin li aliyê rastê ji aliyê yekîneyeke konvansiyonel, nirx bi 25 yekîneyên konvansiyonel zêde dibe. Li ser grafîkê ew mîna bilindbûnek berbiçav a nirxan xuya dike ji xaleke diyarkirî.
Mînakek din. Nirxa hilanînê wekhev e -0,1 tê wê wateyê ku dema jicîhûwarkirin per yek yekîneya adetî, nirx bi tenê 0,1 yekîneya kevneşopî kêm dibe. Di heman demê de, li ser grafiya fonksiyonê, em dikarin xêzek berjêr ya ku bi zorê xuya dibe temaşe bikin. Bi çiyayekî re hevwateyekê xêzkirin, wisa dixuye ku em pir hêdî hêdî ji çiyayekî dadikevin xwarê, berevajî mînaka berê, ku diviyabû em hilkişin lûtkeyên pir asê :)
Bi vî awayî, piştî cudakirina fonksiyonê bi astengiyan и , em hevkêşeyên cudahiya qismî yên rêza 1 diyar dikin. Piştî diyarkirina hevkêşan, em ê pergalek du hevkêşan werbigirin, bi çareserkirina wan re em ê karibin van nirxên hevkêşan hilbijêrin. и , ya ku di xalên diyarkirî de nirxên derûvên têkildar bi rêjeyek pir, pir piçûk diguhezin, û di rewşek çareseriyek analîtîk de qet nayê guhertin. Bi gotinek din, fonksiyona xeletiyê di hevrêzên ku hatine dîtin de dê bigihîje hindiktirîn, ji ber ku nirxa derhênerên qismî li van xalan dê bi sifirê re bibe.
Ji ber vê yekê, li gorî rêgezên cudahiyê, hevkêşeya derhêner a qismî ya rêza 1-ê li gorî hevberê dê formê bigire:
Rêza 1'emîn hevkêşana dervayî ya qismî ya bi rêz dê formê bigire:
Wekî encamek, me pergalek hevkêşan wergirt ku xwedan çareseriyek analîtîk pir hêsan e:
destpêk{hevkêşî*}
dest pê kirin
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
dawî{hal}
dawiya{hevkêşe*}
Berî ku hevkêşeyê çareser bikin, em berê bar bikin, kontrol bikin ka barkirin rast e, û daneyan format bikin.
Daneyên barkirin û formatkirin
Pêdivî ye ku were zanîn ku ji ber vê rastiyê ku ji bo çareseriya analîtîk, û dûv re jî ji bo daketina gradient a gradient û stokastîk, em ê kodê di du guhertoyan de bikar bînin: karanîna pirtûkxaneyê numpy û bêyî ku wê bikar bînin, wê hingê em ê hewceyê formata daneya guncan bin (kodê bibînin).
Daneyên barkirin û koda pêvajoyê
# импортируем все нужные нам библиотеки
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 '********************************************'
Dîtin
Naha, piştî ku me, yekem, daneyan bar kir, ya duyemîn jî, rastbûna barkirinê kontrol kir û di dawiyê de daneyan format kir, em ê dîmena yekem pêk bînin. Rêbaza ku pir caran ji bo vê tê bikar anîn ev e pairplot pirtûkxane deryayê. Di mînaka me de, ji ber hejmarên bisînor, ti wateya karanîna pirtûkxaneyê tune deryayê. Em ê pirtûkxaneya birêkûpêk bikar bînin matplotlib û tenê li scatterplot binêre.
Koda 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()
Nexşeya Hejmar 1 "Girêdana dahatê bi meha salê re"
Çareseriya analîtîk
Ka em di nav de amûrên herî gelemperî bikar bînin python û pergala hevkêşan çareser bikin:
destpêk{hevkêşî*}
dest pê kirin
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
dawî{hal}
dawiya{hevkêşe*}
Li gorî qaîdeya Cramer em ê diyarkera giştî û hem jî diyarkeran ji aliyê ve bibînin û ji hêla , piştî ku, dabeşkirina diyarker bi ji bo diyarkera giştî - hevberê bibînin , bi heman awayî em hevberê jî dibînin .
Koda çareseriya analîtîk
# определим функцию для расчета коэффициентов 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)
Ya ku me girt ev e:
Ji ber vê yekê, nirxên hevberan hatine dîtin, berhevoka veguheztina çargoşe hate saz kirin. Werin em li gorî hevberên hatine dîtin xêzek rast li ser histograma belavbûyî xêz bikin.
Koda xeta regresyonê
# определим функцию для формирования массива рассчетных значений выручки
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()
Tabloya Hejmar 2 "Bersivên rast û hesabkirî"
Hûn dikarin ji bo her mehê li grafika devjêberdanê binêrin. Di doza me de, em ê ti nirxek pratîkî ya girîng jê dernexin, lê em ê meraqa xwe têr bikin ka hevkêşeya regresyona xêzikî ya hêsan çiqasî girêdayîbûna dahatê ya bi meha salê diyar dike.
Koda nexşeya devjêberdanê
# определим функцию для формирования массива отклонений в процентах
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()
Nexşeya jimare 3 "Deviations, %"
Ne bêkêmasî, lê me karê xwe temam kir.
Ka em fonksiyonek binivîsin ku, ji bo diyarkirina hevberan и pirtûkxaneyê bi kar tîne numpy, bi rastî, em ê du fonksiyonan binivîsin: yek bi karanîna matrixek pseudoinverse (di pratîkê de nayê pêşniyar kirin, ji ber ku pêvajo ji hêla hesabkirinê ve tevlihev û bêîstiqrar e), ya din bi karanîna hevokek matrixê.
Koda Çareseriya Analîtîk (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
Werin em wextê ku ji bo diyarkirina hevberan derbas bûye bidin ber hev и , li gorî 3 rêbazên pêşkêşkirî.
Koda ji bo hesabkirina dema hesabkirinê
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)
Digel hejmarek piçûk a daneyê, fonksiyonek "xwe-nivîsandî" derdikeve pêş, ku bi karanîna rêbaza Cramer jimareyan dibîne.
Naha hûn dikarin li rêyên din biçin da ku hevseran bibînin и .
Gradient Descent
Pêşîn, em rave bikin ka gradient çi ye. Bi hêsanî, gradient perçeyek e ku rêgeza mezinbûna herî zêde ya fonksiyonê destnîşan dike. Li gora hilkişîna çiyayekî, cihê ku berjêr ber bi serê çiyê ve hilkişiyaya herî asê ye. Pêşxistina mînaka bi çiyê, em ji bîr dikin ku di rastiyê de ji bo ku em bi zûtirîn dem bigihîjin nizmê, ango hindiktirîn - cîhê ku fonksiyon lê zêde nebe an kêm bibe, pêdivî bi daketina herî zirav heye. Di vê nuqteyê de deran dê bibe sifir. Ji ber vê yekê, em hewce ne bi gradient, lê antîgradient. Ji bo dîtina antîgradientê, hûn tenê hewce ne ku gradientê bi zêde bikin -1 (kêm yek).
Ka em bala xwe bidin vê yekê ku fonksiyonek dikare çend hindiktirîn hebe, û ku em bi algorîtmaya ku li jêr tê pêşniyar kirin dakevin yek ji wan, em ê nikaribin kêmtirînek din bibînin, ku dibe ku ji ya hatî dîtin kêmtir be. Em rehet bin, ev ji bo me ne tehdîd e! Di rewşa me de, ji ber ku fonksiyona me, em bi kêmtirînek yekane re mijûl dibin li ser grafîkê parabola birêkûpêk e. Û wek ku divê em hemî ji qursa matematîkê ya dibistana xwe pir baş zanibin, parabola tenê kêmanîyek heye.
Piştî ku me fêhm kir ku çima hewcedariya me bi gradient heye, û her weha ku gradient perçeyek e, ango vektorek bi koordînatên diyarkirî, ku bi rastî heman hevkêş in. и em dikarin daketina gradient pêk bînin.
Berî ku dest pê bikim, ez pêşniyar dikim ku tenê çend hevokan li ser algorîtmaya daketinê bixwînin:
- Em bi rengekî pseudo-random koordînatên hevberan diyar dikin и . Di mînaka xwe de, em ê hevberên nêzî sifirê diyar bikin. Ev pratîkek hevpar e, lê dibe ku her rewşek pratîkek xwe hebe.
- Ji koordînat di xalê de nirxa derbirîka qismî ya rêza 1'emîn jê bikin . Ji ber vê yekê, heke dereng erênî be, wê hingê fonksiyon zêde dibe. Ji ber vê yekê, bi daxistina nirxa dakêşanê, em ê berevajiyê mezinbûnê, ango di riya daketinê de bimeşin. Heger rengdêr neyînî be, wê gavê fonksiyona vê xalê kêm dibe û bi jêkirina nirxa daçekê em ber bi daketinê ve diçin.
- Em bi heman koordîneyê operasyonê li dar dixin : di xalê de nirxa dergûşa qismî jêke .
- Ji bo ku nekevin ser hindiktirîn û nefirin nav cîhê kûr, pêdivî ye ku pîvana gavê di riya daketinê de were danîn. Bi gelemperî, hûn dikarin gotarek tevde binivîsin ka meriv çawa gav bi rêkûpêk saz dike û meriv wê çawa di dema pêvajoya daketinê de biguhezîne da ku lêçûnên hesabkirinê kêm bike. Lê naha li pêşiya me peywirek hinekî cûda heye, û em ê mezinahiya gavê bi karanîna rêbaza zanistî ya "poke" an, wekî ku bi zimanê hevpar dibêjin, bi ezmûnî saz bikin.
- Carekê em ji koordînatên dayî ne и Nirxên deran ji hev derdixin, em koordînatên nû digirin и . Em gavê paşîn (derxistin), jixwe ji koordînatên hesabkirî digirin. Û bi vî awayî çerx dîsa û dîsa dest pê dike, heta ku lihevhatina pêwîst pêk tê.
Gişt! Naha em amade ne ku biçin lêgerîna kûrtirîn keviya Xendek Mariana. Werin em dest pê bikin.
Koda ji bo daketina gradient
# напишем функцию градиентного спуска без использования библиотеки 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
Me ber bi binê Xendeka Mariana ve daqurtand û li wir me hemî heman nirxên hevberê dît и , ku tam ya ku dihat hêvî kirin e.
Werin em bivegerin din, tenê vê carê, wesayîta meya deryaya kûr dê bi teknolojiyên din, ango pirtûkxaneyek, tije bibe. numpy.
Koda ji bo daketina gradient (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
Nirxên hevseng и neguherbar.
Ka em binerin ka xeletî di dema daketina gradientê de çawa guherî, ango bi her gavê re çendeya qutiyên çargoşe çawa diguhere.
Koda ji bo xêzkirina berhevokên qutkirina çargoşeyan
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()
Grafîk No.
Li ser grafîkê em dibînin ku bi her gavê re xeletî kêm dibe, û piştî çend hejmarek dubareyan em xêzek hema hema horizontal temaşe dikin.
Di dawiyê de, em cûdahiya di dema darvekirina kodê de texmîn bikin:
Koda ji bo destnîşankirina dema hesabkirina daketina gradient
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)
Dibe ku em tiştek xelet dikin, lê dîsa ew fonksiyonek "mal-nivîsandî" ya hêsan e ku pirtûkxaneyê bikar nayîne. numpy ji dema hesabkirina fonksiyonek ku pirtûkxaneyê bikar tîne bêtir dike numpy.
Lê em ne sekinîne, lê em ber bi lêkolîna rêgezek din a balkêş ve diçin da ku hevkêşeya regresyona xêzikî ya hêsan çareser bikin. Bi me re hevdîtin bikin!
Daketina gradient Stochastic
Ji bo ku meriv zû prensîba xebitandina daketina gradientê ya stochastîk zû fam bike, çêtir e ku meriv cûdahiyên wê ji daketina gradientê ya asayî diyar bike. Em, di rewşa daketina gradientê de, di hevkêşeyên jêderên yên и berhevokên nirxên hemî taybetmendiyan û bersivên rastîn ên ku di nimûneyê de hene bikar anîn (ango, berhevokên hemî и ). Di daketina gradientê ya stochastîk de, em ê hemî nirxên ku di nimûneyê de hene bikar neynin, lê li şûna wê, bi pseudo-random bi navê index nimûne hilbijêrin û nirxên wê bikar bînin.
Mînakî, heke index wekî jimareya 3 (sê) were destnîşankirin, wê hingê em nirxan digirin и , wê hingê em nirxan dixin şûna hevokên derbirînê û hevrêzên nû diyar dikin. Dûv re, piştî ku koordînat diyar kirin, em dîsa bi pseudo-random indeksa nimûneyê destnîşan dikin, nirxên ku bi pêvekê re têkildar in di hevokên cudahiya qismî de diguhezînin û hevrêzan bi rengek nû diyar dikin. и etc. heta ku lihevhatin kesk bibe. Di nihêrîna pêşîn de, dibe ku wusa xuya neke ku ev çu carî dikare bixebite, lê ew dike. Rast e hêjayî gotinê ye ku bi her gavê re xeletî kêm nabe, lê bêguman meylek heye.
Feydeyên daketina gradienta stokastîk li ser ya kevneşopî çi ne? Ger mezinahiya nimûneya me pir mezin be û bi deh hezaran nirxan were pîvandin, wê hingê ew pir hêsantir e ku meriv, bêje, hezarek ji wan, ji tevahî nimûneyê, pêvajoyek hêsantir e. Li vir daketina gradientê ya stochastîk tê lîstin. Di rewşa me de, bê guman, em ê pir cûdahiyek nebînin.
Ka em li kodê binêrin.
Koda ji bo daketina gradient stochastic
# определим функцию стох.град.шага
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])
Em bi baldarî li hevberan dinêrin û pirsa "Ev çawa dibe?" Me nirxên hevsengên din wergirtin и . Dibe ku daketina gradientê ya stokastîk ji bo hevkêşeyê parametreyên çêtirîn dîtibe? Mixabin na. Tenê bes e ku meriv li berhevoka qutiyên çargoşe binêre û bibîne ku bi nirxên nû yên hevberan re xeletî mezintir e. Em ji bo bêhêvîbûnê lez nakin. Werin em grafiyek guherîna xeletiyê ava bikin.
Koda ji bo xêzkirina berhevoka veguheztina çargoşe di daketina gradienta stokastîk de
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()
Grafîk jimare 5 "Serhevdehatina çargoşeyan di dema daketina gradientê ya stokastîk de"
Li bernameyê dinêrin, her tişt di cîhê xwe de dikeve û naha em ê her tiştî rast bikin.
Îcar çi qewimî? Ya jêrîn qewimî. Dema ku em mehek bi rengek bêhemdî hilbijêrin, wê hingê ew ji bo meha hilbijartî ye ku algorîtmaya me hewl dide ku xeletiya di hesabkirina dahatê de kêm bike. Dûv re em mehek din hilbijêrin û hesabê dubare bikin, lê em xeletiya meha duyemîn a hilbijartî kêm dikin. Naha ji bîr mekin ku du mehên pêşîn bi girîngî ji rêza hevkêşeya regresyona xêzikî ya hêsan dûr dikevin. Ev tê vê wateyê ku gava yek ji van her du mehan were hilbijartin, bi kêmkirina xeletiya her yekê ji wan, algorîtmaya me xeletiya tevahî nimûneyê bi giranî zêde dike. Îcar çi bikin? Bersiv hêsan e: hûn hewce ne ku gavê daketinê kêm bikin. Beriya her tiştî, bi kêmkirina gavê daketinê, xeletî dê "hilweşîn" jor û jêr jî rawestîne. Ya rast, xeletiya "bazirînê" dê nesekine, lê ew ê wusa zû neke :) Ka em kontrol bikin.
Koda ku SGD bi zêdebûnên piçûktir dimeşîne
# запустим функцию, уменьшив шаг в 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()
Grafîk jimare 6 “Serhevdehatina çargoşeyan di dema daketina gradientê ya stokastîk de (80 hezar gav)”
Rêjeyên çêtir bûne, lê dîsa jî ne îdeal in. Bi hîpotetîk, ev dikare bi vî rengî were rast kirin. Ji bo nimûne, em di 1000 dubareyên paşîn de nirxên hevberên ku bi wan xeletiya herî kêm hatî çêkirin hilbijêrin. Rast e, ji bo vê yekê em ê jî neçar in ku nirxên hevberan bixwe jî binivîsin. Em ê vê yekê nekin, lê bêtir bala xwe bidin bernameyê. Ew xweş xuya dike û xeletî bi rengek wekhev kêm dibe. Bi rastî ev ne rast e. Ka em li 1000 dubareyên pêşîn binêrin û wan bi yên paşîn re bidin ber hev.
Koda ji bo nexşeya SGD (1000 gavên pêşîn)
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()
Grafîk No.
Grafîk No. 8 "Serhevdehatina çargoşeyan SGD (1000 gavên paşîn)"
Di destpêka daketinê de, em kêmbûnek berbiçav û hişk a xeletiyê dibînin. Di dubarekirinên paşîn de, em dibînin ku xeletî li dora nirxa 1,475-ê û li dora nirxê XNUMX-ê digere û di hin kêliyan de jî digihîje vê nirxa çêtirîn, lê paşê ew dîsa jî bilind dibe... Ez dubare dikim, hûn dikarin nirxên nirxê binivîsin. hevkêşan и , û dûv re yên ku xeletiya wan hindik e hilbijêrin. Lêbelê, me pirsgirêkek cidîtir hebû: me neçar ma ku 80 hezar gav bavêjin (kodê binihêrin) da ku nirxan nêzî çêtirîn bibin. Û ev jixwe nakokiya ramana hilanîna dema hesabkirinê bi daketina gradientê ya stokastîk re li gorî daketina gradientê berovajî dike. Çi dikare were rastkirin û çêtir kirin? Ne zehmet e ku meriv têbigihîje ku di dubareyên yekem de em bi xwebawer daketin jêr û ji ber vê yekê, divê em di dubareyên yekem de gavek mezin bihêlin û gava ku em pêşve diçin gavê kêm bikin. Em ê di vê gotarê de vê yekê nekin - ew jixwe pir dirêj e. Yên ku dixwazin dikarin bi xwe bifikirin ka meriv çawa vê yekê bike, ne dijwar e :)
Naha em bi karanîna pirtûkxaneyê dakêşana gradientê ya stokastîk pêk bînin numpy (û bila em li kevirên ku me berê nas kirine nekevin)
Koda ji bo Daketina Gradient Stochastic (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
Nirxên ku bêyî karanîna daketinê hema hema yek in numpy. Lêbelê, ev mentiqî ye.
Ka em fêr bibin ka daketinên gradientê yên stokastîk çiqas dirêj me girt.
Koda ji bo destnîşankirina dema hesabkirina SGD (80 hezar gav)
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)
Her ku diçe nav daristanê, ewr tarîtir dibin: dîsa, formula "xwe-nivîsandî" encama çêtirîn nîşan dide. Hemî ev pêşniyar dike ku pêdivî ye ku rêyên hê bêtir nazik ji bo karanîna pirtûkxaneyê hebin numpy, ku bi rastî operasyonên hesabkirinê lez dikin. Di vê gotarê de em ê li ser wan fêr nebin. Dê di dema weya vala de tiştek hebe ku hûn li ser bifikirin :)
Em kurt bikin
Berî ku ez kurt bikim, ez dixwazim bersiva pirsek ku bi îhtîmaleke mezin ji xwendevanê me yê hêja derketiye bidim. Çima, bi rastî, bi daketinê re bi vî rengî "îşkence", çima hewce ye ku em li çiya (bi piranî dakeve) bimeşin da ku em deşta xezînekirî bibînin, heke di destên me de amûrek wusa bi hêz û hêsan heye, di forma çareseriyek analîtîk, ku tavilê me li cîhê Rast teleport dike?
Bersiva vê pirsê li ser rûyê erdê ye. Naha me li mînakek pir hêsan nihêrî, ku tê de bersiva rast e bi yek nîşanekê ve girêdayî ye . Hûn di jiyanê de pir caran vê yekê nabînin, ji ber vê yekê em bifikirin ku me 2, 30, 50 an jî bêtir nîşan hene. Ka em ji bo her taybetmendiyê bi hezaran, an jî bi deh hezaran nirxan li vê zêde bikin. Di vê rewşê de, çareseriya analîtîk dibe ku ceribandinê li ber xwe nede û têk neçe. Di encamê de, daketina gradient û guheztinên wê dê hêdî-hêdî lê bê guman me nêzikî armancê bike - hindiktirîn fonksiyonê. Û ji leza xwe xeman nebin - em ê belkî li awayên ku dê rê bidin me ku dirêjahiya gavê (ango, bilez) destnîşan û rêkûpêk bikin, binihêrin.
Û niha kurteya kurteya rastîn.
Ya yekem, ez hêvî dikim ku materyalê ku di gotarê de hatî pêşkêş kirin dê ji destpêka "zanistên daneyê" re bibe alîkar ku meriv çawa çawa hevkêşeyên regresyonê yên hêsan (û ne tenê) çareser bike.
Ya duyemîn, me li çend awayên çareserkirina hevkêşeyê nihêrî. Naha, li gorî rewşê, em dikarin ya ku ji bo çareserkirina pirsgirêkê çêtirîn e hilbijêrin.
Ya sêyemîn, me hêza mîhengên pêvek, ango dirêjahiya gavê daketina gradient dît. Ev parametre nayê paşguh kirin. Wekî ku li jor hate destnîşan kirin, ji bo kêmkirina lêçûna hesaban, divê dirêjahiya gavê di dema daketinê de were guheztin.
Ya çaremîn, di rewşa me de, fonksiyonên "mal-nivîsandî" ji bo hesaban encamên demê çêtirîn nîşan didin. Dibe ku ev ji ber ne karanîna herî profesyonel a kapasîteyên pirtûkxaneyê ye numpy. Lê wekî ku dibe bila bibe, encama jêrîn xwe pêşniyar dike. Ji aliyekî ve, carinan hêja ye ku ramanên damezrandî bipirsin, û ji hêla din ve, ne hêja ye ku her tiştî tevlihev bikin - berevajî vê yekê, carinan rêyek hêsan a çareserkirina pirsgirêkê bi bandortir e. Û ji ber ku mebesta me analîzkirina sê nêzîkatiyên ji bo çareserkirina hevkêşeyek regresyonê ya hêsan bû, karanîna fonksiyonên "xwe-nivîsandî" ji me re têr bû.
Edebiyat (an tiştekî wisa)
1. Regresyona xêzikî
2. Rêbaza herî kêm çargoşe
3. Bergir
4. Gradient
5. Daketina gradient
6. Pirtûkxaneya NumPy