Shanraq.org Shanraq.org
Бірінші модель: сызықтық регрессия
IT

Python: деректен өз есебіңізге дейін 44-сабақ (барлығы 56)

Бірінші модель: сызықтық регрессия

Python курсының қырық үшінші сабағы. Он алты жылдық баға арқылы жүргізілген түзу R² 0.927 береді әрі «өткен жылдағыдай» деген ережеден жүздік тармаққа ұтылады. Оның қатесі кездейсоқ емес, пішіні бар: плюс, минус, плюс. Логарифмдегі түзу екі есе аз қателеседі, өйткені баға көбейтіледі.

Не үшін керек

Өткен сабақтағы байланыс «бұл екі баған бірге қозғалды» дейді. Модель одан көбін айтады: қаншаға және мынадай мәнде не болады. Олардың біріншісі әрі ең адалы — түзу.

Оның бағасы — енді санмен атауға болатын қате. Сабақ модельді қалай үйрету керегі (екі жол) туралы емес, оның қателеріне қалай қарау керегі және әдемі R²-ға қалай алданбау керегі туралы.

Бірден тұтас

model.py файлы. Қатар нағыз: Қазақстанның 2010 жылдан бергі тұтыну бағасының индексі, Дүниежүзілік банк. Кітапхана жаңа — scikit-learn, pip install scikit-learn==1.9.1.

"""43-сабақ: бірінші модель — баға арқылы өтетін түзу.

Қатар нағыз: Қазақстанның тұтыну бағасының индексі, 2010 = 100, Дүниежүзілік
банктің FP.CPI.TOTL көрсеткіші. Кітапхана — scikit-learn.
"""

import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score

CPI = pd.Series({
    2010: 100.00, 2011: 108.45, 2012: 114.09, 2013: 120.87, 2014: 129.15,
    2015: 137.77, 2016: 157.56, 2017: 169.28, 2018: 179.72, 2019: 189.30,
    2020: 202.02, 2021: 218.27, 2022: 251.07, 2023: 287.54, 2024: 312.53,
    2025: 348.12,
})

# sklearn белгілер кестесін күтеді: жол — бақылау, баған — белгі.
# Мұнда белгі біреу, жыл, сондықтан баған да біреу — бірақ баған, қатар емес.
X = CPI.index.to_numpy().reshape(-1, 1)
y = CPI.to_numpy()

print("== Он алты жыл арқылы өтетін түзу")
line = LinearRegression().fit(X, y)
print("  жылына индекс қосады:", round(float(line.coef_[0]), 2), "тармақ")
print("  R²:", round(r2_score(y, line.predict(X)), 3))
print("  орташа қате:", round(mean_absolute_error(y, line.predict(X)), 2), "тармақ")

print()
print("== Сәйкестік қана емес, қате де")
table = pd.DataFrame({"индекс": CPI, "түзу": line.predict(X).round(1)})
table["қате"] = (table["индекс"] - table["түзу"]).round(1)
print(table.to_string())
worst = table["қате"].abs().idxmax()
print("  ең нашар жыл:", worst, "— қателік", round(float(table.loc[worst, "қате"]), 1), "тармақ")

print()
print("== Қатенің пішіні бар")
signs = "".join("+" if e > 0 else "-" for e in table["қате"])
print("  жылдар бойынша қате таңбалары:", signs)
print("  қатар келген таңба топтары:", 1 + sum(1 for a, b in zip(signs, signs[1:]) if a != b))
print("  кездейсоқ қатеде олар шамамен", round(len(signs) / 2 + 1), "болар еді")

print()
print("== Логарифмдегі түзу")
log_line = LinearRegression().fit(X, np.log(y))
growth = float(np.exp(log_line.coef_[0]) - 1)
predicted = np.exp(log_line.predict(X))
print("  жылына баға көбейтіледі:", round(float(np.exp(log_line.coef_[0])), 4),
      "— бұл жылына", round(growth * 100, 2), "%")
print("  орташа қате:", round(mean_absolute_error(y, predicted), 2), "тармақ")
print("  ең үлкен қателік:", round(float(np.max(np.abs(y - predicted))), 2), "тармақ")

