Պարզ գծային ռեգրեսիայի հավասարման լուծում

Հոդվածում քննարկվում են պարզ (զույգված) ռեգրեսիոն գծի մաթեմատիկական հավասարումը որոշելու մի քանի եղանակ:

Այստեղ քննարկված հավասարման լուծման բոլոր մեթոդները հիմնված են նվազագույն քառակուսիների մեթոդի վրա: Մեթոդները նշենք հետևյալ կերպ.

  • Վերլուծական լուծում
  • Գրադիենտ ծագում
  • Ստոխաստիկ գրադիենտ վայրէջք

Ուղիղ գծի հավասարման լուծման յուրաքանչյուր մեթոդի համար հոդվածը տրամադրում է տարբեր գործառույթներ, որոնք հիմնականում բաժանվում են նրանց, որոնք գրված են առանց գրադարանից օգտվելու: NumPy- ն և նրանք, որոնք օգտագործում են հաշվարկների համար NumPy- ն. Ենթադրվում է, որ հմուտ օգտագործումը NumPy- ն կնվազեցնի հաշվողական ծախսերը:

Հոդվածում տրված բոլոր ծածկագրերը գրված են լեզվով python 2.7 օգտագործելով Jupyter Notebook. Աղբյուրի կոդը և ֆայլը ընտրանքային տվյալների հետ տեղադրված են Github

Հոդվածն ավելի շատ ուղղված է ինչպես սկսնակներին, այնպես էլ նրանց, ովքեր արդեն աստիճանաբար սկսել են տիրապետել արհեստական ​​ինտելեկտի մի շատ լայն բաժնի՝ մեքենայական ուսուցման ուսումնասիրությանը։

Նյութը պատկերացնելու համար մենք օգտագործում ենք շատ պարզ օրինակ.

Օրինակ պայմաններ

Մենք ունենք հինգ արժեք, որոնք բնութագրում են կախվածությունը Y - ից X (Աղյուսակ թիվ 1):

Աղյուսակ թիվ 1 «Օրինակ պայմաններ»

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Մենք կենթադրենք, որ արժեքները Պարզ գծային ռեգրեսիայի հավասարման լուծում տարվա ամիսն է, և Պարզ գծային ռեգրեսիայի հավասարման լուծում - եկամուտ այս ամիս: Այլ կերպ ասած, եկամուտը կախված է տարվա ամսից, և Պարզ գծային ռեգրեսիայի հավասարման լուծում - միակ նշանը, որից կախված է եկամուտը:

Օրինակն այդպես է, և՛ տարվա ամսից եկամտի պայմանական կախվածության տեսանկյունից, և՛ արժեքների քանակի տեսանկյունից՝ դրանք շատ քիչ են: Սակայն նման պարզեցումը հնարավորություն կտա, ինչպես ասում են, ոչ միշտ հեշտությամբ բացատրել այն նյութը, որը յուրացնում են սկսնակները։ Եվ նաև թվերի պարզությունը թույլ կտա նրանց, ովքեր ցանկանում են օրինակը լուծել թղթի վրա՝ առանց զգալի աշխատանքային ծախսերի։

Ենթադրենք, որ օրինակում տրված կախվածությունը կարող է բավականին լավ մոտավորվել ձևի պարզ (զույգացված) ռեգրեսիոն գծի մաթեմատիկական հավասարմամբ.

Պարզ գծային ռեգրեսիայի հավասարման լուծում

որտեղ Պարզ գծային ռեգրեսիայի հավասարման լուծում այն ամիսն է, երբ ստացվել է եկամուտը, Պարզ գծային ռեգրեսիայի հավասարման լուծում - ամսվան համապատասխան եկամուտ, Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում գնահատված գծի ռեգրեսիայի գործակիցներն են:

Նշենք, որ գործակիցը Պարզ գծային ռեգրեսիայի հավասարման լուծում հաճախ կոչվում է գնահատված գծի թեքություն կամ գրադիենտ. ներկայացնում է այն գումարը, որով Պարզ գծային ռեգրեսիայի հավասարման լուծում երբ այն փոխվում է Պարզ գծային ռեգրեսիայի հավասարման լուծում.

Ակնհայտ է, որ օրինակում մեր խնդիրն է ընտրել նման գործակիցներ հավասարման մեջ Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում, որի դեպքում մեր հաշվարկված եկամտի արժեքների շեղումները ըստ ամիսների իրական պատասխաններից, այսինքն. Նմուշում ներկայացված արժեքները նվազագույն կլինեն:

Նվազագույն քառակուսի մեթոդ

