การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

บทความนี้กล่าวถึงหลายวิธีในการกำหนดสมการทางคณิตศาสตร์ของเส้นถดถอยแบบง่าย (คู่)

วิธีการแก้สมการทั้งหมดที่กล่าวถึงในที่นี้ใช้วิธีกำลังสองน้อยที่สุด เรามาแสดงวิธีการดังต่อไปนี้:

  • โซลูชันการวิเคราะห์
  • การไล่ระดับโคตร
  • โคตรลาดสุ่ม

สำหรับการแก้สมการเส้นตรงแต่ละวิธี บทความนี้มีฟังก์ชันต่างๆ มากมาย ซึ่งส่วนใหญ่จะแบ่งออกเป็นส่วนที่เขียนโดยไม่ใช้ไลบรารี นำพาย และพวกที่ใช้ในการคำนวณ นำพาย. เชื่อกันว่าใช้ความชำนาญ นำพาย จะลดต้นทุนการประมวลผล

รหัสทั้งหมดที่ระบุในบทความเขียนด้วยภาษา หลาม 2.7 กับ โน้ตบุ๊ค Jupyter. มีการโพสต์ซอร์สโค้ดและไฟล์พร้อมข้อมูลตัวอย่าง Github

บทความนี้มุ่งเป้าไปที่ทั้งผู้เริ่มต้นและผู้ที่ค่อยๆ เริ่มเชี่ยวชาญการศึกษาในส่วนที่กว้างมากในด้านปัญญาประดิษฐ์ - การเรียนรู้ของเครื่อง

เพื่ออธิบายเนื้อหา เราใช้ตัวอย่างง่ายๆ

เงื่อนไขตัวอย่าง

เรามีค่าห้าประการที่แสดงถึงการพึ่งพาอาศัยกัน Y จาก X (ตารางที่ 1):

ตารางที่ 1 “เงื่อนไขตัวอย่าง”

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

เราจะถือว่าค่าต่างๆ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย เป็นเดือนของปีและ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย - รายได้ในเดือนนี้ กล่าวอีกนัยหนึ่ง รายได้ขึ้นอยู่กับเดือนของปี และ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย - สัญญาณเดียวที่รายได้ขึ้นอยู่กับ

ตัวอย่างนั้นค่อนข้างดีทั้งจากมุมมองของการพึ่งพารายได้แบบมีเงื่อนไขในเดือนของปีและจากมุมมองของจำนวนค่า - มีน้อยมาก อย่างไรก็ตามการลดความซับซ้อนดังกล่าวจะทำให้สามารถอธิบายเนื้อหาที่ผู้เริ่มต้นดูดซึมได้ไม่ใช่เรื่องง่ายเสมอไป และความเรียบง่ายของตัวเลขจะช่วยให้ผู้ที่ต้องการแก้ตัวอย่างบนกระดาษโดยไม่ต้องเสียค่าแรงจำนวนมาก

ให้เราสมมติว่าการพึ่งพาที่ให้ไว้ในตัวอย่างสามารถประมาณได้ค่อนข้างดีด้วยสมการทางคณิตศาสตร์ของเส้นการถดถอยอย่างง่าย (คู่) ของแบบฟอร์ม:

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

ที่ไหน การแก้สมการการถดถอยเชิงเส้นอย่างง่าย คือเดือนที่ได้รับรายได้ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย - รายได้สอดคล้องกับเดือน การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่าย คือค่าสัมประสิทธิ์การถดถอยของเส้นประมาณค่า

โปรดทราบว่าค่าสัมประสิทธิ์ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย มักเรียกว่าความชันหรือการไล่ระดับสีของเส้นประมาณ แสดงถึงจำนวนเงินที่ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย เมื่อมันเปลี่ยนไป การแก้สมการการถดถอยเชิงเส้นอย่างง่าย.

แน่นอนว่างานของเราในตัวอย่างคือการเลือกค่าสัมประสิทธิ์ดังกล่าวในสมการ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่ายซึ่งการเบี่ยงเบนของมูลค่ารายได้ที่คำนวณของเราเป็นรายเดือนจากคำตอบที่แท้จริงคือ ค่าที่แสดงในตัวอย่างจะน้อยที่สุด

