Python: деректен өз есебіңізге дейін 45-сабақ (барлығы 56)
Үйрету және тексеру: өз деректерінде неге өлшеуге болмайды
Python курсының қырық төртінші сабағы. Сол модель, сол дерек: үйреткен жылдарында қате 2.48, көрмегенінде 35.99. Уақыт бойынша кесудің орнына кездейсоқ кесу 5.37 көрсетеді әрі өтірік айтады. Бесінші дәрежелі көпмүше дерлік мінсіз үйренеді де, түзуден үш есе нашар қателеседі.
Не үшін керек
Өткен сабақ мойындаумен бітті: екі модель де өздері үйренген жылдарда өлшенді. Бәрі өзін солай өлшейді — әрі бұл модель әрқашан өтетін жалғыз тексеру.
Адал тексеру бір жол кодқа тұрады да, барлық қорытындыны өзгертеді. Бұл сабақ қатарды уақыт бойынша қалай кесу керегі, мұнда кездейсоқ кесудің неге өтірік айтатыны және қайта оқып кетудің көрінгенде қалай көрінетіні туралы.
Бірден тұтас
proverka.py файлы. Қатар өткен сабақтағыдай: Қазақстанның тұтыну бағасының индексі, Дүниежүзілік банк.
"""44-сабақ: үйрету және тексеру — өз деректерінде неге өлшеуге болмайды.
Қатар өткен сабақтағыдай: Қазақстанның тұтыну бағасының индексі, 2010 = 100,
Дүниежүзілік банктің FP.CPI.TOTL көрсеткіші.
"""
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import train_test_split
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,
})
YEARS = CPI.index.to_numpy()
VALUES = CPI.to_numpy()
# Жылдарды нөлге жақындатып, онға бөлеміз: дәрежедегі үлкен сандар есепті
# тұрақсыз етеді, ал төменде дәрежелер керек болады.
def feature(years, degree=1):
return np.vander((years - 2010) / 10, degree + 1)
def log_line(years, values):
"""Логарифм бойынша түзу — өткен сабақтағы сол пішін."""
model = LinearRegression().fit(feature(years), np.log(values))
return lambda ask: np.exp(model.predict(feature(ask)))
print("== Уақыт бойынша кесу")
past = YEARS <= 2021
guess = log_line(YEARS[past], VALUES[past])
on_train = mean_absolute_error(VALUES[past], guess(YEARS[past]))
on_test = mean_absolute_error(VALUES[~past], guess(YEARS[~past]))
print(" үйретеміз:", int(YEARS[past].min()), "-", int(YEARS[past].max()),
f"({int(past.sum())} жыл)")
print(" тексереміз:", [int(y) for y in YEARS[~past]])
print(" үйретудегі қате:", round(on_train, 2), "тармақ")
print(" тексерудегі қате:", round(on_test, 2), "тармақ")
print(" тексеру үйретуден", round(on_test / on_train, 1), "есе нашар")
print()
print("== Кездейсоқ кесу жағымпаздық жасайды")
y_train, y_test, v_train, v_test = train_test_split(
YEARS, VALUES, test_size=4, random_state=0)
shuffled = log_line(y_train, v_train)
print(" тексеру жылдары:", [int(y) for y in sorted(y_test)])
print(" тексерудегі қате:", round(mean_absolute_error(v_test, shuffled(y_test)), 2), "тармақ")
print(" сол модель уақыт бойынша кесуде:", round(on_test, 2), "тармақ")
print()
print("== Неғұрлым күрделі, соғұрлым нашар")
rows = []
for degree in (1, 2, 3, 5):
model = LinearRegression().fit(feature(YEARS[past], degree), VALUES[past])
rows.append({
"дәреже": degree,
"үйретуде": round(mean_absolute_error(
VALUES[past], model.predict(feature(YEARS[past], degree))), 2),
"тексеруде": round(mean_absolute_error(
VALUES[~past], model.predict(feature(YEARS[~past], degree))), 2),
})
table = pd.DataFrame(rows).set_index("дәреже")
print(table.to_string())
print()
print("== Нені таңдау керек")
best_train = table["үйретуде"].idxmin()
best_test = table["тексеруде"].idxmin()
print(" үйрету бойынша ең жақсы дәреже:", best_train, "— тексерудегі қатесі",
table.loc[best_train, "тексеруде"])
print(" тексеру бойынша ең жақсы дәреже:", best_test, "— тексерудегі қатесі",
table.loc[best_test, "тексеруде"])
print(" логарифм бойынша түзу:", round(on_test, 2), "— барлық көпмүшеден жақсы")
Шығысы:
== Уақыт бойынша кесу
үйретеміз: 2010 - 2021 (12 жыл)
тексереміз: [2022, 2023, 2024, 2025]
үйретудегі қате: 2.48 тармақ
тексерудегі қате: 35.99 тармақ
тексеру үйретуден 14.5 есе нашар
== Кездейсоқ кесу жағымпаздық жасайды
тексеру жылдары: [2011, 2016, 2018, 2019]
тексерудегі қате: 5.37 тармақ
сол модель уақыт бойынша кесуде: 35.99 тармақ
== Неғұрлым күрделі, соғұрлым нашар
үйретуде тексеруде
дәреже
1 3.51 60.78
2 2.30 41.22
3 2.13 57.09
5 0.99 116.69
== Нені таңдау керек
үйрету бойынша ең жақсы дәреже: 5 — тексерудегі қатесі 116.69
тексеру бойынша ең жақсы дәреже: 2 — тексерудегі қатесі 41.22
логарифм бойынша түзу: 35.99 — барлық көпмүшеден жақсы
Талдау
Тексеру — бұл модель көрмеген жылдар
үйретудегі қате: 2.48 тармақ
тексерудегі қате: 35.99 тармақ
Модель де, дерек те қырық үшінші сабақтағыдай. Өзгергені біреу: оны 2010–2021 жылдарда үйретіп, 2022–2025 туралы сұрадық. Қате 14.5 есе өсті.
Бұл сандардың бірі «нағыз», екіншісі «жалған» емес. Олар жай ғана әртүрлі сұраққа жауап береді. Үйретудегі қате модельдің өткенді қаншалық жақсы сипаттағанын айтады; тексерудегі қате — оны әдетте не үшін тұрғызатын болса, соған қаншалық жарайтынын.
Кездейсоқ кесу жағымпаздық жасайды, себебі мынау
тексеру жылдары: [2011, 2016, 2018, 2019]
тексерудегі қате: 5.37 тармақ
сол модель уақыт бойынша кесуде: 35.99 тармақ
train_test_split деректі араластырады — әдепкі күйінде әрі сұрамай. Клиенттер кестесінде бұл дұрыс. Уақыт бойынша қатарда бұл — бұрмалау: 2019 жыл тексеруге түседі, ал 2018 бен 2020 үйретуде қалады, әрі модель 2019-ды болжамайды, оны екі белгілі нүктенің арасына қыстырады. «Әрі қарай не болады» есебі «ортасында не болды» есебіне айналады, ал бұл әлдеқайда оңай.
Оның үстіне кездейсоқ кесуде модель болашақты көреді: үйретуге тексеру жылдарынан кейінгі жылдар түседі. Нағыз жұмыста олай ешқашан болмайды, әрі 5.37 деген цифр — модель бірде-бір рет орындай алмайтын уәде.
Ереже: уақыт бойынша қатарды уақыт бойынша кеседі. Соңғы жылдар — тексеру, тек солар.
Қайта оқып кету тексеру болғанда ғана көрінеді
үйретуде тексеруде
1 3.51 60.78
2 2.30 41.22
3 2.13 57.09
5 0.99 116.69
Бесінші дәрежелі көпмүше өткенді дерлік мінсіз сипаттайды — қатесі бір тармақтан аз. Ал көрмеген жылдарында ол 117 тармаққа қателеседі: ол қатардың пішінін емес, оның жекелеген, тіпті кездейсоқ бөлшектерін жаттап алған.
Міне, қайта оқып кету деген осы, әрі байқаңыз: сол жақ бағаннан оны көру мүмкін емес. Онда бәрі жақсаруға ұқсайды. Қайта оқып кету — модельдің қарап көруге болатын қасиеті емес; бұл екі бағанның арасындағы айырма.
Валидация бойынша таңдап, тестіні соңына қалдырады
үйрету бойынша ең жақсы дәреже: 5 — тексерудегі қатесі 116.69
тексеру бойынша ең жақсы дәреже: 2 — тексерудегі қатесі 41.22
Модельді өткенді қалай сипаттағанына қарап таңдасаңыз, таңдау бардың ішіндегі ең нашарына түседі. Тапсырмада айырма санмен саналады: 75 тармақ — бір қате өлшемнің бағасы.
Әрі бөлек: пішіні дұрыс логарифмдегі түзу тексеруде 35.99 береді әрі барлық көпмүшені ұтады. Пішін күрделіліктен маңызды — өткен сабақтағы сол қорытынды, тек енді ол модель көрмеген деректе алынды.
Бұл есеп нені істей алмайды
Тексеру жылдары төртеу. Бұл нөлден жақсы, бірақ бәрібір аз: олардың арасына 2022-нің орнына бір тыныш жыл түссе, сандар басқа болар еді. Мұндай тексеруден шығатын адал қорытынды — «модель ондаған тармаққа қателеседі», «модель 35.99-ға қателеседі» емес.
Бұл оқу мысалында соңғы төрт жыл модель түрін таңдау үшін валидация ретінде қолданылады. Мұндай таңдаудан кейін тәуелсіз тест қалмайды, сондықтан бұл қателерді сапаның түпкілікті бағасы деуге болмайды. Нақты жұмыста тест кезеңін бөлек қалдырып, модель таңдалғаннан кейін оған бір-ақ рет қарайды.
Әрі осы сабақтан бастап есте ұстайтын тағы бір нәрсе: валидация жылдары жұмсалады. Тексеруге қарап модель іріктей берсеңіз, оны он рет қайталасаңыз, тексеру бірте-бірте үйретуге айналады — жай ғана баяуырақ жолмен.
Сабақ картасы
Өз сөзіңізбен айтыңыз
Қарамай, дауыстап немесе қағазға жауап беріңіз. Жауаптар — сабақтың соңында.
- Үйретудегі қате тексерудегі қатеден неге дерлік әрқашан аз?
- Уақыт бойынша қатарда кездейсоқ кесудің несі жаман?
- Қайта оқып кету екі бағанда қалай көрінеді?
Жаттығу
Тапсырмаға дейінгі үш қысқа қадам: болжау, толықтыру, түзету. Жауаптар — сабақтың соңында, бірақ алдымен өзіңіз жауап беріңіз.
1. Болжаңыз. Тексеруге қандай жылдар түседі әрі олар қатар тұра ма?
import numpy as np
from sklearn.model_selection import train_test_split
years = np.arange(2010, 2026)
train, test = train_test_split(years, test_size=4, random_state=0)
print("тексеру жылдары:", [int(y) for y in sorted(test)])
print("қатар тұр ма:", sorted(int(y) for y in test) == list(range(2022, 2026)))
2. Бос орынды толтырыңыз. ... орнына соңғы төрт жылды ешқандай кездейсоқтықсыз бөліңіз.
# соңғы төрт жыл — тексеруге, қалғаны — үйретуге
import numpy as np
years = np.arange(2010, 2026)
past = ...
print("үйрету:", int(years[past].min()), "-", int(years[past].max()))
print("тексеру:", [int(y) for y in years[~past]])
3. Түзетіңіз. Бағдарлама бір қате басып шығарады да, оны модельдің сапасы деп атайды.
# модельдің сапасы — бір қате емес, екі қате
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
years = np.arange(2010, 2026).reshape(-1, 1)
values = np.array([100.0, 108.45, 114.09, 120.87, 129.15, 137.77, 157.56, 169.28,
179.72, 189.3, 202.02, 218.27, 251.07, 287.54, 312.53, 348.12])
model = LinearRegression().fit(years, values)
print("қате:", round(mean_absolute_error(values, model.predict(years)), 2))
Тапсырма
Міндетті. Қатарды уақыт бойынша кесіңіз: соңғы төрт жыл — тексеруге. Екі бөліктің құрамын басып шығарыңыз әрі бөлек жолмен бірде-бір жылдың екеуіне де түспегеніне көз жеткізіңіз. Логарифм бойынша түзуді үйретіп, екі қатені де және тексерудің неше есе нашар екенін басыңыз. Сосын көпмүшенің біріншіден бесінші дәрежесіне дейін жүріп өтіп, екі қатенің кестесін басыңыз; үйрету бойынша таңдалған дәрежені, тексеру бойынша таңдалған дәрежені және қате таңдаудың тармақпен бағасын атаңыз. Соңында кесуді үш түрлі тұқыммен кездейсоқ қайталап, қателерді адалының қасында көрсетіңіз.
Күтілетін шығыс:
== Уақыт бойынша кесу
үйрету: [2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021]
тексеру: [2022, 2023, 2024, 2025]
екі бөлікке де түскен жылдар: жоқ
логарифм бойынша түзу: үйрету 2.48 — тексеру 35.99
тексеру 14.5 есе нашар
== Көпмүшенің дәрежелері
үйретуде тексеруде
дәреже
1 3.51 60.78
2 2.30 41.22
3 2.13 57.09
4 2.13 52.01
5 0.99 116.69
үйрету бойынша таңдау: 5 — тексеруде ол береді 116.69
тексеру бойынша таңдау: 2 — тексеруде ол береді 41.22
қате таңдаудың бағасы: 75.47 тармақ
== Кездейсоқ кесу, үш әрекет
seed 0: тексеру жылдары [2011, 2016, 2018, 2019] — қате 5.37
seed 1: тексеру жылдары [2012, 2013, 2017, 2023] — қате 4.54
seed 42: тексеру жылдары [2010, 2011, 2015, 2024] — қате 7.68
уақыт бойынша: 35.99 — әрі бұл жалғыз адал цифр
Дайын болғаны: шығыс жол-жолымен сәйкес келеді; ағып кетуді тексеру әрқашан басылады, ағып кету болғанда ғана емес; дәрежені екі өлшемнің әрқайсысы бойынша бөлек код таңдайды; кездейсоқ кесулер анық көрсетілген тұқымдармен жасалады, әйтпесе сандар қайталанбайды.
Өз деректеріңізде. Уақыт бойынша өз қатарыңызды алып, соңғы бестен бірін кесіңіз. Бірінші бөлікте кез келген нәрсені — тіпті орташаны — үйретіп, екінші бөліктегі қатеге қараңыз. Ол дерлік әрқашан бұрын көргеніңізден байқарлық үлкен болып шығады, әрі бұл қалыпты: сіз бірінші рет өзіңіз өлшемек болғанды өлшедіңіз.
Қалауыңыз бойынша.
- Кесу шекарасын 2019 жылға жылжытып, екі қатенің қалай өзгеретінін қараңыз: тексеру ұзарады, ал 2022 оған түседі.
- Модельді жылжымалы тереземен тексеріңіз: N жылға дейін үйретіп, N + 1 туралы сұраңыз, әрі бұны барлық N үшін. Бір санның орнына қателер қатары шығады.
train_test_split(..., shuffle=False)не істейтінін қараңыз: кесу рет бойынша болады, әрі бұл — дайындардың ішіндегі адалға ең жақыны.
Жобада бұл қайда тұрады
Жиырма үшінші қадам: жиынтық өз моделінен ол көрмеген жыл туралы сұрайды.
esep.trend енді түзуді екінші рет — соңғы жылсыз — үйретеді де, сол жыл туралы сұрайды. Бетте екі қате де тұр: Қазақстан өз жылдарында 3.55, бөтен жылда 4.85; Өзбекстан 1.02 және 2.56. Ресейде керісінше: 2.95 және 1.32, көрмеген жылында дәлірек. Тексеру нүктесі біреу болғанда солай болады, әрі бағанның «нағыз қате» деп аталмауының себебі де сол: бір қалдырылған жыл — тексерудің басы, үкім емес.
Болжам бұрынғысынша жоқ. Белгілі жылға бес тармақ қателесетін түзу белгісіз жыл туралы сыпайы сұрағаннан сенімді бола қалмайды.
Қосымша, бұл қадамда қойма түзетілді. saqtau.save мөлшерлемелерді үтірден кейін екі таңбамен жазатын, әрі сол бір есеп желіге барған жүрісте 3.55, файлды оқыған жүрісте 3.56 дейтін. Инфляция мөлшерлемесіне екі таңба жетеді, он алты осындай мөлшерлеме арқылы өткен түзуге — жетпейді. Жауапты өзгертетін қойма — қойма емес.
Жауаптар
Жауаптарды көрсету
Сұрақтарға
- Өйткені үйретуде модель өз коэффициенттерін дәл сол нүктелерге іріктеді — ол жауаптарды көрген. Тексеруде ол алғаш рет жауап береді. Бір жарым-екі еселік алшақтық қалыпты; мұндағыдай он төрт еселік алшақтық модельдің заңдылықты емес, өткенді сипаттағанын білдіреді.
- Араластыру тексеру жылын белгілі жылдардың арасына қоятынымен, әрі «болжау» есебі «жетіспейтінді қыстыру» есебіне ауысады. Оның үстіне үйретуге шын мәнінде тексеру жылдарынан кейін келетін жылдар түседі — модель болашақты көреді. Цифр әдемі әрі орындалмайтын болып шығады.
- Сол жақ баған түседі, оң жағы өседі. Сол жақ баған бөлек алғанда қайта оқып кету туралы ештеңе айтпайды: бесінші дәрежеде ол бәрінен жақсы, ал тексеруде сол модель бәрінен нашар.
Жаттығуға
train_test_splitәдепкі күйінде араластырады, сондықтан жылдар бүкіл қатарға шашырайды әрі қатар тұрмайды.
тексеру жылдары: [2011, 2016, 2018, 2019]
қатар тұр ма: False
years <= 2021. Кездейсоқтық емес, жылмен салыстыру: кесу шекарасы кодта көрініп тұр әрі жүрістен жүріске өзгермейді.
# соңғы төрт жыл — тексеруге, қалғаны — үйретуге
import numpy as np
years = np.arange(2010, 2026)
past = years <= 2021
print("үйрету:", int(years[past].min()), "-", int(years[past].max()))
print("тексеру:", [int(y) for y in years[~past]])
үйрету: 2010 - 2021
тексеру: [2022, 2023, 2024, 2025]
- Модель бүкіл қатарда үйренген, сондықтан басылған қате — үйретудегі қате. Қатарды кесіп, екеуін де басу керек.
# қатені модель көрмеген жылдарда өлшейді
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
years = np.arange(2010, 2026).reshape(-1, 1)
values = np.array([100.0, 108.45, 114.09, 120.87, 129.15, 137.77, 157.56, 169.28,
179.72, 189.3, 202.02, 218.27, 251.07, 287.54, 312.53, 348.12])
past = (years <= 2021).ravel()
model = LinearRegression().fit(years[past], values[past])
print("үйретуде:", round(mean_absolute_error(values[past], model.predict(years[past])), 2))
print("тексеруде:", round(mean_absolute_error(values[~past], model.predict(years[~past])), 2))
үйретуде: 3.51
тексеруде: 60.78
Тапсырмаға
Ағып кету туралы жол әрқашан басылады — әрі бұл формалдылық емес. Ағып кету сирек қате сияқты көрінеді: код жұмыс істейді, сандар әдемі шығады, әрі жалғыз белгі — олардың тым әдемі екені. Әр жолы «жоқ» деп басатын тексеру арзан тұрады, ал өзгеше табылмайтынды табады.
Үш кездейсоқ кесу 5.37, 4.54 және 7.68 береді — үшеуі де адал 35.99-дан бірнеше есе аз. Олардың өзара да сәйкес келмейтініне назар аударыңыз: тұқымға цифрдың әдемілігі ғана емес, цифрдың өзі де тәуелді. Нәтиже кездейсоқ санға тәуелді болса, оны сол санмен бірге басады.
Дереккөздер
- train_test_split, scikit-learn — осының бәрі содан болатын
shuffleменrandom_stateпараметрлері. - Уақыт қатарларындағы кросс-валидация, scikit-learn —
TimeSeriesSplit, дайын уақыт бойынша кесу. - Тұтыну бағасының индексі, Дүниежүзілік банк — сабақ тұрғызылған қатар.
Пікірлер (0)
Пікір қалдыру үшін кіріңіз →
Әзірге пікір жоқ. Бірінші болыңыз.