Նվազագույն քառակուսիների մեթոդի համաձայն, շեղումը պետք է հաշվարկվի քառակուսու միջոցով: Այս տեխնիկան թույլ է տալիս խուսափել շեղումների փոխադարձ չեղարկումից, եթե դրանք ունեն հակառակ նշաններ: Օրինակ, եթե մի դեպքում, շեղումը +5 (գումարած հինգ), իսկ մյուսում -5 (մինուս հինգ), ապա շեղումների գումարը կչեղարկի միմյանց և կկազմի 0 (զրո): Կարելի է ոչ թե շեղումը քառակուսի դնել, այլ օգտագործել մոդուլի հատկությունը և այդ ժամանակ բոլոր շեղումները դրական կլինեն և կկուտակվեն։ Մենք մանրամասնորեն չենք կանգնի այս կետի վրա, այլ պարզապես նշում ենք, որ հաշվարկների հարմարության համար ընդունված է շեղումը քառակուսի դնել:

Ահա թե ինչ տեսք ունի բանաձևը, որով մենք կորոշենք քառակուսի շեղումների (սխալների) նվազագույն գումարը.

Պարզ գծային ռեգրեսիայի հավասարման լուծում

որտեղ Պարզ գծային ռեգրեսիայի հավասարման լուծում ճշմարիտ պատասխանների մոտավորության ֆունկցիան է (այսինքն՝ մեր հաշվարկած եկամուտը),

Պարզ գծային ռեգրեսիայի հավասարման լուծում ճշմարիտ պատասխաններն են (նմուշում ներկայացված եկամուտը),

Պարզ գծային ռեգրեսիայի հավասարման լուծում նմուշի ինդեքսն է (ամսվա քանակը, որում որոշվում է շեղումը)

Եկեք տարբերակենք ֆունկցիան, սահմանենք մասնակի դիֆերենցիալ հավասարումները և պատրաստ լինենք անցնելու վերլուծական լուծմանը։ Բայց նախ, եկեք մի փոքր էքսկուրս անենք այն մասին, թե ինչ է տարբերակումը և հիշենք ածանցյալի երկրաչափական նշանակությունը:

Տարբերակում

Տարբերակումը ֆունկցիայի ածանցյալը գտնելու գործողությունն է։

Ինչի համար է օգտագործվում ածանցյալը: Ֆունկցիայի ածանցյալը բնութագրում է ֆունկցիայի փոփոխության արագությունը և մեզ ասում է դրա ուղղությունը։ Եթե ​​տվյալ կետում ածանցյալը դրական է, ապա ֆունկցիան մեծանում է, հակառակ դեպքում ֆունկցիան նվազում է: Եվ որքան մեծ է բացարձակ ածանցյալի արժեքը, այնքան մեծ է ֆունկցիայի արժեքների փոփոխության արագությունը, ինչպես նաև ֆունկցիայի գրաֆիկի թեքությունը։

Օրինակ, դեկարտյան կոորդինատային համակարգի պայմաններում M(0,0) կետում ածանցյալի արժեքը հավասար է. +25 նշանակում է, որ տվյալ կետում, երբ արժեքը տեղափոխվում է Պարզ գծային ռեգրեսիայի հավասարման լուծում դեպի աջ՝ պայմանական միավորով, արժեք Պարզ գծային ռեգրեսիայի հավասարման լուծում ավելանում է 25 պայմանական միավորով: Գրաֆիկի վրա կարծես արժեքների բավականին կտրուկ բարձրացում է Պարզ գծային ռեգրեսիայի հավասարման լուծում տվյալ կետից:

Մեկ այլ օրինակ. Ածանցյալ արժեքը հավասար է 0,1 - նշանակում է, որ երբ տեղահանված է Պարզ գծային ռեգրեսիայի հավասարման լուծում մեկ պայմանական միավորի համար, արժեքը Պարզ գծային ռեգրեսիայի հավասարման լուծում նվազում է ընդամենը 0,1 պայմանական միավորով: Միևնույն ժամանակ, ֆունկցիայի գրաֆիկի վրա մենք կարող ենք նկատել ներքևի թեքություն: Լեռան հետ անալոգիա անելով, ասես սարից շատ դանդաղ իջնում ​​ենք մեղմ լանջով, ի տարբերություն նախորդ օրինակի, որտեղ մենք պետք է բարձրանայինք շատ զառիթափ գագաթներ :)

Այսպիսով, ֆունկցիան տարբերակելուց հետո Պարզ գծային ռեգրեսիայի հավասարման լուծում գործակիցներով Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում, սահմանում ենք 1-ին կարգի մասնակի դիֆերենցիալ հավասարումներ։ Հավասարումները որոշելուց հետո մենք կստանանք երկու հավասարումների համակարգ, որը լուծելով մենք կկարողանանք ընտրել գործակիցների նման արժեքները. Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում, որի համար տվյալ կետերում համապատասխան ածանցյալների արժեքները փոխվում են շատ ու շատ փոքր քանակությամբ, իսկ վերլուծական լուծման դեպքում ընդհանրապես չեն փոխվում։ Այլ կերպ ասած, հայտնաբերված գործակիցների սխալի գործառույթը կհասնի նվազագույնի, քանի որ այս կետերում մասնակի ածանցյալների արժեքները հավասար կլինեն զրոյի:

Այսպիսով, ըստ տարբերակման կանոնների, 1-ին կարգի մասնակի ածանցյալ հավասարումը գործակցի նկատմամբ. Պարզ գծային ռեգրեսիայի հավասարման լուծում կընդունի ձևը՝

Պարզ գծային ռեգրեսիայի հավասարման լուծում

1-ին կարգի մասնակի ածանցյալ հավասարումը նկատմամբ Պարզ գծային ռեգրեսիայի հավասարման լուծում կընդունի ձևը՝

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Արդյունքում մենք ստացանք հավասարումների համակարգ, որն ունի բավականին պարզ վերլուծական լուծում.

սկիզբ{հավասարում*}
սկիզբ{դեպքեր}
na + bsumlimits_{i=1}^nx_i — sumlimits_{i=1}^ny_i = 0

Sumlimits_ {i = 1} ^ nx_i (a + bsumlimits_ {i = 1} ^ nx_i - sumlimits_ {i = 1} ^ ny_i) = 0
վերջ{դեպքեր}
վերջ{հավասարում*}

Հավասարումը լուծելուց առաջ եկեք նախապես բեռնենք, ստուգենք, որ բեռնումը ճիշտ է և ֆորմատավորենք տվյալները։

Տվյալների բեռնում և ձևաչափում

Հարկ է նշել, որ հաշվի առնելով այն հանգամանքը, որ վերլուծական լուծման համար, և հետագայում գրադիենտ և ստոխաստիկ գրադիենտ իջնելու համար, մենք կօգտագործենք կոդը երկու տարբերակով՝ օգտագործելով գրադարանը. NumPy- ն Եվ առանց դրա օգտագործելու, ապա մեզ անհրաժեշտ կլինեն համապատասխան տվյալների ձեւավորում (տես կոդ):

Տվյալների բեռնման և մշակման կոդ

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

Visualization

Այժմ, այն բանից հետո, երբ մենք, նախ, բեռնել ենք տվյալները, երկրորդը, ստուգել ենք բեռնման ճիշտությունը և վերջապես ձևաչափել տվյալները, մենք կիրականացնենք առաջին վիզուալիզացիան: Դրա համար հաճախ օգտագործվող մեթոդն է զույգ հողամաս գրադարաններ Ծովային. Մեր օրինակում սահմանափակ թվերի պատճառով գրադարանից օգտվելն իմաստ չունի Ծովային. Մենք կօգտվենք սովորական գրադարանից Մատպլոտլիբ և պարզապես նայեք ցրված սյուժեին:

Scatterplot կոդը

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

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

«Եկամուտների կախվածությունը տարվա ամսից» գծապատկեր թիվ 1.

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Վերլուծական լուծում

Եկեք օգտագործենք ամենատարածված գործիքները Python և լուծել հավասարումների համակարգը.

սկիզբ{հավասարում*}
սկիզբ{դեպքեր}
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
վերջ{դեպքեր}
վերջ{հավասարում*}

Քրամերի կանոնի համաձայն մենք կգտնենք ընդհանուր որոշիչը, ինչպես նաև որոշիչները ըստ Պարզ գծային ռեգրեսիայի հավասարման լուծում իսկ Պարզ գծային ռեգրեսիայի հավասարման լուծում, որից հետո որոշիչը բաժանելով Պարզ գծային ռեգրեսիայի հավասարման լուծում ընդհանուր որոշիչին - գտե՛ք գործակիցը Պարզ գծային ռեգրեսիայի հավասարման լուծում, նմանապես գտնում ենք գործակիցը Պարզ գծային ռեգրեսիայի հավասարման լուծում.

Լուծման վերլուծական ծածկագիր

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

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

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

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

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

Ահա թե ինչ ենք ստացել.

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Այսպիսով, գտնվել են գործակիցների արժեքները, սահմանվել է քառակուսի շեղումների գումարը: Գտած գործակիցներին համապատասխան ուղիղ գիծ գծենք ցրման հիստոգրամի վրա։

Ռեգրեսիայի գծի կոդը

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

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

Գծապատկեր թիվ 2 «Ճիշտ և հաշվարկված պատասխաններ».

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Դուք կարող եք դիտել շեղումների գրաֆիկը յուրաքանչյուր ամսվա համար: Մեր դեպքում մենք դրանից որևէ նշանակալի գործնական արժեք չենք բխի, բայց կբավարարենք մեր հետաքրքրությունը, թե որքանով է պարզ գծային ռեգրեսիոն հավասարումը բնութագրում եկամտի կախվածությունը տարվա ամսից:

Շեղման գծապատկերի կոդը

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

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

Գծապատկեր թիվ 3 «Շեղումներ, %»

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Կատարյալ չէ, բայց մենք ավարտեցինք մեր խնդիրը:

Գրենք մի ֆունկցիա, որը գործակիցները որոշելու համար Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում օգտագործում է գրադարանը NumPy- նԱվելի ճիշտ՝ մենք կգրենք երկու ֆունկցիա՝ մեկը՝ օգտագործելով կեղծ հակադարձ մատրիցա (գործնականում խորհուրդ չի տրվում, քանի որ պրոցեսը հաշվողականորեն բարդ է և անկայուն), մյուսը՝ օգտագործելով մատրիցային հավասարում։

Լուծման վերլուծական ծածկագիր (NumPy)

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

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

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

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

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

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

Եկեք համեմատենք գործակիցների որոշման վրա ծախսված ժամանակը Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում, ներկայացված 3 մեթոդներին համապատասխան։

Կոդ՝ հաշվարկման ժամանակի հաշվարկման համար

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

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Փոքր քանակությամբ տվյալների դեպքում առաջ է գալիս «ինքնագրված» ֆունկցիա, որը գտնում է գործակիցները՝ օգտագործելով Քրամերի մեթոդը։

Այժմ կարող եք անցնել գործակիցներ գտնելու այլ եղանակների Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում.

Գրադիենտ ծագում

Նախ, եկեք սահմանենք, թե ինչ է գրադիենտը: Պարզ ասած՝ գրադիենտը մի հատված է, որը ցույց է տալիս ֆունկցիայի առավելագույն աճի ուղղությունը։ Լեռ բարձրանալու անալոգիայով, որտեղ գրադիենտը նայում է այն վայրին, որտեղ գտնվում է լեռան գագաթին ամենից զառիթափ բարձրանալը: Զարգացնելով օրինակը լեռան հետ, մենք հիշում ենք, որ իրականում մեզ անհրաժեշտ է ամենադաժան վայրէջքը, որպեսզի հնարավորինս արագ հասնենք հարթավայր, այսինքն՝ նվազագույնը՝ այն վայրը, որտեղ ֆունկցիան չի ավելանում կամ նվազում։ Այս պահին ածանցյալը հավասար կլինի զրոյի: Հետեւաբար, մեզ ոչ թե գրադիենտ է պետք, այլ հակագրադիենտ։ Հակագրադիենտը գտնելու համար պարզապես անհրաժեշտ է գրադիենտը բազմապատկել -1 (մինուս մեկ):

Եկեք ուշադրություն դարձնենք այն փաստին, որ ֆունկցիան կարող է ունենալ մի քանի մինիմումներ, և ներքևում առաջարկված ալգորիթմով իջնելով դրանցից մեկի մեջ՝ մենք չենք կարողանա գտնել մեկ այլ նվազագույն, որը կարող է լինել ավելի ցածր, քան գտնվածը։ Եկեք հանգստանանք, սա մեզ համար սպառնալիք չէ: Մեր դեպքում գործ ունենք մեկ մինիմումի հետ, քանի որ մեր գործառույթը Պարզ գծային ռեգրեսիայի հավասարման լուծում գրաֆիկի վրա կանոնավոր պարաբոլա է: Եվ, ինչպես մենք բոլորս պետք է շատ լավ իմանանք մեր դպրոցի մաթեմատիկայի խաղից, պարաբոլան ունի ընդամենը մեկ նվազագույն:

Այն բանից հետո, երբ պարզեցինք, թե ինչու է մեզ անհրաժեշտ գրադիենտ, ինչպես նաև, որ գրադիենտը հատված է, այսինքն՝ տրված կոորդինատներով վեկտոր, որոնք ճիշտ նույն գործակիցներն են։ Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում մենք կարող ենք իրականացնել գրադիենտ ծագում:

Սկսելուց առաջ ես առաջարկում եմ կարդալ ընդամենը մի քանի նախադասություն ծագման ալգորիթմի մասին.

  • Մենք կեղծ պատահական եղանակով որոշում ենք գործակիցների կոորդինատները Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում. Մեր օրինակում մենք կորոշենք զրոյի մոտ գործակիցները: Սա սովորական պրակտիկա է, բայց յուրաքանչյուր դեպք կարող է ունենալ իր պրակտիկան:
  • Կոորդինատից Պարզ գծային ռեգրեսիայի հավասարման լուծում Նվազեցրեք 1-ին կարգի մասնակի աղտոտման արժեքը կետում Պարզ գծային ռեգրեսիայի հավասարման լուծում. Այսպիսով, եթե ածանցյալը դրական է, ապա ֆունկցիան մեծանում է։ Հետեւաբար, հանելով ածանցյալի արժեքը, մենք կշարժվենք աճի հակառակ ուղղությամբ, այսինքն՝ իջնելու ուղղությամբ։ Եթե ​​ածանցյալը բացասական է, ապա ֆունկցիան այս պահին նվազում է և հանելով ածանցյալի արժեքը՝ շարժվում ենք իջնելու ուղղությամբ։
  • Նմանատիպ գործողություն ենք իրականացնում կոորդինատով Պարզ գծային ռեգրեսիայի հավասարման լուծումկետում հանել մասնակի ածանցյալի արժեքը Պարզ գծային ռեգրեսիայի հավասարման լուծում.
  • Որպեսզի չցատկեք նվազագույնի վրայով և չթռչեք խորը տարածություն, անհրաժեշտ է քայլի չափը սահմանել վայրէջքի ուղղությամբ: Ընդհանուր առմամբ, դուք կարող եք գրել մի ամբողջ հոդված այն մասին, թե ինչպես ճիշտ կարգավորել քայլը և ինչպես փոխել այն վայրէջքի գործընթացում, որպեսզի նվազեցվեն հաշվողական ծախսերը: Բայց հիմա մեր առջև մի փոքր այլ խնդիր է դրված, և քայլի չափը կհաստատենք գիտական ​​մեթոդով «խոց» կամ, ինչպես ասում են սովորական լեզվով, էմպիրիկ եղանակով։
  • Մի անգամ տրված կոորդինատներից ենք Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում հանում ենք ածանցյալների արժեքները, ստանում ենք նոր կոորդինատներ Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում. Մենք վերցնում ենք հաջորդ քայլը (հանում), արդեն հաշվարկված կոորդինատներից: Եվ այսպես, ցիկլը նորից ու կրկին սկսվում է, մինչեւ անհրաժեշտ է կոնվերգենցիան ձեռք բերվի:

Բոլորը! Այժմ մենք պատրաստ ենք գնալ Մարիանյան խրամատի ամենախոր կիրճը փնտրելու։ Եկեք սկսենք.

Գրադիենտ վայրէջքի կոդը

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

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Մենք սուզվեցինք Մարիանայի խրամատի հենց ներքեւի մասում, եւ այնտեղ մենք գտանք բոլոր նույն գործակից արժեքները Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում, ինչը հենց այն է, ինչ սպասելի էր։

Եկեք ևս մեկ սուզվենք, միայն թե այս անգամ մեր խորջրյա մեքենան կլցվի այլ տեխնոլոգիաներով, այն է՝ գրադարանով։ NumPy- ն.

Գրադիենտ վայրէջքի ծածկագիր (NumPy)

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

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

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

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


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

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

Պարզ գծային ռեգրեսիայի հավասարման լուծում
Գործակիցների արժեքները Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում անփոփոխելի.

Եկեք նայենք, թե ինչպես է փոխվել սխալը գրադիենտ ծագման ժամանակ, այսինքն, թե ինչպես են փոխվել քառակուսի շեղումների գումարը յուրաքանչյուր քայլի հետ:

Քառակուսի շեղումների գումարների գծագրման կոդը

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

Գրաֆիկ թիվ 4 «Գրադիենտ վայրէջքի ժամանակ քառակուսի շեղումների գումարը»

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Գրաֆիկի վրա տեսնում ենք, որ յուրաքանչյուր քայլի հետ սխալը նվազում է, և որոշակի թվով կրկնություններից հետո մենք դիտարկում ենք գրեթե հորիզոնական գիծ։

Ի վերջո, եկեք գնահատենք կոդի կատարման ժամանակի տարբերությունը.

Կոդ՝ գրադիենտ վայրէջքի հաշվարկման ժամանակը որոշելու համար

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

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

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Միգուցե մենք ինչ-որ բան սխալ ենք անում, բայց նորից դա պարզ «տնային գրված» գործառույթ է, որը չի օգտագործում գրադարանը NumPy- ն գերազանցում է գրադարանի օգտագործմամբ ֆունկցիայի հաշվարկման ժամանակը NumPy- ն.

Բայց մենք դեռ կանգնած չենք, այլ շարժվում ենք դեպի պարզ գծային ռեգրեսիայի հավասարումը լուծելու մեկ այլ հետաքրքիր միջոց ուսումնասիրելու ուղղությամբ: Հանդիպե՛ք

Ստոխաստիկ գրադիենտ վայրէջք