วิธีกำลังสองน้อยที่สุด

ตามวิธีกำลังสองน้อยที่สุด ค่าเบี่ยงเบนควรคำนวณโดยการยกกำลังสอง เทคนิคนี้ช่วยให้คุณหลีกเลี่ยงการยกเลิกการเบี่ยงเบนร่วมกันหากมีสัญญาณตรงกันข้าม ตัวอย่างเช่นหากในกรณีหนึ่งมีการเบี่ยงเบน +5 (บวกห้า) และอีกอย่าง -5 (ลบห้า) จากนั้นผลรวมของการเบี่ยงเบนจะหักล้างกันและเป็น 0 (ศูนย์) เป็นไปไม่ได้ที่จะยกกำลังสองส่วนเบี่ยงเบน แต่ต้องใช้คุณสมบัติของโมดูลัสแล้วส่วนเบี่ยงเบนทั้งหมดจะเป็นค่าบวกและจะสะสม เราจะไม่เจาะลึกประเด็นนี้โดยละเอียด แต่เพียงระบุว่าเพื่อความสะดวกในการคำนวณ เป็นเรื่องปกติที่จะต้องยกกำลังสองส่วนเบี่ยงเบน

นี่คือลักษณะของสูตรที่เราจะพิจารณาผลรวมน้อยที่สุดของการเบี่ยงเบนกำลังสอง (ข้อผิดพลาด):

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

ที่ไหน การแก้สมการการถดถอยเชิงเส้นอย่างง่าย เป็นฟังก์ชันของการประมาณคำตอบที่แท้จริง (นั่นคือ รายได้ที่เราคำนวณ)

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย คือคำตอบที่แท้จริง (รายได้ตามตัวอย่าง)

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย คือดัชนีตัวอย่าง (จำนวนเดือนที่คำนวณค่าเบี่ยงเบน)

เรามาแยกความแตกต่างของฟังก์ชัน กำหนดสมการเชิงอนุพันธ์ย่อย และเตรียมพร้อมที่จะดำเนินการแก้ปัญหาเชิงวิเคราะห์ต่อไป แต่ก่อนอื่น เรามาอธิบายสั้นๆ ว่าความแตกต่างคืออะไร และจำความหมายทางเรขาคณิตของอนุพันธ์กันก่อน

ความแตกต่าง

ความแตกต่างคือการดำเนินการค้นหาอนุพันธ์ของฟังก์ชัน

อนุพันธ์ใช้ทำอะไร? อนุพันธ์ของฟังก์ชันจะแสดงลักษณะเฉพาะของอัตราการเปลี่ยนแปลงของฟังก์ชันและบอกทิศทางของฟังก์ชันนั้น ถ้าอนุพันธ์ ณ จุดที่กำหนดเป็นบวก ฟังก์ชันจะเพิ่มขึ้น มิฉะนั้น ฟังก์ชันจะลดลง และยิ่งค่าของอนุพันธ์สัมบูรณ์มีค่ามาก อัตราการเปลี่ยนแปลงของค่าฟังก์ชันก็จะยิ่งสูงขึ้น และความชันของกราฟฟังก์ชันก็จะยิ่งชันมากขึ้นด้วย

ตัวอย่างเช่น ภายใต้เงื่อนไขของระบบพิกัดคาร์ทีเซียน ค่าของอนุพันธ์ที่จุด M(0,0) จะเท่ากับ +25 หมายความว่า ณ จุดที่กำหนด เมื่อมีการเลื่อนค่า การแก้สมการการถดถอยเชิงเส้นอย่างง่าย ไปทางขวาตามหน่วยทั่วไป ค่า การแก้สมการการถดถอยเชิงเส้นอย่างง่าย เพิ่มขึ้น 25 หน่วยทั่วไป บนกราฟดูเหมือนว่าค่าจะเพิ่มขึ้นค่อนข้างสูงชัน การแก้สมการการถดถอยเชิงเส้นอย่างง่าย จากจุดที่กำหนด