print()
print("== Болжам және оның бағасы")
next_year = np.array([[2026]])
print("  түзу 2026 жылға уәде етеді:", round(float(line.predict(next_year)[0]), 1))
print("  логарифмдегі түзу:", round(float(np.exp(log_line.predict(next_year)[0])), 1))
print("  уәделер арасындағы айырма:",
      round(float(np.exp(log_line.predict(next_year)[0]) - line.predict(next_year)[0]), 1), "тармақ")

Шығысы:

== Он алты жыл арқылы өтетін түзу
  жылына индекс қосады: 15.45 тармақ
  R²: 0.927
  орташа қате: 17.17 тармақ

== Сәйкестік қана емес, қате де
      индекс   түзу  қате
2010  100.00   73.2  26.8
2011  108.45   88.7  19.8
2012  114.09  104.1  10.0
2013  120.87  119.6   1.3
2014  129.15  135.0  -5.8
2015  137.77  150.5 -12.7
2016  157.56  165.9  -8.3
2017  169.28  181.4 -12.1
2018  179.72  196.8 -17.1
2019  189.30  212.3 -23.0
2020  202.02  227.7 -25.7
2021  218.27  243.2 -24.9
2022  251.07  258.6  -7.5
2023  287.54  274.1  13.4
2024  312.53  289.5  23.0
2025  348.12  305.0  43.1
  ең нашар жыл: 2025 — қателік 43.1 тармақ

== Қатенің пішіні бар
  жылдар бойынша қате таңбалары: ++++---------+++
  қатар келген таңба топтары: 3
  кездейсоқ қатеде олар шамамен 9 болар еді

== Логарифмдегі түзу
  жылына баға көбейтіледі: 1.0849 — бұл жылына 8.49 %
  орташа қате: 7.39 тармақ
  ең үлкен қателік: 24.09 тармақ

== Болжам және оның бағасы
  түзу 2026 жылға уәде етеді: 320.4
  логарифмдегі түзу: 351.5
  уәделер арасындағы айырма: 31.1 тармақ

Талдау

Модель — бұл екі жол

model = LinearRegression().fit(X, y)
model.predict(X)

fit түзуді іріктейді, predict одан сұрайды. Сабақтағы қалғанының бәрі — оның жарайтын-жарамайтынын қалай түсіну керегі туралы.

Деректің пішінінде бір нәзіктік бар: X белгілер кестесі болуға тиіс — бақылауға бір жол, белгіге бір баған, — сондықтан reshape(-1, 1). Мұндағы белгі біреу, жыл, бірақ баған бәрібір керек: sklearn сізде бір белгі ме, әлде жүз бе, соны болжамайды.

R² әдемі әрі дерлік ештеңе білдірмейді

  R²: 0.927
  орташа қате: 17.17 тармақ

R² — модель түсіндірген шашыраудың үлесі: 0.927 деген «модель 93 %-ға дұрыс» сияқты естіледі. Шын мәнінде оның қасында жүзден басталған индексте 17 тармақтық орташа қате тұр.

Себебі қарапайым: R² модельді орташа мәнді болжайтын базалық үлгімен салыстырады. R² = 0 сол базаға тең, ал теріс мән базадан нашар екенін білдіреді; бұл мүмкін болатын ең әлсіз модель емес. Өсіп келе жатқан кез келген қатарда оны ұту оңай. Сондықтан R² «модель жақсы ма» деген сұраққа жауап бола алмайды.

Қатенің пішіні бар

  жылдар бойынша қате таңбалары: ++++---------+++
  қатар келген таңба топтары: 3
  кездейсоқ қатеде олар шамамен 9 болар еді

Бұл — пайдалы эвристика, бірақ түпкілікті диагноз емес. Қалдықтар тәуелсіз болса, олардың таңбалары жиірек алмасады; сериялардың күтілетін саны оң және теріс қалдықтардың санына тәуелді. Ресми қорытынды үшін сериялар тесті мен қалдықтар графигі керек, ал «нүктелердің шамамен жартысы» — таңбалар теңгерілгендегі жуық бағдар ғана. Мұнда топ үшеу: модель алдымен жүйелі түрде асыра болжайды, сосын сонша жыл кемітіп болжайды, сосын тағы асырады.