Որպեսզի արագ հասկանանք ստոխաստիկ գրադիենտ ծագման գործողության սկզբունքը, ավելի լավ է որոշել դրա տարբերությունները սովորական գրադիենտ ծագումից: Մենք, գրադիենտ ծագման դեպքում, ածանցյալների հավասարումների դեպքում Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում օգտագործել է նմուշում առկա բոլոր հատկանիշների արժեքների և ճշմարիտ պատասխանների գումարները (այսինքն՝ բոլորի գումարները Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում) Ստոխաստիկ գրադիենտ ծագման դեպքում մենք չենք օգտագործի նմուշում առկա բոլոր արժեքները, այլ փոխարենը կեղծ պատահականորեն ընտրում ենք այսպես կոչված նմուշի ինդեքսը և կօգտագործենք դրա արժեքները:

Օրինակ, եթե ինդեքսը որոշվում է որպես թիվ 3 (երեք), ապա մենք վերցնում ենք արժեքները Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում, այնուհետև արժեքները փոխարինում ենք ածանցյալ հավասարումների մեջ և որոշում նոր կոորդինատներ։ Այնուհետև, որոշելով կոորդինատները, մենք նորից կեղծ պատահականորեն որոշում ենք նմուշի ինդեքսը, ինդեքսին համապատասխանող արժեքները փոխարինում ենք մասնակի դիֆերենցիալ հավասարումների մեջ և նորովի ենք որոշում կոորդինատները։ Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում և այլն: մինչև կոնվերգենցիան կանաչի: Առաջին հայացքից կարող է թվալ, որ սա ընդհանրապես չի կարող աշխատել, բայց դա անում է: Ճիշտ է, հարկ է նշել, որ ամեն քայլափոխի սխալը չի ​​նվազում, բայց անշուշտ միտում կա.

Որո՞նք են ստոխաստիկ գրադիենտ անկման առավելությունները սովորականի նկատմամբ: Եթե ​​մեր ընտրանքի չափը շատ մեծ է և չափվում է տասնյակ հազարավոր արժեքներով, ապա շատ ավելի հեշտ է մշակել, ասենք, դրանցից պատահական հազարը, այլ ոչ թե ամբողջ նմուշը: Սա այն վայրն է, որտեղ ստոխաստիկ գրադիենտ ծագումը խաղում է: Մեր դեպքում, իհարկե, մեծ տարբերություն չենք նկատի։

Եկեք նայենք կոդը.

Կոդ ստոխաստիկ գրադիենտ իջնելու համար

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


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


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

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


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

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

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Մենք ուշադիր նայում ենք գործակիցներին և բռնում ինքներս մեզ «Ինչպե՞ս կարող է լինել» հարցը: Մենք ստացանք գործակիցների այլ արժեքներ Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում. Միգուցե ստոխաստիկ գրադիենտ ծագումը գտել է ավելի օպտիմալ պարամետրեր հավասարման համար: Ցավոք, ոչ. Բավական է նայել քառակուսի շեղումների գումարին և տեսնել, որ գործակիցների նոր արժեքների դեպքում սխալն ավելի մեծ է։ Մենք չենք շտապում հուսահատվել։ Եկեք կառուցենք սխալի փոփոխության գրաֆիկը:

Քառակուսի շեղումների գումարը ստոխաստիկ գրադիենտ իջնելիս գծագրելու կոդը

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

Գրաֆիկ թիվ 5 «Շեղումների քառակուսիների գումարը ստոխաստիկ գրադիենտ վայրէջքի ժամանակ»

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Նայելով ժամանակացույցին՝ ամեն ինչ իր տեղն է ընկնում, և հիմա մենք ամեն ինչ կշտկենք։

Եւ ինչ պատահեց? Տեղի ունեցավ հետևյալը. Երբ մենք պատահականորեն ընտրում ենք ամիսը, ապա հենց ընտրված ամսվա համար է, որ մեր ալգորիթմը փորձում է նվազեցնել եկամուտների հաշվարկման սխալը: Այնուհետև մենք ընտրում ենք ևս մեկ ամիս և կրկնում ենք հաշվարկը, բայց մենք նվազեցնում ենք սխալը երկրորդ ընտրված ամսվա համար: Այժմ հիշեք, որ առաջին երկու ամիսները զգալիորեն շեղվում են պարզ գծային ռեգրեսիայի հավասարման գծից: Սա նշանակում է, որ երբ ընտրվում է այս երկու ամիսներից որևէ մեկը, նվազեցնելով դրանցից յուրաքանչյուրի սխալը, մեր ալգորիթմը լրջորեն մեծացնում է սխալը ամբողջ նմուշի համար։ Այսպիսով, ինչ անել: Պատասխանը պարզ է՝ դուք պետք է կրճատեք վայրէջքի աստիճանը: Ի վերջո, իջեցնելով աստիճանը, սխալը նույնպես կդադարի «ցատկել» վեր ու վար: Ավելի ճիշտ՝ «ցատկելու» սխալը չի ​​դադարի, բայց այդքան արագ չի անի :) Եկեք ստուգենք։