ตัวอย่างอื่น. มูลค่าอนุพันธ์จะเท่ากัน -0,1 หมายความว่าเมื่อถูกแทนที่ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย ต่อหนึ่งหน่วยธรรมดา ค่า การแก้สมการการถดถอยเชิงเส้นอย่างง่าย ลดลงเพียง 0,1 หน่วยธรรมดา ในเวลาเดียวกัน บนกราฟของฟังก์ชัน เราสามารถสังเกตเห็นความชันลงที่แทบจะสังเกตไม่เห็นได้ เปรียบเสมือนภูเขา ราวกับว่าเรากำลังลงจากภูเขาอย่างช้าๆ ไม่เหมือนตัวอย่างที่แล้ว ซึ่งเราต้องปีนยอดเขาที่สูงชันมาก :)

ดังนั้นหลังจากแยกฟังก์ชันแล้ว การแก้สมการการถดถอยเชิงเส้นอย่างง่าย โดยอัตราต่อรอง การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่ายเรากำหนดสมการเชิงอนุพันธ์ย่อยอันดับ 1 หลังจากกำหนดสมการแล้วเราจะได้ระบบสมการสองสมการโดยแก้โจทย์เราจะสามารถเลือกค่าสัมประสิทธิ์ดังกล่าวได้ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่ายซึ่งค่าของอนุพันธ์ที่เกี่ยวข้อง ณ จุดที่กำหนดเปลี่ยนแปลงไปจำนวนน้อยมาก และในกรณีของโซลูชันเชิงวิเคราะห์จะไม่เปลี่ยนแปลงเลย กล่าวอีกนัยหนึ่งฟังก์ชันข้อผิดพลาดที่ค่าสัมประสิทธิ์ที่พบจะถึงค่าต่ำสุดเนื่องจากค่าของอนุพันธ์บางส่วนที่จุดเหล่านี้จะเท่ากับศูนย์

ดังนั้นตามกฎของการหาความแตกต่าง สมการอนุพันธ์ย่อยของลำดับที่ 1 เทียบกับสัมประสิทธิ์ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย จะอยู่ในรูปแบบ:

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

สมการอนุพันธ์ย่อยอันดับ 1 เทียบกับ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย จะอยู่ในรูปแบบ:

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

เป็นผลให้เราได้รับระบบสมการที่มีวิธีวิเคราะห์ที่ค่อนข้างง่าย:

เริ่มต้น{สมการ*}
เริ่มต้น{กรณี}
นา + bsumlimits_{i=1}^nx_i — sumlimits_{i=1}^ny_i = 0

sumlimits_{i=1}^nx_i(a +bsumlimits_{i=1}^nx_i — sumlimits_{i=1}^ny_i) = 0
สิ้นสุด{กรณี}
สิ้นสุด{สมการ*}

ก่อนที่จะแก้สมการ มาโหลดล่วงหน้า ตรวจสอบว่าการโหลดถูกต้อง และจัดรูปแบบข้อมูล

กำลังโหลดและจัดรูปแบบข้อมูล

ควรสังเกตว่าเนื่องจากข้อเท็จจริงที่ว่าสำหรับโซลูชันเชิงวิเคราะห์ และต่อมาสำหรับการไล่ระดับสีและการไล่ระดับแบบสุ่ม เราจะใช้โค้ดในสองรูปแบบ: การใช้ไลบรารี นำพาย และหากไม่มีการใช้งานเราจะต้องมีการจัดรูปแบบข้อมูลที่เหมาะสม (ดูโค้ด)

การโหลดข้อมูลและรหัสการประมวลผล

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

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

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

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

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

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

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

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

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

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

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

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

การแสดง