Бұл шу емес, модельдің жетіспейтін бөлігі осылай көрінеді. Түзу иіле алмайды, ал қатар иіледі.

Баға көбейтіледі — демек, түзу логарифмде керек

Отыз сегізінші сабақ: пайыздар қосылмайды, көбейтіледі. Жыл сайын шамамен бірдей санға көбейтілетін қатар — түзу емес, экспонента. Логарифм көбейтуді қосуға айналдырады, әрі логарифмде сол түзу дұрыс пішінге айналады:

  жылына баға көбейтіледі: 1.0849 — бұл жылына 8.49 %
  орташа қате: 7.39 тармақ

Қате екі еседен астам азайды, ал коэффициент оқылатын болды: жылына 8.49 % — бұл отыз сегізінші сабақтағы сол жылдық орташа мөлшерлеме, тек модельмен алынған.

Оның да қателесетінін байқаңыз: орташа 7.39 тармақ, ең нашар жылы 24. Ішінде 2022 жыл бар қатар бір тұрақты мөлшерлемемен сипатталмайды — әрі бұл екі модельдің де адал шегі, үшіншісін іздеуге себеп емес.

Болжам — бір сан емес, екі сан

  түзу 2026 жылға уәде етеді: 320.4
  логарифмдегі түзу: 351.5

Отыз бір тармақ айырма — бұл дерек емес, модель пішінін таңдау: қатар сол бір қатар. Осыдан кез келген формуладан бұрын түсінетін ереже шығады: модель мен оның қатесі аталмаған болжам — бұл пікір, әрі үтірден кейінгі цифр оған салмақ қоспайды.

Бұл есеп нені істей алмайды

Екі модель де өздері үйренген жылдарда өлшенді. Былай өлшеу тек қатенің пішінін көру үшін жарайды; «жаңа жылмен қалай справится» деген сұраққа мүлде жарамайды — модель жауаптарды әлдеқашан көрген. Қатарды адал бөлу — келесі сабақ.

Сабақ картасы

Сабақ картасы: нүктелер, түзу және қате

Өз сөзіңізбен айтыңыз

Қарамай, дауыстап немесе қағазға жауап беріңіз. Жауаптар — сабақтың соңында.

  1. X не үшін бір бағаннан тұратын кестеге айналдырылады?
  2. R² 0.927 модельдің жақсы екенін неге білдірмейді?
  3. Қатедегі тоғыздың орнына үш топ нені білдіреді?

Жаттығу

Тапсырмаға дейінгі үш қысқа қадам: болжау, толықтыру, түзету. Жауаптар — сабақтың соңында, бірақ алдымен өзіңіз жауап беріңіз.

1. Болжаңыз. Нүктелер идеал түзуде жатса, бағдарлама не басып шығарады?

import numpy as np
from sklearn.linear_model import LinearRegression

x = np.array([[1], [2], [3], [4]])
y = np.array([3.0, 5.0, 7.0, 9.0])
model = LinearRegression().fit(x, y)
print("көлбеу:", round(float(model.coef_[0]), 3))
print("жылжу:", round(float(model.intercept_), 3))
print("10 үшін:", round(float(model.predict(np.array([[10]]))[0]), 3))

2. Бос орынды толтырыңыз. ... орнына жылдарды sklearn күтетін пішінге келтіріңіз.

# sklearn белгілер кестесін күтеді, қатарды емес
import numpy as np
from sklearn.linear_model import LinearRegression

years = np.array([2020, 2021, 2022, 2023])
index = np.array([100.0, 108.0, 117.0, 126.0])
X = ...
model = LinearRegression().fit(X, index)
print("жылына қосады:", round(float(model.coef_[0]), 2))

3. Түзетіңіз. Бағдарлама қатені орташа айырмамен өлшейді де, модельді мінсіз деп жариялайды.

# қателер таңбасымен қосылады, ал түзуде олар бірін-бірі жояды
import numpy as np

index = np.array([100.0, 108.0, 117.0, 126.0])
guess = np.array([99.0, 109.0, 118.0, 125.0])
print("орташа қате:", round(float((index - guess).mean()), 2))