Կոդ՝ SGD-ն ավելի փոքր հավելումներով գործարկելու համար

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

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


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



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

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

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Գրաֆիկ թիվ 6 «Շեղումների քառակուսիների գումարը ստոխաստիկ գրադիենտ վայրէջքի ժամանակ (80 հազար քայլ)»

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Գործակիցները բարելավվել են, բայց դեռ իդեալական չեն։ Հիպոթետիկորեն սա կարելի է ուղղել այսպես. Մենք ընտրում ենք, օրինակ, վերջին 1000 կրկնություններում այն ​​գործակիցների արժեքները, որոնցով կատարվել է նվազագույն սխալը: Ճիշտ է, դրա համար մենք ստիպված կլինենք նաև գրել գործակիցների արժեքները: Մենք դա չենք անի, այլ ավելի շուտ ուշադրություն դարձնենք ժամանակացույցին: Այն հարթ տեսք ունի, և սխալը կարծես հավասարապես նվազում է: Իրականում դա ճիշտ չէ։ Դիտարկենք առաջին 1000 կրկնությունները և համեմատենք վերջինների հետ։

SGD գծապատկերի կոդը (առաջին 1000 քայլերը)

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

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

Գրաֆիկ թիվ 7 «SGD քառակուսի շեղումների գումարը (առաջին 1000 քայլ)»

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Գրաֆիկ թիվ 8 «SGD քառակուսի շեղումների գումարը (վերջին 1000 քայլը)»

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Իջնելու հենց սկզբում մենք նկատում ենք սխալի բավականին միատեսակ և կտրուկ նվազում։ Վերջին կրկնություններում մենք տեսնում ենք, որ սխալը պտտվում է 1,475 արժեքի շուրջ և որոշ պահերին հավասարվում է այս օպտիմալ արժեքին, բայց հետո այն դեռ բարձրանում է... Կրկնում եմ՝ կարող եք գրել արժեքների արժեքները: գործակիցները Պարզ գծային ռեգրեսիայի հավասարման լուծում и Պարզ գծային ռեգրեսիայի հավասարման լուծում, և այնուհետև ընտրեք դրանք, որոնց դեպքում սխալը նվազագույն է: Այնուամենայնիվ, մենք ունեինք ավելի լուրջ խնդիր՝ մենք պետք է կատարեինք 80 հազար քայլ (տե՛ս կոդը)՝ արժեքները օպտիմալին մոտեցնելու համար։ Եվ սա արդեն հակասում է հաշվողական ժամանակի խնայողության գաղափարին ստոխաստիկ գրադիենտ իջնելով գրադիենտ ծագման համեմատ: Ի՞նչը կարելի է շտկել և բարելավել: Դժվար չէ նկատել, որ առաջին կրկնություններում մենք վստահորեն իջնում ​​ենք իջնում ​​և, հետևաբար, պետք է մեծ քայլ թողնել առաջին կրկնումներում և քայլն առաջ գնալով նվազեցնել։ Մենք դա չենք անի այս հոդվածում, դա արդեն չափազանց երկար է: Ցանկացողները կարող են ինքնուրույն մտածել, թե ինչպես դա անել, դժվար չէ :)

Այժմ եկեք կատարենք ստոխաստիկ գրադիենտ վայրէջք՝ օգտագործելով գրադարանը NumPy- ն (և եկեք չսայթաքենք այն քարերի վրա, որոնք մենք հայտնաբերել ենք ավելի վաղ)

Ստոխաստիկ գրադիենտ ծագման կոդը (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

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Արժեքները գրեթե նույնն են, ինչ առանց օգտագործելու իջնելիս NumPy- ն. Այնուամենայնիվ, սա տրամաբանական է.

Եկեք պարզենք, թե որքան ժամանակ տևեց մեզ ստոխաստիկ գրադիենտ վայրէջքները:

SGD-ի հաշվարկման ժամանակի որոշման ծածկագիր (80 հազար քայլ)

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

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

Պարզ գծային ռեգրեսիայի հավասարման լուծում

Որքան հեռու է անտառի մեջ, այնքան ավելի մութ են ամպերը. կրկին «ինքնագրված» բանաձևը ցույց է տալիս լավագույն արդյունքը: Այս ամենը հուշում է, որ գրադարանից օգտվելու էլ ավելի նուրբ ձևեր պետք է լինեն NumPy- ն, որոնք իսկապես արագացնում են հաշվողական գործողությունները։ Այս հոդվածում մենք չենք սովորի նրանց մասին: Ձեր ազատ ժամանակ մտածելու բան կլինի :)