ตอนนี้ หลังจากที่เราโหลดข้อมูลแล้ว ประการที่สอง ตรวจสอบความถูกต้องของการโหลด และสุดท้ายจัดรูปแบบข้อมูล เราจะดำเนินการสร้างภาพข้อมูลครั้งแรก วิธีที่มักใช้สำหรับสิ่งนี้ก็คือ พล็อตคู่ ห้องสมุด ทะเล. ในตัวอย่างของเรา เนื่องจากมีจำนวนจำกัด จึงไม่มีประโยชน์ในการใช้ไลบรารี ทะเล. เราจะใช้ห้องสมุดปกติ Matplotlib และดูที่แผนภาพกระจาย

รหัสกระจาย

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 “การพึ่งพารายได้ในเดือนของปี”

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

โซลูชันการวิเคราะห์

มาใช้เครื่องมือที่พบบ่อยที่สุดใน หลาม และแก้ระบบสมการได้ดังนี้

เริ่มต้น{สมการ*}
เริ่มต้น{กรณี}
นา + 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)

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

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

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

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

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

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

ลองเปรียบเทียบเวลาที่ใช้ในการหาค่าสัมประสิทธิ์ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่ายตามวิธีที่นำเสนอทั้ง 3 วิธี

รหัสสำหรับการคำนวณเวลาในการคำนวณ

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

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

ด้วยข้อมูลจำนวนเล็กน้อย ฟังก์ชัน "เขียนเอง" จะปรากฏขึ้นข้างหน้า ซึ่งจะค้นหาค่าสัมประสิทธิ์โดยใช้วิธีของ Cramer

ตอนนี้คุณสามารถใช้วิธีอื่นในการหาค่าสัมประสิทธิ์ได้แล้ว การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่าย.

การไล่ระดับโคตร

ก่อนอื่น เรามานิยามกันก่อนว่าการไล่ระดับสีคืออะไร พูดง่ายๆ ก็คือ การไล่ระดับสีเป็นส่วนที่ระบุทิศทางการเติบโตสูงสุดของฟังก์ชัน โดยเปรียบเสมือนการปีนภูเขา โดยที่หน้าลาดเป็นจุดที่ลาดชันที่สุดถึงยอดเขา เมื่อพัฒนาตัวอย่างกับภูเขา เราจำได้ว่าในความเป็นจริงแล้ว เราต้องการทางลงที่ชันที่สุดเพื่อที่จะไปถึงที่ราบลุ่มโดยเร็วที่สุด นั่นคือ ขั้นต่ำ - สถานที่ที่ฟังก์ชันไม่เพิ่มหรือลดลง ณ จุดนี้อนุพันธ์จะเท่ากับศูนย์ ดังนั้นเราจึงไม่จำเป็นต้องมีเกรเดียนต์ แต่เป็นแอนติกราเดียนต์ ในการหาแอนติกราเดียนต์ คุณเพียงแค่ต้องคูณเกรเดียนต์ด้วย -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
def error_square_numpy(ab,x_np,y_np):
    y_pred = np.dot(x_np,ab)
    error = y_pred - y_np
    return sum((error)**2)

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

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

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


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

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

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย
ค่าสัมประสิทธิ์ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่าย ไม่สามารถเปลี่ยนแปลงได้

มาดูกันว่าข้อผิดพลาดเปลี่ยนแปลงไปอย่างไรในระหว่างการไล่ระดับสี กล่าวคือ ผลรวมของการเบี่ยงเบนกำลังสองเปลี่ยนแปลงไปอย่างไรในแต่ละขั้นตอน

รหัสสำหรับพล็อตผลรวมของการเบี่ยงเบนกำลังสอง

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

กราฟหมายเลข 4 “ผลรวมของการเบี่ยงเบนกำลังสองระหว่างการไล่ระดับลง”

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

บนกราฟเราจะเห็นว่าในแต่ละขั้นตอนข้อผิดพลาดลดลง และหลังจากการวนซ้ำหลายครั้ง เราจะสังเกตเห็นเส้นเกือบแนวนอน

สุดท้ายนี้ เรามาประมาณความแตกต่างของเวลาดำเนินการโค้ดกัน:

รหัสเพื่อกำหนดเวลาการคำนวณการไล่ระดับสี

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

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

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