Тапсырма

Міндетті. Баға индексі үшін жылдар бойынша түзу тұрғызып, жылдар бойынша индексті, болжамды және қатені басып шығарыңыз. Көлбеуді, R²-ты және қателік мөлшерімен бірге ең нашар жылды хабарлаңыз. Бөлек: қате таңбаларын және қатар келген таңба топтарының санын — кездейсоқ қатеде топ қанша болатынының қасында — санаңыз. Соңында бір жылдарда үш болжау тәсілін салыстырыңыз: түзу, логарифмдегі түзу және «өткен жылдағыдай» ережесі, — әрі ең жақсысын атаңыз.

Күтілетін шығыс:

== Жылдар бойынша түзу
      индекс   түзу  қате
2010  100.00   73.2  26.8
2011  108.45   88.7  19.8
2012  114.09  104.1  10.0
2013  120.87  119.6   1.3
2014  129.15  135.0  -5.8
2015  137.77  150.5 -12.7
2016  157.56  165.9  -8.3
2017  169.28  181.4 -12.1
2018  179.72  196.8 -17.1
2019  189.30  212.3 -23.0
2020  202.02  227.7 -25.7
2021  218.27  243.2 -24.9
2022  251.07  258.6  -7.5
2023  287.54  274.1  13.4
2024  312.53  289.5  23.0
2025  348.12  305.0  43.1
  жылына қосады: 15.45 тармақ
  R²: 0.927
  ең нашар жыл: 2025 — қателік 43.1 тармақ

== Қатенің пішіні
  таңбалар: ++++---------+++
  топтар: 3 — кездейсоқ қатеде 9

== Бір жылдарда салыстыру
түзу                 16.53
логарифмдегі түзу     7.58
өткен жылдағыдай     16.54
  салыстырудағы жыл: 15
  ең жақсысы: логарифмдегі түзу
  түзу «ештеңе істемеуді» ұтады: 0.01 тармаққа

Дайын болғаны: шығыс жол-жолымен сәйкес келеді; салыстыру әр модельде бар барлық жылда емес, бір жылдарда жүреді; қате модуль бойынша өлшенеді; ең жақсы тәсілді көз емес, код таңдайды.

Өз деректеріңізде. Уақыт бойынша кез келген өз қатарыңызды алыңыз — айлар бойынша шығыс, салмақ, километр, шоттар. Түзу тұрғызып, қате таңбаларына қарап, өзіңізге бір сұраққа жауап беріңіз: олар кезектесе ме, әлде жолақпен жүре ме? Жолақпен жүрсе, түзу — дұрыс пішін емес, логарифмді көріңіз.

Қалауыңыз бойынша.

  • Түзуді тек 2010–2019 жылдарда үйретіп, оның 2022 жылға не уәде ететінін қараңыз. Бұл — келесі сабақтың репетициясы.
  • Екінші белгі қосыңыз — мысалы, жылдың квадратын — әрі қатенің қалай азаятынын және таңбалар пішініне не болатынын қараңыз.
  • LinearRegression мен numpy.polyfit(x, y, 1) нәтижесін салыстырыңыз: коэффициенттер сәйкес келуге тиіс, әрі бұл модель дәл сіз ойлағанды істеп тұрғанына көз жеткізудің жақсы тәсілі.

Жобада бұл қайда тұрады

Жиырма екінші қадам: жиынтықта бірінші модель пайда болады.

esep.trend әр елдің индексінің логарифмі бойынша түзу тұрғызып, екі сан басады: осы түзу білдіретін жылдық көбейткіш және индекс тармағымен ең үлкен қателік. Екіншісі біріншісінің қасында әдемілік үшін тұрған жоқ — қатесіз тренд бағасы аталмаған тұжырым, ал елдер әртүрлі сипатталады: Қазақстан жылына 1.12, қателігі 3.56; Өзбекстан 1.10, қателігі 1.02.

Болжамды жиынтық баспайды. Ол үшін бір жол керек, әрі оны жазбаудың себебі дәл сол: модель өзі көрмеген жылдарда тексерілгеннен кейін ғана болжамға лайық. Ондай тексеру жоқ кезде жиынтық өзіне берілген жылдар туралы айтады да, берілмегендері туралы үндемейді.