Մենք ամփոփում ենք

Ամփոփելուց առաջ ուզում եմ պատասխանել մի հարցի, որն ամենայն հավանականությամբ ծագել է մեր սիրելի ընթերցողից. Իրականում ինչո՞ւ է նման «տանջանքները» վայրէջքներով, ինչո՞ւ է մեզ անհրաժեշտ սարը վեր ու վար (հիմնականում իջնել) թանկագին հարթավայրը գտնելու համար, եթե մեր ձեռքում կա այդպիսի հզոր և պարզ սարք, վերլուծական լուծման ձև, որն ակնթարթորեն հեռացնում է մեզ ճիշտ վայր:

Այս հարցի պատասխանը մակերեսի վրա է: Այժմ մենք նայեցինք մի շատ պարզ օրինակի, որում ճշմարիտ պատասխանն է Պարզ գծային ռեգրեսիայի հավասարման լուծում կախված է մեկ նշանից Պարզ գծային ռեգրեսիայի հավասարման լուծում. Դուք կյանքում դա հաճախ չեք տեսնում, ուստի եկեք պատկերացնենք, որ մենք ունենք 2, 30, 50 կամ ավելի նշան: Եկեք սրան ավելացնենք հազարավոր կամ նույնիսկ տասնյակ հազարավոր արժեքներ յուրաքանչյուր հատկանիշի համար: Այս դեպքում վերլուծական լուծումը կարող է չդիմանալ փորձությանը և ձախողվել: Իր հերթին, գրադիենտ իջնելը և դրա տատանումները դանդաղ, բայց հաստատ մեզ կմոտեցնեն նպատակին` ֆունկցիայի նվազագույնին: Եվ մի անհանգստացեք արագության մասին. մենք հավանաբար կդիտարկենք ուղիներ, որոնք թույլ կտան մեզ սահմանել և կարգավորել քայլի երկարությունը (այսինքն՝ արագությունը):

Իսկ հիմա բուն համառոտ ամփոփումը։

Նախ, հուսով եմ, որ հոդվածում ներկայացված նյութը կօգնի սկսնակ «տվյալների գիտնականներին» հասկանալու, թե ինչպես լուծել պարզ (և ոչ միայն) գծային ռեգրեսիայի հավասարումները:

Երկրորդ, մենք դիտարկեցինք հավասարումը լուծելու մի քանի եղանակ: Այժմ, կախված իրավիճակից, մենք կարող ենք ընտրել այն, որը լավագույնս համապատասխանում է խնդրի լուծմանը:

Երրորդ, մենք տեսանք լրացուցիչ պարամետրերի ուժը, մասնավորապես՝ գրադիենտ վայրէջքի քայլի երկարությունը: Այս պարամետրը չի կարող անտեսվել: Ինչպես նշվեց վերևում, հաշվարկների արժեքը նվազեցնելու համար քայլի երկարությունը պետք է փոխվի վայրէջքի ժամանակ:

Չորրորդ, մեր դեպքում «տնային գրված» գործառույթները ցույց են տվել լավագույն ժամանակային արդյունքները հաշվարկների համար: Դա, հավանաբար, պայմանավորված է գրադարանի հնարավորությունների ոչ ամենապրոֆեսիոնալ կիրառմամբ NumPy- ն. Բայց այդպես էլ լինի, հետևյալ եզրակացությունն ինքնին հուշում է. Մի կողմից, երբեմն արժե կասկածի տակ դնել կայացած կարծիքները, իսկ մյուս կողմից՝ միշտ չէ, որ արժե ամեն ինչ բարդացնել, ընդհակառակը, երբեմն ավելի արդյունավետ է խնդրի լուծման ավելի պարզ ձևը։ Եվ քանի որ մեր նպատակն էր վերլուծել պարզ գծային ռեգրեսիոն հավասարման լուծման երեք մոտեցում, մեզ համար միանգամայն բավարար էր «ինքնագրված» ֆունկցիաների օգտագործումը։

Գրականություն (կամ նման բան)

1. Գծային ռեգրեսիա

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

2. Նվազագույն քառակուսիների մեթոդ

mathprofi.ru/metod_naimenshih_kvadratov.html

3. Ածանցյալ

www.mathprofi.ru/chastnye_proizvodnye_primery.html

4. Գրադիենտ

mathprofi.ru/proizvodnaja_po_napravleniju_i_gradient.html

5. Գրադիենտ վայրէջք

habr.com/en/post/471458

habr.com/en/post/307312

artemarakcheev.com//2017-12-31/ գծային_ագիր

6. NumPy գրադարան

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

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

pythonworld.ru/numpy/2.html

Source: www.habr.com

Добавить комментарий