บางทีเราอาจทำอะไรผิด แต่ก็เป็นฟังก์ชัน "เขียนเองที่บ้าน" แบบง่ายๆ ที่ไม่ได้ใช้ห้องสมุด นำพาย มีประสิทธิภาพเหนือกว่าเวลาในการคำนวณของฟังก์ชันโดยใช้ไลบรารี นำพาย.

แต่เราไม่ได้หยุดนิ่ง แต่กำลังมุ่งศึกษาวิธีที่น่าตื่นเต้นอีกวิธีหนึ่งในการแก้สมการการถดถอยเชิงเส้นอย่างง่าย พบปะ!

โคตรลาดสุ่ม

เพื่อให้เข้าใจหลักการทำงานของการไล่ระดับสีสุ่มอย่างรวดเร็ว ควรพิจารณาความแตกต่างจากการไล่ระดับสีแบบธรรมดาจะดีกว่า ในกรณีของการไล่ระดับสีโคตร ในสมการของอนุพันธ์ของ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่าย ใช้ผลรวมของค่าคุณสมบัติทั้งหมดและคำตอบที่แท้จริงที่มีอยู่ในตัวอย่าง (นั่นคือผลรวมของทั้งหมด การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่าย). ในการไล่ระดับสีแบบสุ่ม เราจะไม่ใช้ค่าทั้งหมดที่มีอยู่ในตัวอย่าง แต่จะสุ่มเลือกดัชนีตัวอย่างที่เรียกว่าดัชนีตัวอย่างและใช้ค่าของมันแทน

ตัวอย่างเช่น หากดัชนีถูกกำหนดให้เป็นหมายเลข 3 (สาม) เราจะรับค่านั้น การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่ายจากนั้นเราจะแทนค่าลงในสมการอนุพันธ์และกำหนดพิกัดใหม่ จากนั้นเมื่อกำหนดพิกัดแล้วเราจะกำหนดดัชนีตัวอย่างแบบสุ่มหลอกอีกครั้งแทนที่ค่าที่สอดคล้องกับดัชนีลงในสมการเชิงอนุพันธ์บางส่วนและกำหนดพิกัดในรูปแบบใหม่ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่าย ฯลฯ จนกระทั่งการบรรจบกันกลายเป็นสีเขียว เมื่อมองแวบแรกอาจดูเหมือนว่าวิธีนี้จะไม่ได้ผลเลย แต่ก็เป็นเช่นนั้น เป็นเรื่องจริงที่น่าสังเกตว่าข้อผิดพลาดไม่ได้ลดลงในทุกขั้นตอน แต่มีแนวโน้มอย่างแน่นอน

อะไรคือข้อดีของการไล่ระดับสีแบบสุ่มมากกว่าแบบธรรมดา? หากขนาดตัวอย่างของเรามีขนาดใหญ่มากและวัดด้วยค่าหลายหมื่นค่า ก็ง่ายกว่ามากในการประมวลผล เช่น สุ่มค่าหนึ่งพันค่า แทนที่จะประมวลผลทั้งตัวอย่าง นี่คือจุดที่การไล่ระดับแบบสุ่มเข้ามามีบทบาท ในกรณีของเรา แน่นอนว่าเราจะไม่สังเกตเห็นความแตกต่างมากนัก

มาดูโค้ดกัน

รหัสสำหรับการโคตรลาดสุ่ม

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


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


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

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


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

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

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

เราดูค่าสัมประสิทธิ์อย่างรอบคอบและพบว่าตนเองถามคำถามว่า "เป็นไปได้อย่างไร" เราได้ค่าสัมประสิทธิ์อื่นๆ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่าย. บางทีการไล่ระดับสีแบบสุ่มอาจพบพารามิเตอร์ที่เหมาะสมที่สุดสำหรับสมการ น่าเสียดายที่ไม่มี ก็เพียงพอที่จะดูผลรวมของการเบี่ยงเบนกำลังสองและดูว่าด้วยค่าสัมประสิทธิ์ใหม่ข้อผิดพลาดจะใหญ่ขึ้น เราไม่รีบร้อนที่จะสิ้นหวัง มาสร้างกราฟการเปลี่ยนแปลงข้อผิดพลาดกัน