Жобаның requirements.txt файлына scikit-learn бекітілген нұсқасымен қосылды: кітапханасының нұсқасы жазылмаған модель — ешкім қайталай алмайтын модель.

Жауаптар

Жауаптарды көрсету

Сұрақтарға

  1. Өйткені sklearn «бақылаулар × белгілер» кестесін қабылдайды әрі он алты саннан тұратын қатармен нені меңзегеніңізді болжамайды: он алты бақылауы бар бір белгі ме, әлде бір бақылауы бар он алты белгі ме. reshape(-1, 1) мұны анық айтады.
  2. Өйткені R² модельді орташа деңгейдегі көлденең түзумен салыстырады, ақылға қонымды бірдеңемен емес. Өсіп келе жатқан қатарда оны кез келген нәрсе ұтады. Мұндағы R² 0.927-нің қасында 17 тармақтық орташа қате және «өткен жылдағыдай» ережесінен ұтылу тұр.
  3. Қатенің кездейсоқ емес екенін: модель бір бөлікте жүйелі асыра, екіншісінде кемітіп болжайды. Кездейсоқ қатеде таңба жиі ауысар еді — топ саны нүкте санының жартысындай болар еді. Үш топ модельдің пішіні дұрыс емес екенін білдіреді.

Жаттығуға

  1. Нүктелер y = 2x + 1 түзуінде жатыр, сондықтан көлбеуі дәл 2, жылжуы дәл 1, ал ондыққа модель 21 береді.
көлбеу: 2.0
жылжу: 1.0
10 үшін: 21.0
  1. years.reshape(-1, 1). Минус бір — «бұл өлшем өзі есептеледі» дегені, ал бір — «бір баған».
# sklearn белгілер кестесін күтеді, қатарды емес: жол — бақылау, баған — белгі
import numpy as np
from sklearn.linear_model import LinearRegression

years = np.array([2020, 2021, 2022, 2023])
index = np.array([100.0, 108.0, 117.0, 126.0])
X = years.reshape(-1, 1)
model = LinearRegression().fit(X, index)
print("жылына қосады:", round(float(model.coef_[0]), 2))
жылына қосады: 8.7
  1. Қатені модуль бойынша алу керек. Түзуде орташа айырма құрылысы бойынша нөлге тең — ол «жақсы модель» емес, ол сапа өлшемі де емес.
# қатені модуль бойынша өлшейді: түзуде плюс пен минус бірін-бірі жояды
import numpy as np

index = np.array([100.0, 108.0, 117.0, 126.0])
guess = np.array([99.0, 109.0, 118.0, 125.0])
errors = index - guess
print("модуль бойынша орташа:", round(float(np.abs(errors).mean()), 2))
print("ал жай орташа:", round(float(errors.mean()), 2))
модуль бойынша орташа: 1.0
ал жай орташа: 0.0

Тапсырмаға

Тапсырманың басты саны — соңғысы. R² 0.927 түзу «өткен жылды қайтала» ережесін жүздік тармаққа ұтады, яғни мүлде ұтпайды. Әр модель үшін төлеуге тұрарлық баға осы: нөлмен емес, модельсіз істеуге болатын ең қарапайым нәрсемен салыстыру.

Логарифмдегі түзу шынымен ұтады — 16.5-ке қарсы 7.58, — әрі күрделірек болғандықтан емес, пішіні дұрыс болғандықтан. Деректің пішініне қарай іріктелген модель сан алу тілегіне қарай іріктелген модельді дерлік әрқашан басып озады.

Дереккөздер

Мәтінде қате не теру қатесі кездессе, бізге айтыңыз

Тапсырманы тексеру

Алдымен VS Code-та шешіп, іске қосыңыз — редактор қатені сол жерде көрсетеді. Дайын шешімді осында қойыңыз. Тексеретін — модель: ол қатені атап көрсетеді, бірақ дайын жауапты бермейді.

Тексеру үшін кіру керек. Кіру

Пікірлер (0)

Әзірге пікір жоқ. Бірінші болыңыз.