โค้ดสำหรับพล็อตผลรวมของการเบี่ยงเบนกำลังสองในการไล่ระดับสีแบบสุ่ม

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

กราฟหมายเลข 5 “ผลรวมของการเบี่ยงเบนกำลังสองระหว่างการไล่ระดับแบบสุ่ม”

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

เมื่อดูตารางเวลา ทุกอย่างเข้าที่ และตอนนี้เราจะแก้ไขทุกอย่าง

แล้วเกิดอะไรขึ้น? ต่อไปนี้เกิดขึ้น. เมื่อเราสุ่มเลือกเดือน อัลกอริทึมของเราจะพยายามลดข้อผิดพลาดในการคำนวณรายได้สำหรับเดือนที่เลือก จากนั้นเราเลือกเดือนอื่นแล้วคำนวณซ้ำ แต่เราลดข้อผิดพลาดสำหรับเดือนที่สองที่เลือก ตอนนี้จำไว้ว่าในช่วงสองเดือนแรกเบี่ยงเบนไปจากเส้นสมการการถดถอยเชิงเส้นอย่างง่ายอย่างมีนัยสำคัญ ซึ่งหมายความว่าเมื่อเลือกเดือนใดเดือนหนึ่งจากสองเดือนนี้ อัลกอริธึมของเราจะเพิ่มข้อผิดพลาดให้กับกลุ่มตัวอย่างทั้งหมดด้วยการลดข้อผิดพลาดของแต่ละเดือน แล้วต้องทำอย่างไร? คำตอบนั้นง่าย: คุณต้องลดขั้นตอนการลง ท้ายที่สุดแล้ว หากลดขั้นตอนการลง ข้อผิดพลาดก็จะหยุด "กระโดด" ขึ้นลงด้วย หรือมากกว่านั้นข้อผิดพลาด "การกระโดด" จะไม่หยุด แต่จะไม่เกิดขึ้นเร็วนัก :) มาตรวจสอบกันดีกว่า

รหัสเพื่อรัน SGD โดยเพิ่มขึ้นทีละน้อย

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

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


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



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

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

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

กราฟหมายเลข 6 “ผลรวมของการเบี่ยงเบนกำลังสองระหว่างการไล่ระดับสีแบบสุ่ม (80 ขั้นตอน)”

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

ค่าสัมประสิทธิ์ได้รับการปรับปรุง แต่ก็ยังไม่เหมาะ สมมุติว่าสามารถแก้ไขได้ด้วยวิธีนี้ ตัวอย่างเช่นเราเลือกค่าของสัมประสิทธิ์ที่เกิดข้อผิดพลาดขั้นต่ำในการวนซ้ำ 1000 ครั้งล่าสุด จริงอยู่สำหรับสิ่งนี้เราจะต้องเขียนค่าสัมประสิทธิ์ด้วย เราจะไม่ทำเช่นนี้ แต่ให้ความสำคัญกับกำหนดการแทน มันดูราบรื่นและข้อผิดพลาดดูเหมือนจะลดลงเท่าๆ กัน จริงๆแล้วสิ่งนี้ไม่เป็นความจริง ลองดูที่การวนซ้ำ 1000 ครั้งแรกแล้วเปรียบเทียบกับครั้งล่าสุด

รหัสสำหรับแผนภูมิ SGD (1000 ขั้นตอนแรก)

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

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

กราฟหมายเลข 7 “ผลรวมของการเบี่ยงเบนกำลังสอง SGD (1000 ขั้นตอนแรก)”

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

กราฟหมายเลข 8 “ผลรวมของการเบี่ยงเบนกำลังสอง SGD (1000 ขั้นตอนสุดท้าย)”

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

ที่จุดเริ่มต้นของการสืบเชื้อสาย เราสังเกตเห็นข้อผิดพลาดที่ลดลงค่อนข้างสม่ำเสมอและสูงชัน ในการวนซ้ำครั้งล่าสุด เราจะเห็นว่าข้อผิดพลาดเกิดขึ้นรอบๆ และรอบๆ ค่า 1,475 และในบางช่วงเวลาก็เท่ากับค่าที่เหมาะสมที่สุดนี้ด้วยซ้ำ แต่แล้วข้อผิดพลาดก็ยังคงเพิ่มขึ้น... ขอย้ำอีกครั้งว่าคุณสามารถเขียนค่าของ ค่าสัมประสิทธิ์ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย и การแก้สมการการถดถอยเชิงเส้นอย่างง่ายจากนั้นเลือกรายการที่มีข้อผิดพลาดน้อยที่สุด อย่างไรก็ตาม เรามีปัญหาที่ร้ายแรงกว่านั้น: เราต้องใช้เวลา 80 ขั้นตอน (ดูโค้ด) เพื่อให้ได้ค่าที่ใกล้เคียงกับค่าที่เหมาะสมที่สุด และสิ่งนี้ขัดแย้งกับแนวคิดในการประหยัดเวลาในการคำนวณด้วยการไล่ระดับสีแบบสุ่มเมื่อเทียบกับการไล่ระดับสี สิ่งใดสามารถแก้ไขและปรับปรุงได้? ไม่ใช่เรื่องยากที่จะสังเกตว่าในการวนซ้ำครั้งแรก เรากำลังลงไปอย่างมั่นใจ ดังนั้น เราควรทิ้งก้าวใหญ่ในการวนซ้ำครั้งแรก และลดขั้นตอนในขณะที่เราก้าวไปข้างหน้า เราจะไม่ทำเช่นนี้ในบทความนี้ - มันยาวเกินไปแล้ว ใครอยากได้ก็คิดเอาเองว่าต้องทำยังไง ไม่ยาก :)

ตอนนี้เรามาทำการสุ่มโคตรลาดโดยใช้ไลบรารี นำพาย (และอย่าสะดุดก้อนหินที่เราระบุไว้ก่อนหน้านี้)

รหัสสำหรับ Stochastic Gradient Descent (NumPy)

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

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

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

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


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



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

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

ค่าที่ได้เกือบจะเหมือนกับตอนลงโดยไม่ใช้ นำพาย. อย่างไรก็ตาม นี่เป็นตรรกะ

มาดูกันว่าการไล่ระดับสีแบบสุ่มใช้เวลานานแค่ไหน

รหัสกำหนดเวลาการคำนวณ SGD (80 ขั้นตอน)

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

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

การแก้สมการการถดถอยเชิงเส้นอย่างง่าย

ยิ่งเข้าไปในป่าลึก เมฆก็จะยิ่งมืดลง สูตร "เขียนเอง" จะแสดงผลลัพธ์ที่ดีที่สุดอีกครั้ง ทั้งหมดนี้ชี้ให้เห็นว่าต้องมีวิธีที่ละเอียดอ่อนกว่านี้ในการใช้ห้องสมุด นำพายซึ่งทำให้การดำเนินการคำนวณเร็วขึ้นจริงๆ ในบทความนี้ เราจะไม่เรียนรู้เกี่ยวกับสิ่งเหล่านี้ เวลาว่างจะมีเรื่องให้คิด :)

สรุป

ก่อนที่จะสรุปฉันอยากจะตอบคำถามที่อาจเกิดจากผู้อ่านที่รักของเรามากที่สุด ในความเป็นจริงทำไม "การทรมาน" ที่มีการสืบเชื้อสายเช่นนี้ทำไมเราต้องเดินขึ้นลงภูเขา (ส่วนใหญ่ลง) เพื่อค้นหาที่ราบลุ่มอันล้ำค่าหากเรามีอุปกรณ์ที่ทรงพลังและเรียบง่ายอยู่ในมือของเราใน รูปแบบของโซลูชันเชิงวิเคราะห์ ซึ่งจะพาเราไปที่ที่ถูกต้องทันที

คำตอบสำหรับคำถามนี้อยู่บนพื้นผิว ตอนนี้เราได้ดูตัวอย่างง่ายๆ ซึ่งคำตอบที่แท้จริงก็คือ การแก้สมการการถดถอยเชิงเส้นอย่างง่าย ขึ้นอยู่กับสัญญาณเดียว การแก้สมการการถดถอยเชิงเส้นอย่างง่าย. คุณไม่เห็นสิ่งนี้บ่อยนักในชีวิต ลองจินตนาการว่าเรามีสัญญาณ 2, 30, 50 หรือมากกว่านั้น มาเพิ่มค่านับพันหรือหมื่นค่าสำหรับแต่ละแอตทริบิวต์กัน ในกรณีนี้ โซลูชันการวิเคราะห์อาจไม่ทนต่อการทดสอบและล้มเหลว ในทางกลับกัน การไล่ระดับลงและการแปรผันของมันจะทำให้เราเข้าใกล้เป้าหมายมากขึ้นอย่างช้าๆ แต่แน่นอน - ซึ่งเป็นฟังก์ชันขั้นต่ำ และไม่ต้องกังวลเรื่องความเร็ว เราอาจมาดูวิธีที่จะช่วยให้เราสามารถกำหนดและควบคุมความยาวของก้าวได้ (นั่นคือ ความเร็ว)

และตอนนี้บทสรุปสั้น ๆ ที่เกิดขึ้นจริง

ประการแรก ฉันหวังว่าเนื้อหาที่นำเสนอในบทความจะช่วยให้เริ่มต้น "นักวิทยาศาสตร์ข้อมูล" ในการทำความเข้าใจวิธีการแก้สมการถดถอยเชิงเส้นแบบง่าย (และไม่เพียงเท่านั้น)

ประการที่สอง เราดูหลายวิธีในการแก้สมการ ตอนนี้เราสามารถเลือกอันที่เหมาะสมที่สุดในการแก้ปัญหาได้ทั้งนี้ขึ้นอยู่กับสถานการณ์

ประการที่สาม เราเห็นพลังของการตั้งค่าเพิ่มเติม กล่าวคือ ความยาวขั้นบันไดของการไล่ระดับสี พารามิเตอร์นี้ไม่สามารถละเลยได้ ตามที่ระบุไว้ข้างต้น เพื่อลดต้นทุนการคำนวณ ควรเปลี่ยนความยาวของขั้นตอนในระหว่างการสืบเชื้อสาย

ประการที่สี่ ในกรณีของเรา ฟังก์ชัน "เขียนเอง" แสดงผลเวลาที่ดีที่สุดสำหรับการคำนวณ นี่อาจเป็นเพราะไม่ใช่การใช้ความสามารถของห้องสมุดอย่างมืออาชีพที่สุด นำพาย. แต่อย่างไรก็ตาม ข้อสรุปต่อไปนี้ก็แนะนำตัวมันเอง ในอีกด้านหนึ่งบางครั้งก็คุ้มค่าที่จะตั้งคำถามกับความคิดเห็นที่เป็นที่ยอมรับและในทางกลับกันมันไม่คุ้มที่จะทำทุกอย่างให้ซับซ้อนเสมอไป - ในทางกลับกันบางครั้งวิธีที่ง่ายกว่าในการแก้ปัญหาก็มีประสิทธิภาพมากกว่า และเนื่องจากเป้าหมายของเราคือการวิเคราะห์สามวิธีในการแก้สมการการถดถอยเชิงเส้นอย่างง่าย การใช้ฟังก์ชัน "เขียนเอง" จึงเพียงพอสำหรับเรา

วรรณกรรม (หรืออะไรทำนองนั้น)

1. การถดถอยเชิงเส้น

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

2. วิธีกำลังสองน้อยที่สุด

mathprofi.ru/metod_naimenshih_kvadratov.html

3. อนุพันธ์

www.mathprofi.ru/chastnye_proizvodnye_primery.html

4 ลาด

mathprofi.ru/proizvodnaja_po_napravleniju_i_gradient.html

5. การไล่ระดับโคตร

habr.com/th/post/471458

habr.com/th/post/307312

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

6. ห้องสมุด NumPy

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

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

pythonworld.ru/numpy/2.html

ที่มา: will.com

เพิ่มความคิดเห็น