Зеҳн
Омӯзиши мошинӣ ва амиқ

Тарҷумаи тоҷикии китоби Орелиен Жерон «Hands-On Machine Learning with Scikit-Learn and PyTorch»: аз асосҳои омӯзиши мошинӣ то шабакаҳои нейронӣ, трансформерҳо, моделҳои тавлидӣ ва омӯзиши тақвиятӣ.

Агенти Зеҳнӣ · 13 ноябри 2026 · 20 саҳифа · 1 писанд

ИлмБарномасозӣТехнология
Аз аввал хондан

Боби 2. Лоиҳаи омӯзиши мошинӣ аз оғоз то анҷом

Дар ин боб як лоиҳаи намунавиро аз оғоз то анҷом иҷро мекунед ва худро мутахассиси илми додаҳо тасаввур мекунед, ки ба тозагӣ дар ширкати амволи ғайриманқул ба кор гирифта шудааст. Ин мисол сохта аст: мақсад нишон додани қадамҳои асосии лоиҳаи омӯзиши мошинӣ мебошад, на омӯзиши тиҷорати амволи ғайриманқул. Қадамҳои асосӣ чунинанд:

  1. Ба тасвири умумӣ назар кунед.
  2. Додаҳоро ба даст оред.
  3. Барои дарки беҳтар додаҳоро таҳқиқ ва тасвирсозӣ кунед.
  4. Додаҳоро барои алгоритмҳои омӯзиши мошинӣ омода созед.
  5. Моделро интихоб ва омӯзонед.
  6. Моделро танзими дақиқ кунед.
  7. Роҳи ҳалли худро пешниҳод намоед.
  8. Системаро ба кор дароред, назорат кунед ва нигоҳ доред.

Кор бо додаҳои воқеӣ

Ҳангоми омӯхтани омӯзиши мошинӣ беҳтар аст бо додаҳои воқеӣ таҷриба кунед, на бо маҷмӯаҳои сунъӣ. Хушбахтона, ҳазорон маҷмӯи кушода дар соҳаҳои гуногун дастрасанд. Инҳо чанд манбаи маъмули додаҳои кушодаанд:

  • Google Datasets Search;
  • Hugging Face Datasets;
  • OpenML.org;
  • Kaggle.com;
  • анбори омӯзиши мошинии Донишгоҳи Калифорния дар Ирвайн — UC Irvine Machine Learning Repository;
  • маҷмӯи шабакаҳои бузурги Стэнфорд — Stanford Large Network Dataset Collection;
  • маҷмӯаҳои додаҳои AWS-и Amazon;
  • додаҳои кушодаи Ҳукумати ИМА;
  • DataPortals.org;
  • рӯйхати маҷмӯаҳои омӯзиши мошинӣ дар Википедия.

Дар ин боб маҷмӯи нархҳои манзил дар Калифорния аз анбори StatLib-ро истифода мебарем (расми 2.1). Он ба барӯйхатгирии аҳолии соли 1990-и Калифорния асос ёфтааст. Додаҳо чандон нав нестанд — он замон ҳанӯз харидани хонаи хуб дар минтақаи халиҷ имконпазиртар буд — аммо барои омӯзиш бартариҳои зиёд доранд. Аз ин рӯ, вонамуд мекунем, ки додаҳо наванд. Бо мақсади таълим ман як атрибути категориявӣ илова карда, чанд хусусиятро хориҷ намудам.

Харитаи нархҳои манзил дар Калифорния

Расми 2.1. Нархҳои манзил дар Калифорния.

Ба тасвири умумӣ назар кунед

Ба ширкати Machine Learning Housing Corporation хуш омадед! Вазифаи аввалини шумо сохтани модели нархҳои манзил дар Калифорния бо истифодаи додаҳои барӯйхатгирии аҳолии ин иёлат аст. Додаҳо барои ҳар гурӯҳи блокҳои Калифорния нишондиҳандаҳое чун аҳолӣ, медианаи даромад ва медианаи нархи манзилро дар бар мегиранд. Гурӯҳи блокҳо хурдтарин воҳиди ҷуғрофиест, ки Идораи барӯйхатгирии аҳолии ИМА барои он додаҳои намунавӣ нашр мекунад. Одатан чунин гурӯҳ аз 600 то 3 000 нафар аҳолӣ дорад. Барои кӯтоҳӣ онҳоро «ноҳияҳо» меномам.

Модели шумо бояд аз ин додаҳо омӯзад ва бо гирифтани дигар нишондиҳандаҳо медианаи нархи манзилро дар ҳар ноҳия пешгӯӣ карда тавонад.

Маслиҳат. Ҳамчун мутахассиси ботартиби илми додаҳо аввал рӯйхати санҷиши лоиҳаи омӯзиши мошиниро омода кунед. Метавонед аз ин рӯйхат оғоз кунед: он барои аксари лоиҳаҳо муносиб аст, аммо ҳатман ба ниёзҳои худ мутобиқаш созед. Дар ин боб бандҳои зиёди рӯйхатро дида мебароем, вале аз баъзеашон сарфи назар мекунем, зеро ё худ аз худ равшананд ё дар бобҳои баъдӣ баррасӣ мешаванд.

Масъаларо муайян кунед

Аввал аз роҳбар пурсед, ки ҳадафи дақиқи тиҷоратӣ чист. Эҳтимол сохтани модел ҳадафи ниҳоӣ нест. Ширкат онро чӣ гуна истифода бурдан ва аз он фоида гирифтан мехоҳад? Донистани ҳадаф муҳим аст, зеро муайян мекунад, ки масъаларо чӣ гуна мегузоред, кадом алгоритмҳоро интихоб мекунед, самаранокиро бо кадом меъёр арзёбӣ мекунед ва барои танзим чӣ қадар кӯшиш сарф мекунед.

Роҳбар мегӯяд, ки баромади модел — пешгӯии медианаи нархи манзили ноҳия — барои муайян кардани арзанда будани сармоягузорӣ дар минтақаи муайян муҳим аст. Мушаххастар, ин баромад бо чанд сигнали дигар ба системаи дигари омӯзиши мошинӣ дода мешавад (расми 2.2). Пас, модели нархи манзил бояд то ҳадди имкон дуруст кор кунад.

Саволи навбатӣ ин аст, ки роҳи ҳалли ҳозира, агар вуҷуд дошта бошад, чӣ гуна аст. Вазъияти мавҷуда одатан ҳам нуқтаи муқоисаи самаранокӣ медиҳад ва ҳам дар бораи ҳалли масъала фаҳмиш меорад. Роҳбар мегӯяд, ки ҳоло коршиносон нархҳоро дастӣ тахмин мекунанд: гурӯҳ маълумоти нави ноҳияро ҷамъ мекунад ва агар медианаи нархи манзилро наёбад, онро бо қоидаҳои мураккаб тахмин менамояд.

Пайплайни омӯзиши мошинӣ барои сармоягузорӣ

Расми 2.2. Пайплайни омӯзиши мошинӣ барои сармоягузорӣ ба амволи ғайриманқул.

Ин кор гарону вақтталаб аст ва тахминҳо чандон хуб нестанд: вақте медианаи воқеии нарх маълум мешавад, аксар вақт мебинанд, ки тахминашон бештар аз 30 фоиз хато будааст. Аз ин рӯ, ширкат омӯзонидани моделеро муфид мешуморад, ки медианаи нархи манзилро аз рӯйи дигар додаҳои ноҳия пешгӯӣ кунад. Додаҳои барӯйхатгирӣ барои ин мақсад хеле мувофиқ менамоянд, зеро медианаи нархи манзил ва маълумоти дигари ҳазорон ноҳияро доранд.

Пайплайнҳо

Пайдарпайии ҷузъҳои коркарди додаҳо пайплайни додаҳо (data pipeline) ном дорад. Пайплайнҳо дар системаҳои омӯзиши мошинӣ хеле маъмуланд, зеро бо додаҳои зиёд ва табдилҳои гуногун кор кардан лозим меояд.

Ҷузъҳо одатан асинхронӣ кор мекунанд. Ҳар ҷузъ ҳаҷми зиёди додаҳоро мегирад, коркард мекунад ва натиҷаро дар анбори дигар мегузорад. Баъд аз муддате ҷузъи навбатӣ он додаҳоро гирифта, натиҷаи худро мебарорад. Ҳар ҷузъ нисбатан мустақил аст: робитаи байни ҷузъҳо танҳо тавассути анбори додаҳост. Бо ёрии графи ҷараёни додаҳо фаҳмидани система осон мешавад ва гурӯҳҳои гуногун метавонанд ба ҷузъҳои гуногун диққат диҳанд. Агар як ҷузъ вайрон шавад, ҷузъҳои баъдӣ аксар вақт бо истифодаи охирин баромади он, ҳадди ақал муддате, кори муқаррариро идома медиҳанд. Ин меъмориро устувор месозад.

Аммо агар назорати дуруст набошад, вайроншавии ҷузъ метавонад муддате ноаён монад. Додаҳо куҳна шуда, самаранокии умумии система паст мешавад.

Бо ин маълумот акнун омодаед тарҳрезии системаро оғоз кунед. Аввал муайян намоед, ки модел ба кадом навъи назорат ниёз дорад: омӯзиши бо назорат, беназорат, ниманазоратӣ, худназоратӣ ё тақвиятӣ? Вазифа таснифбандӣ аст, регрессия ё чизи дигар? Омӯзиши дастаиро истифода мебаред ё онлайнро? Пеш аз идома таваққуф карда, худатон ҷавоб диҳед.

Ҷавобҳоро ёфтед? Ин равшан вазифаи маъмулии омӯзиши бо назорат аст, зеро моделро бо намунаҳои барчаспдор меомӯзонем: ҳар намуна баромади интизорӣ, яъне медианаи нархи манзили ноҳияро дорад. Ин регрессия аст, зеро бояд қиматеро пешгӯӣ кунем. Дақиқтар, масъалаи регрессияи чандомила (multiple regression) аст: система барои пешгӯӣ чанд хусусият — аҳолӣ, медианаи даромад ва ғайра — истифода мебарад. Ҳамчунин регрессияи якбаромада (univariate regression) аст, зеро барои ҳар ноҳия танҳо як қимат пешгӯӣ мекунем. Агар барои ҳар ноҳия чанд қимат пешгӯӣ мекардем, регрессияи чандбаромада (multivariate regression) мешуд. Ниҳоят, ҷараёни доимии додаҳои воридшаванда вуҷуд надорад, мутобиқшавии фаврӣ ба тағйирот зарур нест ва додаҳо дар хотира меғунҷанд. Пас, омӯзиши одии дастаӣ мувофиқ аст.

Маслиҳат. Агар додаҳо азим мебуданд, метавонистед омӯзиши дастаиро бо усули MapReduce байни чанд сервер тақсим кунед ё омӯзиши онлайнро истифода баред.

Меъёри самаранокиро интихоб кунед

Қадами оянда интихоби меъёри самаранокист. Меъёри маъмули масъалаҳои регрессия решаи миёнаи квадратҳои хато (RMSE) мебошад. Он нишон медиҳад, ки система дар пешгӯиҳо одатан чӣ қадар хато мекунад ва ба хатоҳои калон вазни бештар медиҳад. Муодилаи 2.1 формулаи онро нишон медиҳад.

Муодилаи 2.1. Решаи миёнаи квадратҳои хато (RMSE).

RMSE(X, y, h) = √((1 / m) · Σᵢ₌₁ᵐ (h(x⁽ⁱ⁾) − y⁽ⁱ⁾)²).

Аломатгузорӣ

Дар ин муодила чанд аломати хеле маъмули омӯзиши мошинӣ ҳаст, ки дар тамоми китоб истифода мешаванд:

  • m шумораи намунаҳо дар маҷмӯаест, ки RMSE-и онро чен мекунед. Масалан, барои маҷмӯи тасдиқии 2 000 ноҳия m = 2 000 аст.
  • x⁽ⁱ⁾ вектори ҳамаи қиматҳои хусусиятҳои намунаи i-ум, бе барчасп, ва y⁽ⁱ⁾ барчасп, яъне баромади дилхоҳи он аст. y вектори барчаспҳои тамоми намунаҳост.

Масалан, агар ноҳияи аввал дар тӯли ҷуғрофии −118,29° ва арзи 33,91° ҷойгир бошад, 1 416 аҳолӣ, медианаи даромади 38 372 доллар ва медианаи нархи манзили 156 400 доллар дошта бошад, бо нодида гирифтани хусусиятҳои дигар дорем:

       ⎡ −118.29 ⎤
       ⎢   33.91 ⎥
x⁽¹⁾ = ⎢    1416 ⎥
       ⎣   38372 ⎦

y⁽¹⁾ = 156400.

  • X матритсаи қиматҳои ҳамаи хусусиятҳои ҳамаи намунаҳо, бе барчаспҳост. Барои ҳар намуна як сатр дорад ва сатри i-ум ба транспозаи x⁽ⁱ⁾, яъне (x⁽ⁱ⁾)ᵀ баробар аст. Барои ноҳияи мисоли боло оғози матритса чунин аст:
    ⎡ −118.29   33.91   1416   38372 ⎤
X = ⎣    ⋮        ⋮       ⋮      ⋮   ⎦.
  • h функсияи пешгӯии система аст, ки гипотеза низ ном дорад. Вақте ба система вектори хусусиятҳои x⁽ⁱ⁾-ро медиҳед, қимати пешгӯишудаи ŷ⁽ⁱ⁾ = h(x⁽ⁱ⁾)-ро мебарорад. ŷ-ро «игрек бо кулоҳ» мехонанд. Масалан, агар барои ноҳияи аввал 158 400 доллар пешгӯӣ шавад, ŷ⁽¹⁾ = h(x⁽¹⁾) = 158 400 аст. Хатои пешгӯӣ ŷ⁽¹⁾ − y⁽¹⁾ = 2 000 мебошад.
  • RMSE(X, y, h) функсияи хароҷотест, ки бо гипотезаи h дар маҷмӯи намунаҳо чен шудааст.

Барои қиматҳои скалярӣ, масалан m ё y⁽ⁱ⁾, ва номҳои функсияҳо, масалан h, ҳарфҳои хурди моил; барои векторҳо ҳарфҳои хурди ғафс; барои матритсаҳо ҳарфҳои калони ғафс истифода мекунем.

Ҳарчанд RMSE одатан меъёри бартаридодашудаи регрессия аст, баъзан функсияи дигар муносибтар мешавад, махсусан ҳангоми зиёд будани қиматҳои дур, зеро RMSE ба онҳо ҳассос аст. Он гоҳ метавон миёнаи хатои мутлақ (MAE), ки миёнаи дуршавии мутлақ низ ном дорад, истифода бурд.

Муодилаи 2.2. Миёнаи хатои мутлақ (MAE).

MAE(X, y, h) = (1 / m) · Σᵢ₌₁ᵐ |h(x⁽ⁱ⁾) − y⁽ⁱ⁾|.

RMSE ва MAE роҳҳои чен кардани фосилаи байни ду вектор — пешгӯиҳо ва қиматҳои ҳадаф — мебошанд. Меъёрҳои фосила ё норма-ҳои гуногун вуҷуд доранд:

  • Гирифтани решаи ҷамъи квадратҳо, ки асоси RMSE аст, ба нормаи эвклидӣ мувофиқ меояд: ҳамон фосилаи ба ҳамаи мо шинос. Он нормаи ℓ₂ низ ном дорад ва бо ∥·∥₂ ё танҳо ∥·∥ ишора мешавад.
  • Ҷамъи қиматҳои мутлақ, ки асоси MAE аст, ба нормаи ℓ₁, бо аломати ∥·∥₁, мувофиқ аст. Онро баъзан нормаи Манҳэттен мегӯянд, зеро масофаи байни ду нуқтаи шаҳрро ҳангоми ҳаракат танҳо аз рӯйи кӯчаҳои ба ҳам амудӣ чен мекунад.
  • Умуман, барои вектори v бо n унсур:

∥v∥ₖ = (|v₁|ᵏ + |v₂|ᵏ + ⋯ + |vₙ|ᵏ)^(1/k).

ℓ₀ шумораи унсурҳои ғайрисифрӣ ва ℓ∞ бузургтарин қимати мутлақи векторро медиҳад.

Ҳар қадар индекси норма баланд бошад, ҳамон қадар ба қиматҳои калон бештар ва ба қиматҳои хурд камтар диққат медиҳад. Аз ҳамин сабаб RMSE нисбат ба MAE ба қиматҳои дур ҳассостар аст. Аммо вақте қиматҳои дур ба таври экспоненсиалӣ камёбанд, масалан дар тақсимоти зангӯлашакл, RMSE хеле хуб кор мекунад ва одатан онро афзал медонанд.

Фарзияҳоро санҷед

Дар охир, хуб аст ҳамаи фарзияҳои то ин ҷо аз тарафи шумо ё дигарон гузошташударо рӯйхат карда, санҷед. Ин метавонад мушкилоти ҷиддиро барвақт ошкор кунад. Масалан, нархҳои баровардаи система ба системаи дигари омӯзиши мошинӣ дода мешаванд ва шумо фарз мекунед, ки онҳо айнан ҳамчун нарх истифода мешаванд. Аммо агар системаи баъдӣ нархҳоро ба гурӯҳҳои «арзон», «миёна» ва «гарон» табдил дода, танҳо ҳамин категорияҳоро истифода барад, чӣ? Он гоҳ нархи комилан дуруст муҳим нест: система танҳо бояд категорияро дуруст ёбад. Пас масъала бояд ҳамчун таснифбандӣ гузошта мешуд, на регрессия. Намехоҳед инро баъд аз чанд моҳи кор бо системаи регрессия фаҳмед.

Хушбахтона, пас аз суҳбат бо гурӯҳи масъули системаи баъдӣ мутмаин мешавед, ки онҳо воқеан ба нархҳои аслӣ ниёз доранд, на танҳо категорияҳо. Акнун ҳама чиз омода аст ва метавонед рамзнависиро оғоз кунед!

Додаҳоро ба даст оред

Вақти кори амалӣ расид. Ноутбукро гиред ва мисолҳои рамзиро якҷо иҷро кунед. Чунон ки дар пешгуфтор гуфтам, ҳамаи мисолҳои китоб рамзи кушода доранд ва онлайн дар шакли дафтарҳои Jupyter дастрасанд: ҳуҷҷатҳои интерактивии дорои матн, тасвир ва порчаҳои рамзи иҷрошаванда, дар ин ҷо Python. Дар китоб фарз мекунем онҳоро дар Google Colab иҷро мекунед: хидмати ройгоне, ки имкон медиҳад дафтари Jupyter-ро бевосита онлайн, бе насби чизе дар компютер, иҷро кунед. Агар платформаи дигар, масалан Kaggle, ё насби маҳаллиро хоҳед, ба дастури саҳифаи GitHub-и китоб нигаред.

Иҷрои мисолҳо бо Google Colab

Аввал браузерро кушода, ба homl.info/colab-p равед. Он шуморо ба Google Colab мебарад ва рӯйхати дафтарҳои китобро нишон медиҳад (расми 2.3). Барои ҳар боб як дафтар ва чанд дафтару дарси иловагӣ барои NumPy, Matplotlib, Pandas, алгебраи хаттӣ ва ҳисоби дифференсиалӣ ҳаст. Масалан, бо пахши 02_end_to_end_machine_learning_project.ipynb дафтари боби 2 кушода мешавад (расми 2.4).

Дафтари Jupyter аз рӯйхати ҳуҷайраҳо (cells) иборат аст. Ҳар ҳуҷайра рамзи иҷрошаванда ё матн дорад. Ба ҳуҷайраи аввали матнӣ, ки ҷумлаи «Welcome to Machine Learning Housing Corp.!»-ро дорад, ду бор пахш кунед. Он барои вироиш кушода мешавад. Jupyter барои шаклбандӣ синтаксиси Markdown-ро истифода мебарад: масалан **ғафс**, *моил*, # Сарлавҳа ва [матни пайванд](URL). Матнро тағйир дода, Shift-Enter-ро пахш кунед, то натиҷаро бинед.

Расми 2.3. Рӯйхати дафтарҳо дар Google Colab.

Расми 2.4. Дафтари шумо дар Google Colab.

Баъд аз меню Insert → Code cell-ро интихоб карда, ҳуҷайраи рамзии нав созед. Ҳамчунин метавонед тугмаи + Code-ро дар лавҳаи асбобҳо пахш кунед ё мушро ба поёни ҳуҷайра бурда, аз тугмаҳои пайдошудаи + Code ва + Text тугмаи + Code-ро интихоб намоед. Дар ҳуҷайраи нав рамзе мисли print("Hello World") нависед ва Shift-Enter ё тугмаи ▷-ро дар чапи ҳуҷайра пахш кунед.

Агар ба ҳисоби Google ворид нашуда бошед, аз шумо воридшавиро мепурсанд. Агар ҳисоб надошта бошед, бояд созед. Баъди воридшавӣ ҳангоми иҷрои рамз огоҳии амниятӣ мебинед, ки дафтар аз тарафи Google навишта нашудааст. Шахси бадхоҳ метавонад дафтаре созад, ки шуморо барои гирифтани дастрасӣ ба додаҳои шахсӣ ба ворид кардани маълумоти ҳисоби Google фиреб диҳад. Аз ин рӯ, пеш аз иҷро ҳамеша бовар ҳосил кунед, ки ба муаллиф эътимод доред ё кори ҳар ҳуҷайраро пешакӣ санҷед. Агар ба ман эътимод доред ё ҳар ҳуҷайраро месанҷед, Run anyway-ро пахш кунед.

Colab барои шумо муҳити иҷро (runtime) ҷудо мекунад: мошини виртуалии ройгон дар серверҳои Google, ки воситаҳо ва китобхонаҳои Python, аз ҷумла аксари чизҳои барои бобҳо заруриро дорад. Дар баъзе бобҳо китобхонаҳои иловагиро бо фармон насб мекунед. Ин чанд сония мегирад. Сипас Colab худкор ба он пайваст шуда, рамзро иҷро мекунад. Рамз дар ҳамон муҳит иҷро мешавад, на дар компютери шумо. Натиҷа зери ҳуҷайра пайдо мешавад. Табрик, шумо дар Colab рамзи Python иҷро кардед!

Маслиҳат. Барои илова кардани ҳуҷайраи рамзӣ Ctrl-M, дар macOS Cmd-M, ва баъд A-ро барои гузоштан болои ҳуҷайраи фаъол ё B-ро барои гузоштан поёни он пахш кунед. Миёнабурҳои дигарро бо Ctrl-M ё Cmd-M ва баъд H дидан ва тағйир додан мумкин аст. Дар Kaggle, JupyterLab ё муҳаррире мисли Visual Studio Code бо васеъкунии Jupyter фарқиятҳои хурд ҳастанд: муҳитҳои иҷро «ядро» ё kernel ном доранд, интерфейс ва миёнабурҳо каме фарқ мекунанд. Аммо гузаштан аз як муҳити Jupyter ба дигаре душвор нест.

Нигоҳ доштани тағйироти рамз ва додаҳо

Тағйироти дафтари Colab то вақте варақаи браузер кушода аст, боқӣ мемонанд. Пас аз бастани он гум мешаванд. Барои пешгирӣ бо File → Save a copy in Drive нусхаро дар Google Drive нигоҳ доред. Ё бо File → Download → Download .ipynb дафтарро ба компютер боргирӣ кунед. Баъдтар метавонед ба colab.research.google.com рафта, онро аз Google Drive ё бо боргузорӣ аз компютер боз кунед.

Огоҳӣ. Google Colab танҳо барои истифодаи интерактивӣ пешбинӣ шудааст: метавонед бо дафтарҳо таҷриба карда, рамзро тағйир диҳед, аммо онҳоро муддати тӯлонӣ бе назорат дар ҳолати иҷро гузошта наметавонед. Дар акси ҳол муҳити иҷро хомӯш мешавад ва ҳамаи додаҳои он гум мегарданд.

Агар дафтар додаҳои муҳим эҷод кунад, онҳоро пеш аз хомӯш шудани муҳит боргирӣ намоед. Нишонаи Files-ро пахш кунед — қадами 1 дар расми 2.5 — файли дилхоҳро ёбед, се нуқтаи амудии паҳлуяшро пахш кунед — қадами 2 — ва Download-ро интихоб кунед — қадами 3. Ё Google Drive-ро ба муҳити иҷро пайваст намоед, то дафтар файлҳоро мисли феҳристи маҳаллӣ мустақиман хондаву навишта тавонад. Барои ин Files ва баъд нишонаи Google Drive-ро, ки дар расми 2.5 давр гирифта шудааст, пахш карда, дастури экранро иҷро кунед.

Расми 2.5. Боргирии файл аз муҳити иҷрои Google Colab — қадамҳои 1–3 — ё пайваст кардани Google Drive — нишонаи давргирифта.

Одатан Drive дар /content/drive/MyDrive пайваст мешавад. Барои нусхаи эҳтиётии додаҳо онҳоро ба ин феҳрист кӯчонед:

!cp /content/my_great_model /content/drive/MyDrive

Ҳар фармоне, ки бо ! оғоз мешавад, ҳамчун фармони shell иҷро мешавад, на рамзи Python. cp фармони Linux барои нусхабардории файл аз як роҳ ба роҳи дигар аст. Муҳитҳои Colab дар Linux, мушаххасан Ubuntu, кор мекунанд.

Қудрат ва хатари интерактивӣ

Интерактивӣ будани Jupyter бисёр хуб аст: метавонед ҳуҷайраҳоро яктоӣ иҷро кунед, дар ҳар ҷо таваққуф намоед, ҳуҷайра илова кунед, бо рамз таҷриба кунед, баргардед ва як ҳуҷайраро боз иҷро намоед. Ман инро хеле тавсия медиҳам. Агар танҳо ҳуҷайраҳоро пайдарпай бе таҷриба иҷро кунед, сусттар меомӯзед. Аммо ин чандирӣ нуқсоне дорад: иҷрои ҳуҷайраҳо бо тартиби нодуруст ё фаромӯш кардани яке хеле осон аст. Он гоҳ ҳуҷайраҳои баъдӣ эҳтимол хато медиҳанд. Масалан, ҳуҷайраи аввалини рамзии ҳар дафтар омодасозӣ, аз ҷумла import-ҳоро дорад. Онро ҳатман аввал иҷро кунед, вагарна чизе кор намекунад.

Маслиҳат. Агар хатои аҷибе бинед, аз Runtime → Restart runtime муҳитро бозоғоз карда, ҳамаи ҳуҷайраҳоро аз аввал иҷро кунед. Ин аксар вақт мушкилро ҳал мекунад. Агар не, эҳтимол яке аз тағйироти шумо дафтарро вайрон кардааст: ба нусхаи аслӣ баргашта, боз кӯшиш намоед. Агар ҳанӯз хато бошад, дар GitHub масъала ё issue сабт кунед.

Рамзи китоб ва рамзи дафтар

Баъзан байни рамзи китоб ва дафтар фарқиятҳои хурд мебинед. Сабабҳо метавонанд чунин бошанд:

  • То вақти хондани шумо китобхона каме тағйир ёфтааст ё бо вуҷуди кӯшишҳо дар китоб хато мондааст. Ман рамзи нусхаи китоби шуморо сеҳрнок ислоҳ карда наметавонам, магар нусхаи электронӣ дошта, версияи навро боргирӣ кунед. Аммо дафтарҳоро ислоҳ карда метавонам. Пас, агар рамзи аз китоб гирифташуда хато диҳад, нусхаи ислоҳшударо дар дафтарҳо ҷӯед: кӯшиш мекунам онҳо бехато ва бо версияҳои нави китобхонаҳо мувофиқ бошанд.
  • Дафтарҳо барои зеботар кардани расмҳо — барчаспҳо, андозаи ҳуруф ва ғайра — ва нигоҳдории онҳо бо сифати баланд рамзи иловагӣ доранд. Агар хоҳед, онро нодида гиред.
  • Рамзро барои хондан ва фаҳмидани осон то ҳадди имкон хаттӣ ва ҳамвор, бо функсияву синфҳои кам, навиштаам. Мақсад ин аст, ки рамзи иҷрошаванда пеши чашматон бошад, на дар чанд қабати абстраксия, ки бояд ҷустуҷӯ кунед. Таҷриба кардан ҳам осонтар мешавад. Барои содагӣ коркарди хатоҳо маҳдуд аст ва баъзе import-ҳои камистифодаро дар ҷойи лозим гузоштам, на дар оғози файл, ки дастури услуби Python — PEP 8 — тавсия медиҳад. Рамзи муҳити воқеии шумо аз ин хеле фарқ намекунад: танҳо модулитар буда, санҷишҳо ва коркарди хатоҳои бештар дорад.

Вақте бо Colab роҳат шудед, барои боргирии додаҳо омодаед.

Боргирии додаҳо

Дар муҳитҳои маъмулӣ додаҳо дар пойгоҳи додаҳои релятсионӣ ё анбори дигар буда, байни чанд ҷадвал, ҳуҷҷат ё файл тақсим шудаанд. Барои дастрасӣ аввал маълумоти воридшавӣ ва иҷозатҳои дастрасӣ гирифта, бо схемаи додаҳо шинос мешавед. Аммо дар ин лоиҳа кор осонтар аст: танҳо файли фишурдаи housing.tgz-ро боргирӣ мекунед, ки файли CSV бо номи housing.csv ва ҳамаи додаҳоро дорад.

Ба ҷойи боргирӣ ва бозкушоии дастӣ одатан беҳтар аст функсияе нависед, ки ин корро кунад. Махсусан агар додаҳо мунтазам нав шаванд: скрипти хурде бо он додаҳои навро мегирад ё кори ҷадвалбандишударо барои гирифтани худкор дар фосилаҳои муайян танзим мекунед. Ин худкорсозӣ ҳангоми насби маҷмӯа дар чанд компютер низ муфид аст.

Функсияи гирифтан ва бор кардани додаҳо чунин аст:

from pathlib import Path
import pandas as pd
import tarfile
import urllib.request

def load_housing_data():
    tarball_path = Path("datasets/housing.tgz")
    if not tarball_path.is_file():
        Path("datasets").mkdir(parents=True, exist_ok=True)
        url = "https://github.com/ageron/data/raw/main/housing.tgz"
        urllib.request.urlretrieve(url, tarball_path)
        with tarfile.open(tarball_path) as housing_tarball:
            housing_tarball.extractall(path="datasets", filter="data")
    return pd.read_csv(Path("datasets/housing/housing.csv"))

housing_full = load_housing_data()

Эзоҳ. Агар дар macOS хатои SSL CERTIFICATE_VERIFY_FAILED бинед, эҳтимол бояд бастаи certifi-ро мувофиқи ин дастур насб кунед.

Ҳангоми даъват load_housing_data() файли datasets/housing.tgz-ро меҷӯяд. Агар набошад, дар феҳристи ҷорӣ, ки дар Colab одатан /content аст, феҳристи datasets месозад; файлро аз анбори GitHub-и ageron/data боргирӣ карда, ба datasets мекушояд. Дар натиҷа datasets/housing/housing.csv ҳосил мешавад. Дар охир CSV-ро ба объекти DataFrame-и Pandas бо ҳамаи додаҳо бор карда, бармегардонад.

Эзоҳ. Аргументи filter='data'-и extractall() имкониятҳои алгоритми бозкушоиро маҳдуд карда, амниятро беҳтар месозад. Он аз Python 3.12 ва дар навсозиҳои охири версияҳои пештара (3.10.12, 3.11.4 ва баъд) дастрас аст; дар версияи куҳнатар хатои TypeError медиҳад — он гоҳ ин аргументро нест кунед ё Python-ро нав кунед. Барои тафсилот ба ҳуҷҷатгузорӣ нигаред.

Нигоҳи зуд ба сохтори додаҳо

Аввал бо методи head() панҷ сатри аввали DataFrame-ро мебинед (расми 2.6).

Панҷ сатри аввали маҷмӯи додаҳо

Расми 2.6. Панҷ сатри аввали маҷмӯи додаҳо.

Ҳар сатр як ноҳияро ифода мекунад. Даҳ атрибут ҳаст: longitude — тӯли ҷуғрофӣ, latitude — арзи ҷуғрофӣ, housing_median_age — медианаи синни манзилҳо, total_rooms — шумораи умумии ҳуҷраҳо, total_bedrooms — шумораи умумии ҳуҷраҳои хоб, population — аҳолӣ, households — хонаводаҳо, median_income — медианаи даромад, median_house_value — медианаи арзиши манзил ва ocean_proximity — наздикӣ ба уқёнус.

Методи info() тавсифи кӯтоҳ медиҳад: шумораи умумии сатрҳо, навъи ҳар атрибут ва шумораи қиматҳои ғайрихолӣ:

>>> housing_full.info()

RangeIndex: 20640 entries, 0 to 20639
Data columns (total 10 columns):
 #   Column              Non-Null Count  Dtype
---  ------              --------------  -----
 0   longitude           20640 non-null  float64
 1   latitude            20640 non-null  float64
 2   housing_median_age  20640 non-null  float64
 3   total_rooms         20640 non-null  float64
 4   total_bedrooms      20433 non-null  float64
 5   population          20640 non-null  float64
 6   households          20640 non-null  float64
 7   median_income       20640 non-null  float64
 8   median_house_value  20640 non-null  float64
 9   ocean_proximity     20640 non-null  object
dtypes: float64(9), object(1)
memory usage: 1.6+ MB

Эзоҳ. Дар китоб мисолҳои омехтаи рамзу натиҷа мисли интерпретатори Python шаклбандӣ мешаванд: сатрҳои рамз бо >>> ё барои блокҳои идомадор бо ... оғоз мешаванд; натиҷаҳо чунин пешванд надоранд.

Маҷмӯа 20 640 намуна дорад: барои омӯзиши мошинӣ хурд, аммо барои оғоз комил аст. total_bedrooms танҳо 20 433 қимати ғайрихолӣ дорад, яъне дар 207 ноҳия ин хусусият намерасад. Баъдтар инро ҳал мекунед.

Ҳамаи атрибутҳо ададианд, ғайр аз ocean_proximity. Навъи он object аст ва метавонад ҳар объекти Python-ро нигоҳ дорад. Аммо азбаски додаҳо аз CSV омадаанд, медонед, ки матнист. Дар панҷ сатри аввал қиматҳои такрории ин сутунро дидед; пас эҳтимол категориявӣ аст. Бо value_counts() категорияҳо ва шумораи ноҳияҳои ҳар кадомро меёбед:

>>> housing_full["ocean_proximity"].value_counts()
ocean_proximity
<1H OCEAN     9136
INLAND        6551
NEAR OCEAN    2658
NEAR BAY      2290
ISLAND           5
Name: count, dtype: int64

Барои майдонҳои дигар describe() ҷамъбасти атрибутҳои ададиро медиҳад (расми 2.7).

Ҷамъбасти атрибутҳои ададӣ

Расми 2.7. Ҷамъбасти ҳар атрибути ададӣ.

Сатрҳои count, mean, min ва max шумора, миёна, хурдтарин ва калонтарин қиматҳоро нишон медиҳанд. Қиматҳои холӣ ба ҳисоб намераванд: масалан, count-и total_bedrooms ба 20 433 баробар аст, на 20 640. std инҳирофи стандартиро нишон медиҳад, ки парокандагии қиматҳоро чен мекунад. Сатрҳои 25%, 50% ва 75% персентилҳоянд: персентил қиматест, ки фоизи муайяни мушоҳидаҳо аз он поён ҷойгиранд. Масалан, дар 25 фоизи ноҳияҳо housing_median_age аз 18, дар 50 фоиз аз 29 ва дар 75 фоиз аз 37 камтар аст. Онҳоро персентили 25-ум ё квартили аввал, медиана ва персентили 75-ум ё квартили сеюм меноманд.

Роҳи дигари зуд барои шиносоӣ кашидани гистограммаи ҳар атрибути ададист. Гистограмма дар меҳвари амудӣ шумораи намунаҳо ва дар меҳвари уфуқӣ фосилаҳои қиматҳоро нишон медиҳад. Метавон ҳар атрибутро алоҳида кашид ё hist()-ро барои тамоми маҷмӯа даъват кард, то барои ҳамаи атрибутҳои ададӣ гистограмма созад (расми 2.8).

Гистограммаҳои атрибутҳои ададӣ

Расми 2.8. Гистограмма барои ҳар атрибути ададӣ.

Шумораи фосилаҳоро бо bins танзим мекунед. Онро тағйир дода, таъсирро бинед:

import matplotlib.pyplot as plt

housing_full.hist(bins=50, figsize=(12, 8))
plt.show()

Аз гистограммаҳо чанд чиз маълум мешавад:

  • Медианаи даромад ба доллари ИМА монанд нест. Гурӯҳи ҷамъоварии додаҳо мегӯяд, ки миқёс тағйир дода шуда, ҳадди боло барои даромадҳои баланд 15, аниқтараш 15,0001, ва ҳадди поён 0,5, аниқтараш 0,4999, гузошта шудааст. Ададҳо тақрибан даҳҳо ҳазор долларро ифода мекунанд: 3 тақрибан 30 000 доллар аст. Атрибутҳои пешкоркардшуда маъмуланд ва худ аз худ мушкил нестанд, аммо бояд тарзи ҳисобашонро фаҳмед.
  • Медианаи синни манзил ва медианаи арзиши манзил низ ҳадгузорӣ шудаанд. Дуюмӣ метавонад мушкили ҷиддӣ бошад, зеро атрибути ҳадаф ё барчаспи шумост. Алгоритмҳо шояд омӯзанд, ки нарх ҳеҷ гоҳ аз ин ҳад намегузарад. Аз гурӯҳи истифодабарандаи баромади система пурсед, ки ин мушкил аст ё не. Агар пешгӯии дақиқ барои нархҳои бештар аз 500 000 доллар ҳам лозим бошад, ду роҳ доред: барчаспҳои дурусти ноҳияҳои ҳадгузоришударо ҷамъ кунед ё он ноҳияҳоро аз маҷмӯи омӯзишӣ ва санҷишӣ хориҷ намоед. Система набояд барои пешгӯии бештар аз 500 000 доллар беасос бад арзёбӣ шавад.
  • Миқёсҳои атрибутҳо хеле фарқ мекунанд. Баъдтар ҳангоми миқёсбандии хусусиятҳо инро баррасӣ мекунем.
  • Бисёр гистограммаҳо ба рост каҷанд: аз медиана ба рост нисбат ба чап хеле дуртар тӯл мекашанд. Ин метавонад дарёфти қонуниятҳоро барои баъзе алгоритмҳо душвортар кунад. Баъдтар онҳоро ба тақсимоти симметрӣ ва зангӯлашакл наздиктар мекунед.

Акнун навъи додаҳоро беҳтар мефаҳмед.

Маҷмӯи санҷишӣ созед

Пеш аз таҳқиқи бештар маҷмӯи санҷишӣ созед, канор гузоред ва дигар ба он нигоҳ накунед. Шояд дар ин марҳила ихтиёран ҷудо кардани қисми додаҳо аҷиб намояд: ҳанӯз танҳо як нигоҳи кӯтоҳ кардед ва пеш аз интихоби алгоритмҳо бояд бештар омӯзед, дуруст? Бале, аммо мағзи шумо системаи олии дарёфти қонуниятҳо аст ва ҳамин онро ба аз ҳад мутобиқшавӣ майл медиҳад. Агар маҷмӯи санҷиширо бинед, шояд қонунияти зоҳиран ҷолибе пайдо карда, навъи муайяни моделро интихоб кунед. Он гоҳ тахмини хатои умумиятдиҳӣ бо ин маҷмӯа аз ҳад хушбинона мешавад ва системаи ба кор даровардашуда аз интизорӣ бадтар кор мекунад. Ин ғарази аз назар гузарондани додаҳо (data snooping bias) ном дорад.

Аз ҷиҳати назарӣ сохтани маҷмӯа осон аст: тасодуфан чанд намуна, одатан 20 фоиз ё барои маҷмӯи азим камтар, интихоб карда, канор гузоред:

import numpy as np

def shuffle_and_split_data(data, test_ratio, rng):
    shuffled_indices = rng.permutation(len(data))
    test_set_size = int(len(data) * test_ratio)
    test_indices = shuffled_indices[:test_set_size]
    train_indices = shuffled_indices[test_set_size:]
    return data.iloc[train_indices], data.iloc[test_indices]

Истифодаи функсия:

>>> rng = np.random.default_rng()  # default random number generator
>>> train_set, test_set = shuffle_and_split_data(housing_full, 0.2, rng)
>>> len(train_set)
16512
>>> len(test_set)
4128

Ин кор мекунад, аммо комил нест: иҷрои навбатӣ маҷмӯи санҷишии дигар медиҳад. Бо гузашти вақт шумо ё алгоритмҳоятон тамоми додаҳоро мебинед, ки бояд пешгирӣ шавад.

Як роҳ нигоҳ доштани маҷмӯи санҷишӣ дар иҷрои аввал ва бор кардани он дар иҷроҳои баъдӣ аст. Роҳи дигар гузоштани тухми генератори ададҳои тасодуфӣ (seed), масалан seed=42 дар default_rng(), мебошад, то ҳар иҷро ҳамон пайдарпайии ададҳоро диҳад.

Аммо бо гирифтани маҷмӯи навшуда ҳар ду роҳ мушкил пайдо мекунанд. Барои тақсимоти устувори омӯзишу санҷиш пас аз навсозӣ одатан шиносаи ҳар намунаро истифода мебаранд, агар шиносаҳо ягона ва тағйирнопазир бошанд. Масалан, ҳеши шиносаро ҳисоб карда, агар он аз 20 фоизи қимати бузургтарини ҳеш камтар ё баробар бошад, намунаро ба санҷиш мегузоред. Ҳамин тавр, тақсимот дар иҷроҳои гуногун ва баъди навсозӣ устувор мемонад. Маҷмӯи нави санҷишӣ 20 фоизи намунаҳои навро мегирад, аммо ягон намунаеро, ки пештар дар маҷмӯи омӯзишӣ буд, намегирад.

Як татбиқи имконпазир:

from zlib import crc32

def is_id_in_test_set(identifier, test_ratio):
    return crc32(np.int64(identifier)) < test_ratio * 2**32

def split_data_with_id_hash(data, test_ratio, id_column):
    ids = data[id_column]
    in_test_set = ids.apply(lambda id_: is_id_in_test_set(id_, test_ratio))
    return data.loc[~in_test_set], data.loc[in_test_set]

Мутаассифона, маҷмӯи манзил сутуни шиноса надорад. Содатарин роҳ индекси сатрро ҳамчун ID истифода бурдан аст:

housing_with_id = housing_full.reset_index()  # adds an `index` column
train_set, test_set = split_data_with_id_hash(housing_with_id, 0.2, "index")

Он гоҳ бояд додаҳои нав танҳо ба охир илова шаванд ва ягон сатр нест нашавад. Агар ин имконнопазир бошад, шиносаро аз хусусиятҳои устувортар созед. Масалан, арз ва тӯли ҷуғрофии ноҳия чанд миллион сол устувор мемонанд; онҳоро чунин якҷо кардан мумкин аст:

housing_with_id["id"] = (housing_full["longitude"] * 1000
                         + housing_full["latitude"])
train_set, test_set = split_data_with_id_hash(housing_with_id, 0.2, "id")

Scikit-Learn барои ҷудо кардани маҷмӯаҳо ба қисмҳо функсияҳои гуногун дорад. Содатаринаш train_test_split() аст: тақрибан кори shuffle_and_split_data()-и моро мекунад, бо ду имконияти иловагӣ. random_state тухми генераторро муайян мекунад. Ҳамчунин метавонед чанд маҷмӯи дорои шумораи яксони сатрро диҳед: онҳо бо индексҳои яксон тақсим мешаванд. Ин ҳангоми доштани DataFrame-и алоҳидаи барчаспҳо хеле муфид аст:

from sklearn.model_selection import train_test_split

train_set, test_set = train_test_split(housing_full, test_size=0.2,
                                       random_state=42)

То ин ҷо танҳо намунагирии комилан тасодуфиро дидем. Агар маҷмӯа ба қадри кофӣ калон бошад, махсусан нисбат ба шумораи атрибутҳо, ин одатан хуб аст. Вагарна ғарази назарраси намунагирӣ пайдо шуда метавонад. Барои пурсиши 1 000 нафар кормандони ширкати пурсиш танҳо 1 000 номро тасодуфан аз феҳристи телефон намегиранд: мекӯшанд намуна намояндаи тамоми аҳолӣ нисбат ба саволҳо бошад. Масалан, тибқи додаҳои Идораи барӯйхатгирии ИМА, 51,6 фоизи шаҳрвандони дорои синни овоздиҳӣ зан ва 48,4 фоиз марданд. Пурсиши дуруст ин таносубро нигоҳ медорад: 516 зан ва 484 мард, ҳадди ақал агар ҷавобҳо эҳтимол аз ҷинс вобаста бошанд. Ин намунагирии қишрӣ (stratified sampling) аст: аҳолӣ ба зергурӯҳҳои якхела — қишрҳо (strata) — ҷудо шуда, аз ҳар қишр шумораи муносиб интихоб мешавад, то маҷмӯи санҷишӣ намояндаи аҳолии умумӣ бошад. Бо интихоби комилан тасодуфӣ эҳтимоли бештар аз 10-фоиза ҳаст, ки ҳиссаи занон аз 49 фоиз кам ё аз 54 фоиз зиёд шавад. Ҳар ду натиҷаи пурсишро ғаразнок мекунанд.

Фарз мекунем коршиносон гуфтанд, ки медианаи даромад барои пешгӯии нархи манзил хеле муҳим аст. Мехоҳед маҷмӯи санҷишӣ категорияҳои гуногуни даромади тамоми додаҳоро намояндагӣ кунад. Азбаски даромад атрибути ададии пайваста аст, аввал атрибути категорияи даромад месозед. Дар гистограммаи расми 2.8 аксари қиматҳо дар фосилаи 1,5–6, яъне 15 000–60 000 доллар, ҷойгиранд, аммо баъзеҳо аз 6 хеле баландтаранд. Ҳар қишр бояд намунаҳои кофӣ дошта бошад, вагарна аҳаммияташ ғаразнок тахмин мешавад. Пас қишрҳо набояд аз ҳад зиёд бошанд ва ҳар кадом бояд ба қадри кофӣ калон бошад. Рамзи зерин бо pd.cut() панҷ категорияи 1–5 месозад: якум аз 0 то 1,5, яъне камтар аз 15 000 доллар, дуюм аз 1,5 то 3 ва ғайра:

housing_full["income_cat"] = pd.cut(housing_full["median_income"],
                                    bins=[0., 1.5, 3.0, 4.5, 6., np.inf],
                                    labels=[1, 2, 3, 4, 5])

Категорияҳо дар расми 2.9 нишон дода шудаанд:

cat_counts = housing_full["income_cat"].value_counts().sort_index()
cat_counts.plot.bar(rot=0, grid=True)
plt.xlabel("Income category")
plt.ylabel("Number of districts")
plt.show()

Акнун барои намунагирии қишрӣ аз рӯйи категорияи даромад омодаед. Бастаи sklearn.model_selection синфҳои гуногуни тақсимкунанда дорад. Ҳар кадом методи split() дорад, ки итератори тақсимоти гуногуни омӯзишу санҷиши ҳамон додаҳоро бармегардонад.

Гистограммаи категорияҳои даромад

Расми 2.9. Гистограммаи категорияҳои даромад.

Дақиқтараш split() индексҳои омӯзишӣ ва санҷиширо медиҳад, на худи додаҳоро. Чанд тақсимот барои арзёбии беҳтари модел муфиданд; баъдтар дар бахши санҷиши салибӣ мебинем. Масалан, ин рамз 10 тақсимоти қишрии гуногун месозад:

from sklearn.model_selection import StratifiedShuffleSplit

splitter = StratifiedShuffleSplit(n_splits=10, test_size=0.2, random_state=42)
strat_splits = []
for train_index, test_index in splitter.split(housing_full,
                                              housing_full["income_cat"]):
    strat_train_set_n = housing_full.iloc[train_index]
    strat_test_set_n = housing_full.iloc[test_index]
    strat_splits.append([strat_train_set_n, strat_test_set_n])

Ҳоло тақсимоти аввалро истифода баред:

strat_train_set, strat_test_set = strat_splits[0]

Азбаски намунагирии қишрӣ маъмул аст, роҳи кӯтоҳтар истифодаи train_test_split() бо stratify мебошад:

strat_train_set, strat_test_set = train_test_split(
    housing_full, test_size=0.2, stratify=housing_full["income_cat"],
    random_state=42)

Барои санҷидани натиҷа ҳиссаи категорияҳои даромадро дар маҷмӯи санҷишӣ бинед:

>>> strat_test_set["income_cat"].value_counts() / len(strat_test_set)
income_cat
3    0.350533
2    0.318798
4    0.176357
5    0.114341
1    0.039971
Name: count, dtype: float64

Бо рамзи монанд ҳиссаҳои тамоми маҷмӯаро ҳисоб карда метавонед. Расми 2.10 онҳоро дар тамоми додаҳо, маҷмӯи санҷишии қишрӣ ва маҷмӯи санҷишии тасодуфӣ муқоиса мекунад. Ҳиссаҳои намунагирии қишрӣ қариб ба маҷмӯи пурра баробаранд, аммо тақсимоти тасодуфӣ каҷшавӣ дорад.

Ҷадвали ғарази намунагирӣ

Расми 2.10. Муқоисаи ғарази намунагирии қишрӣ ва комилан тасодуфӣ.

Сутуни income_cat дигар лозим нест; онро хориҷ карда, додаҳоро ба ҳолати аслӣ баргардонед:

for set_ in (strat_train_set, strat_test_set):
    set_.drop("income_cat", axis=1, inplace=True)

Ба сохтани маҷмӯи санҷишӣ вақти зиёд ҷудо кардем, зеро ин қисми аксар вақт нодидагирифта, вале бисёр муҳими лоиҳа аст. Бисёр андешаҳои он дар санҷиши салибӣ ҳам муфид мешаванд. Акнун ба таҳқиқи додаҳо мегузарем.

Додаҳоро барои дарки беҳтар таҳқиқ ва тасвирсозӣ кунед

То ин ҷо танҳо барои тасаввури умумӣ ба додаҳо нигоҳ кардед. Акнун амиқтар меравем.

Аввал бовар ҳосил кунед, ки маҷмӯи санҷишӣ канор гузошта шудааст ва танҳо маҷмӯи омӯзиширо таҳқиқ мекунед. Агар он хеле калон бошад, барои кори осону тез як қисми онро ҳамчун маҷмӯи таҳқиқӣ гиред. Дар ин мисол хурд аст ва бо ҳамааш кор мекунем. Азбаски табдилҳои гуногунро месанҷед, нусхае гиред, то баъд ба асл баргардед:

housing = strat_train_set.copy()

Тасвирсозии додаҳои ҷуғрофӣ

Азбаски арз ва тӯли ҷуғрофӣ ҳастанд, графики парокандагии ҳамаи ноҳияҳоро кашидан хуб аст (расми 2.11):

housing.plot(kind="scatter", x="longitude", y="latitude", grid=True)
plt.show()

Графики парокандагии ҷуғрофӣ

Расми 2.11. Графики ҷуғрофии парокандагии додаҳо.

Он ба Калифорния монанд аст, аммо қонунияти дигареро дидан душвор аст. Бо alpha=0.2 ҷойҳои зичии баланди нуқтаҳо равшантар мешаванд (расми 2.12):

housing.plot(kind="scatter", x="longitude", y="latitude", grid=True, alpha=0.2)
plt.show()

Акнун хеле беҳтар аст: минтақаи халиҷ, атрофи Лос-Анҷелес ва Сан-Диего ва қатори дарози минтақаҳои нисбатан зич дар водии Марказӣ, махсусан атрофи Сакраменто ва Фресно, равшананд.

Мағзи мо қонуниятҳоро дар тасвир хуб меёбад, аммо барои равшан кардани онҳо шояд параметрҳои тасвирсозиро тағйир додан лозим шавад.

Графики парокандагии ҷуғрофӣ бо alpha = 0.2

Расми 2.12. Намоиши беҳтаре, ки минтақаҳои зичро равшан мекунад.

Баъд нархҳоро мебинем (расми 2.13). Радиуси ҳар доира аҳолии ноҳияро — параметри s — ва ранг нархро — параметри c — нишон медиҳад. Харитаи рангии тайёри jet бо cmap интихоб мешавад: аз кабуд барои қиматҳои паст то сурх барои нархҳои баланд.

housing.plot(kind="scatter", x="longitude", y="latitude", grid=True,
             s=housing["population"] / 100, label="population",
             c="median_house_value", cmap="jet", colorbar=True,
             legend=True, sharex=False, figsize=(10, 7))
plt.show()

Тасвир нишон медиҳад, ки нархи манзил ба ҷойгиршавӣ, масалан наздикӣ ба уқёнус, ва зичии аҳолӣ сахт вобаста аст. Эҳтимол инро аллакай медонистед. Алгоритми кластербандӣ метавонад барои ёфтани кластерҳои асосӣ ва илова кардани хусусиятҳое муфид бошад, ки наздикӣ ба марказҳои кластерҳоро чен мекунанд. Атрибути наздикӣ ба уқёнус ҳам шояд муфид бошад, аммо дар шимоли Калифорния нархҳои соҳилӣ чандон баланд нестанд; пас қоида сода нест.

Нархҳои манзил ва аҳолии ноҳияҳо

Расми 2.13. Нархҳои манзил дар Калифорния: сурх — гарон, кабуд — арзон; доираҳои калон аҳолии бештарро нишон медиҳанд.

Ҳамбастагиҳоро ҷӯед

Азбаски маҷмӯа калон нест, бо corr() коэффисиенти стандартии ҳамбастагӣ, ё r-и Пирсон-ро барои ҳар ҷуфти атрибутҳои ададӣ ҳисоб карда метавонед:

corr_matrix = housing.corr(numeric_only=True)

Акнун ҳамбастагии ҳар атрибутро бо медианаи арзиши манзил бинед:

>>> corr_matrix["median_house_value"].sort_values(ascending=False)
median_house_value    1.000000
median_income         0.688380
total_rooms           0.137455
housing_median_age    0.102175
households            0.071426
total_bedrooms        0.054635
population           -0.020153
longitude            -0.050859
latitude             -0.139584
Name: median_house_value, dtype: float64

Коэффисиент аз −1 то 1 аст. Наздик ба 1 — ҳамбастагии қавии мусбат: масалан, бо зиёд шудани медианаи даромад медианаи арзиши манзил низ меафзояд. Наздик ба −1 — ҳамбастагии қавии манфӣ. Байни арз ва нархи манзил ҳамбастагии хурди манфӣ ҳаст: бо ҳаракат ба шимол нархҳо каме поён мераванд. Қимати наздик ба 0 маънои набудани ҳамбастагии хаттиро дорад.

Роҳи дигар scatter_matrix()-и Pandas аст, ки ҳар атрибути ададиро нисбат ба дигарон мекашад. Барои 9 атрибут 9² = 81 график ҳосил мешавад ва дар саҳифа намеғунҷад. Пас ба чанд атрибути умедбахш, ки бо арзиши манзил бештар ҳамбастаанд, диққат медиҳем (расми 2.14):

from pandas.plotting import scatter_matrix

attributes = ["median_house_value", "median_income", "total_rooms",
              "housing_median_age"]
scatter_matrix(housing[attributes], figsize=(12, 8))
plt.show()

Матритсаи парокандагӣ

Расми 2.14. Матритсаи парокандагӣ ҳар атрибути ададиро нисбат ба дигарон мекашад. Дар диагонали асосӣ, аз болои чап то поёни рост, гистограммаи қиматҳои ҳар атрибут ҷойгир аст.

Агар Pandas ҳар тағйирёбандаро нисбат ба худаш мекашид, диагонал аз хатҳои рост иборат мешуд ва фоида надошт. Ба ҷойи он гистограмма нишон медиҳад. Имконоти дигар ҳам ҳастанд; ба ҳуҷҷатгузории Pandas нигаред.

Аз графикҳо бармеояд, ки медианаи даромад умедбахштарин атрибут барои пешгӯии арзиши манзил аст. Пас онро ҷудогона мебинем (расми 2.15):

housing.plot(kind="scatter", x="median_income", y="median_house_value",
             alpha=0.1, grid=True)
plt.show()

Медианаи даромад ва медианаи арзиши манзил

Расми 2.15. Медианаи даромад нисбат ба медианаи арзиши манзил.

График чанд чизро ошкор мекунад. Аввал, ҳамбастагӣ воқеан қавист: бо вуҷуди ғавғо тамоюли болоравӣ равшан аст. Дуюм, ҳадди нархи 500 000 доллар ҳамчун хати уфуқӣ намоён аст. Хатҳои камтар ошкор ҳам ҳастанд: тақрибан 450 000, 350 000, шояд 280 000 доллар ва чанд хати поёнтар. Шояд ноҳияҳои мувофиқро хориҷ кунед, то алгоритмҳо ин хусусиятҳои аҷиби додаҳоро такрор кардан наомӯзанд.

Коэффисиент танҳо робитаи хаттиро чен мекунад: «бо афзоиши x, y одатан зиёд ё кам мешавад». Робитаи ғайрихаттӣ, масалан «бо ба сифр наздик шудани x, y меафзояд», метавонад тамоман аз назар афтад. Дар расми 2.16 маҷмӯаҳои гуногун бо коэффисиентҳояшон ҳастанд. Дар ҳамаи графикҳои сатри поён он 0 аст, ҳарчанд тағйирёбандаҳо равшан мустақил нестанд: инҳо робитаҳои ғайрихаттианд. Дар сатри дуюм коэффисиентҳо 1 ё −1 мебошанд; ин ба нишебии хат вобаста нест. Масалан, қади шумо бо дюйм бо қади шумо бо фут ё нанометр ҳамбастагии 1 дорад.

Мисолҳои коэффисиенти ҳамбастагӣ

Расми 2.16. Коэффисиенти стандартии ҳамбастагии маҷмӯаҳои гуногун (мисли расми маъруфи Википедия, аз нав сохташуда).

Бо таркибҳои атрибутҳо таҷриба кунед

Бахшҳои пешина чанд роҳи таҳқиқ ва дарки додаҳоро нишон доданд. Чанд хусусияти аҷиберо ёфтед, ки пеш аз омӯзиш тоза кардан мехоҳед, ва ҳамбастагиҳои ҷолиб, махсусан бо ҳадаф, пайдо кардед. Баъзе атрибутҳо тақсимоти ба рост каҷ доранд ва шояд онҳоро бо логарифм ё решаи квадратӣ табдил диҳед. Албатта, ҳар лоиҳа натиҷаҳои хоси худро дорад, аммо андешаҳои умумӣ монанданд.

Пеш аз омодасозӣ боз таркибҳои гуногуни атрибутҳоро санҷед. Шумораи умумии ҳуҷраҳои ноҳия бе шумораи хонаводаҳо чандон муфид нест: шумораи ҳуҷраҳо ба ҳар хонавода лозим аст. Шумораи умумии ҳуҷраҳои хоб ҳам танҳо ба худии худ фоидаи зиёд надорад; нисбати он ба тамоми ҳуҷраҳо ҷолибтар аст. Аҳолӣ ба ҳар хонавода низ таркиби ҷолиб мебошад. Хусусиятҳои навро чунин месозед:

housing["rooms_per_house"] = housing["total_rooms"] / housing["households"]
housing["bedrooms_ratio"] = housing["total_bedrooms"] / housing["total_rooms"]
housing["people_per_house"] = housing["population"] / housing["households"]

Баъд матритсаи ҳамбастагиро боз мебинед:

>>> corr_matrix = housing.corr(numeric_only=True)
>>> corr_matrix["median_house_value"].sort_values(ascending=False)
median_house_value    1.000000
median_income         0.688380
rooms_per_house       0.143663
total_rooms           0.137455
housing_median_age    0.102175
households            0.071426
total_bedrooms        0.054635
population           -0.020153
people_per_house     -0.038224
longitude            -0.050859
latitude             -0.139584
bedrooms_ratio       -0.256397
Name: median_house_value, dtype: float64

Бад нест! bedrooms_ratio бо медианаи арзиши манзил аз шумораи умумии ҳуҷраҳо ё ҳуҷраҳои хоб хеле бештар ҳамбаста аст. Робита манфии қавист: хонаҳое, ки нисбати ҳуҷраҳои хоб ба ҳамаи ҳуҷраҳояшон камтар аст, одатан гаронтаранд. Ҳуҷраҳо ба ҳар хонавода низ аз шумораи умумии ҳуҷраҳои ноҳия иттилооти бештар медиҳанд: маълум аст, ки хонаҳои калонтар гаронтаранд.

Огоҳӣ. Ҳангоми сохтани хусусиятҳои таркибӣ бовар ҳосил кунед, ки бо хусусиятҳои мавҷуда ҳамбастагии хаттии аз ҳад зиёд надоранд. Ҳамхаттӣ (collinearity) ба баъзе моделҳо, аз ҷумла регрессияи хаттӣ, мушкил меорад. Махсусан аз ҷамъи содаи вазндори хусусиятҳои мавҷуда худдорӣ кунед.

Ин даври таҳқиқ набояд комилан ҳамаҷониба бошад: мақсад оғози дуруст ва гирифтани зудтари фаҳмиш барои сохтани намунаи аввалини нисбатан хуб аст. Раванд такроршаванда мебошад: пас аз кор кардани прототип натиҷаҳояшро таҳлил карда, фаҳмиши нав мегиред ва ба таҳқиқ бармегардед.

Додаҳоро барои алгоритмҳои омӯзиши мошинӣ омода созед

Вақти омодасозии додаҳо расид. Ба ҷойи кори дастӣ барои он функсияҳо нависед, зеро:

  • табдилҳоро дар ҳар маҷмӯа, масалан додаҳои нави баъдӣ, осон такрор мекунед;
  • тадриҷан китобхонаи функсияҳои табдил месозед, ки дар лоиҳаҳои оянда такроран истифода мешаванд;
  • ҳамин функсияҳо додаҳои нави системаи фаъолро пеш аз ворид кардан ба алгоритмҳо табдил медиҳанд;
  • санҷидани табдилҳои гуногун ва ёфтани беҳтарин таркиб осон мешавад.

Аввал ба маҷмӯи тозаи омӯзишӣ баргардед ва strat_train_set-ро боз нусхабардорӣ кунед. Пешгӯикунандаҳо ва барчаспҳоро ҷудо намоед, зеро шояд барои онҳо табдилҳои яксон нахоҳед. drop() нусха месозад ва ба strat_train_set таъсир намерасонад:

housing = strat_train_set.drop("median_house_value", axis=1)
housing_labels = strat_train_set["median_house_value"].copy()

Додаҳоро тоза кунед

Аксари алгоритмҳо бо хусусиятҳои гумшуда кор карда наметавонанд. Пештар дидед, ки total_bedrooms қиматҳои гумшуда дорад. Се роҳ ҳаст:

  1. Ноҳияҳои мувофиқро хориҷ кунед.
  2. Тамоми атрибутро хориҷ кунед.
  3. Қиматҳои гумшударо бо сифр, миёна, медиана ё қимати дигар пур кунед. Ин пуркунии қиматҳои гумшуда (imputation) ном дорад.

Бо методҳои dropna(), drop() ва fillna() инҳо осонанд:

housing.dropna(subset=["total_bedrooms"], inplace=True)  # option 1

housing.drop("total_bedrooms", axis=1, inplace=True)  # option 2

median = housing["total_bedrooms"].median()  # option 3
housing["total_bedrooms"] = housing["total_bedrooms"].fillna(median)

Роҳи 3-ро интихоб мекунед, зеро камтар маълумотро нест мекунад. Аммо ба ҷойи рамзи боло синфи қулайи Scikit-Learn — SimpleImputer-ро истифода мебаред. Он медианаи ҳар хусусиятро нигоҳ медорад ва барои пур кардани маҷмӯи омӯзишӣ, тасдиқӣ, санҷишӣ ва ҳар додаи нав истифода мекунад. Аввал объекти онро сохта, мегӯед, ки қиматҳои гумшуда бо медианаи ҳамон атрибут иваз шаванд:

from sklearn.impute import SimpleImputer

imputer = SimpleImputer(strategy="median")

Медиана танҳо барои атрибутҳои ададӣ ҳисоб мешавад. Пас нусхаеро танҳо бо хусусиятҳои ададӣ созед, то ocean_proximity хориҷ шавад:

housing_num = housing.select_dtypes(include=[np.number])

Акнун бо fit() пуркунандаро ба додаҳои омӯзишӣ мутобиқ кунед:

imputer.fit(housing_num)

Он медианаи ҳар атрибутро ҳисоб карда, дар statistics_ нигоҳ медорад. Ҳоло танҳо total_bedrooms қимати гумшуда дошт, аммо кафолат нест, ки баъди ба кор даромадани система дар хусусиятҳои дигар қимат гум намешавад. Пас татбиқ ба ҳамаи атрибутҳои ададӣ бехатартар аст:

>>> imputer.statistics_
array([-118.51  ,   34.26  ,   29.    , 2125.    ,  434.    , 1167.    ,
        408.    ,    3.5385])
>>> housing_num.median().values
array([-118.51  ,   34.26  ,   29.    , 2125.    ,  434.    , 1167.    ,
        408.    ,    3.5385])

Бо пуркунандаи «омӯзонидашуда» қиматҳои гумшударо ба медианаҳои омӯхташуда иваз кунед:

X = imputer.transform(housing_num)

Ба ҷойи медиана метавон миёна — strategy="mean", қимати сертакрор — strategy="most_frequent" ё қимати доимӣ — strategy="constant", fill_value=… — гузошт. Ду роҳи охир додаҳои ғайриададиро ҳам дастгирӣ мекунанд.

Маслиҳат. Дар sklearn.impute пуркунандаҳои тавонотар ҳам ҳастанд; ҳар ду танҳо барои хусусиятҳои ададӣ:

  • KNNImputer қимати гумшударо бо миёнаи қимати ҳамон хусусият дар k ҳамсояи наздиктарин иваз мекунад. Фосила аз рӯйи ҳамаи хусусиятҳои дастрас ҳисоб мешавад.
  • IterativeImputer барои ҳар хусусият модели регрессия меомӯзонад, то қиматҳои гумшударо аз рӯйи дигар хусусиятҳо пешгӯӣ кунад. Баъд бо додаҳои навшуда боз меомӯзонад ва чанд бор такрор мекунад; ҳар давр моделҳо ва қиматҳои ҷойгузин беҳтар мешаванд.

Тарҳрезии Scikit-Learn

API-и Scikit-Learn хеле хуб тарҳрезӣ шудааст. Принсипҳои асосӣ чунинанд:

Ягонагӣ. Ҳамаи объектҳо интерфейси сода ва яксон доранд.

Арзёбандаҳо (estimators). Ҳар объекте, ки аз маҷмӯи додаҳо параметрҳоро ҳисоб карда метавонад, estimator аст, масалан SimpleImputer. Ҳисоб бо fit() иҷро мешавад. Он як маҷмӯа мегирад ё барои омӯзиши бо назорат дуто: дуюмӣ барчаспҳост. Параметрҳои дигари роҳнамоии раванд, мисли strategy, гиперпараметранд ва ҳамчун тағйирёбандаи объект, одатан тавассути аргументи созанда, муайян мешаванд.

Табдилдиҳандаҳо (transformers). Баъзе арзёбандаҳо, мисли SimpleImputer, маҷмӯаҳоро табдил ҳам медиҳанд. transform() маҷмӯи воридотиро гирифта, маҷмӯи табдилшударо бармегардонад. Одатан табдил ба параметрҳои омӯхташуда такя мекунад. Ҳамаи табдилдиҳандаҳо fit_transform() низ доранд, ки баробари даъвати пайдарпайи fit() ва transform() аст, вале баъзан беҳинасозӣ шуда, хеле тезтар кор мекунад.

Пешгӯикунандаҳо (predictors). Баъзе арзёбандаҳо аз додаҳо пешгӯӣ мекунанд. Масалан, LinearRegression-и боби пеш аз ММД ба ҳар сари аҳолӣ қаноатмандӣ аз зиндагиро пешгӯӣ мекард. predict() маҷмӯи намунаҳои навро гирифта, пешгӯиҳоро бармегардонад. score() бо маҷмӯи санҷишӣ ва барои омӯзиши бо назорат бо барчаспҳои мувофиқ сифати пешгӯиҳоро чен мекунад.

Имкони таҳлил. Ҳамаи гиперпараметрҳо бевосита тавассути тағйирёбандаҳои оммавии объект, мисли imputer.strategy, дастрасанд. Параметрҳои омӯхташуда тағйирёбандаҳои оммавии дорои пасванди _ доранд, мисли imputer.statistics_.

Аз ҳад зиёд накардани синфҳо. Додаҳо бо массивҳои NumPy ё матритсаҳои тунуки SciPy ифода мешаванд, на синфҳои махсуси сохташуда. Гиперпараметрҳо сатрҳо ё ададҳои одии Python мебошанд.

Таркибпазирӣ. Ҷузъҳои мавҷуда то ҳадди имкон дубора истифода мешаванд. Масалан, сохтани арзёбандаи Pipeline аз пайдарпайии дилхоҳи табдилдиҳандаҳо ва як арзёбандаи ниҳоӣ осон аст; баъдтар мебинед.

Қиматҳои пешфарзи оқилона. Аксари параметрҳо пешфарзҳои муносиб доранд, то зуд системаи ибтидоии коршоям созед.

Табдилдиҳандаҳои Scikit-Learn ҳатто бо вуруди DataFrame одатан массиви NumPy ё баъзан матритсаи тунуки SciPy медиҳанд. Пас X, яъне натиҷаи imputer.transform(housing_num), номҳои сутун ва индекс надорад. Хушбахтона, онро ба DataFrame печонда, номҳо ва индексро аз housing_num барқарор кардан осон аст:

housing_tr = pd.DataFrame(X, columns=housing_num.columns,
                          index=housing_num.index)

Кор бо атрибутҳои матнӣ ва категориявӣ

То ин ҷо танҳо атрибутҳои ададиро дидем, аммо додаҳо метавонанд матнӣ ҳам бошанд. Дар ин маҷмӯа танҳо ocean_proximity чунин аст. Қиматҳои аввалро бинем:

>>> housing_cat = housing[["ocean_proximity"]]
>>> housing_cat.head(8)
      ocean_proximity
13096        NEAR BAY
14973       <1H OCEAN
3785           INLAND
14689          INLAND
20507      NEAR OCEAN
1286           INLAND
18078       <1H OCEAN
4396         NEAR BAY

Ин матни озод нест: шумораи маҳдуди қиматҳо ҳаст ва ҳар кадом категорияеро нишон медиҳад. Аксари алгоритмҳо ададҳоро авлотар медонанд. Пас категорияҳоро бо OrdinalEncoder аз матн ба адад табдил медиҳем:

from sklearn.preprocessing import OrdinalEncoder

ordinal_encoder = OrdinalEncoder()
housing_cat_encoded = ordinal_encoder.fit_transform(housing_cat)

Қиматҳои аввали рамзгузоришуда:

>>> housing_cat_encoded[:8]
array([[3.],
       [0.],
       [1.],
       [1.],
       [4.],
       [1.],
       [0.],
       [3.]])

categories_ рӯйхати категорияҳоро медиҳад: барои ҳар атрибути категориявӣ як массиви якченака. Дар ин ҷо танҳо як массив ҳаст:

>>> ordinal_encoder.categories_
[array(['<1H OCEAN', 'INLAND', 'ISLAND', 'NEAR BAY', 'NEAR OCEAN'],
       dtype=object)]

Мушкил дар он аст, ки алгоритмҳо қиматҳои наздикро аз қиматҳои дур монандтар мешуморанд. Барои категорияҳои тартибдор, мисли «бад», «миёна», «хуб», «аъло», ин муносиб аст. Аммо барои ocean_proximity не: категорияҳои 0 ва 4 аз 0 ва 1 монандтаранд. Роҳи маъмули ҳал сохтани як атрибути дуӣ барои ҳар категория аст: яке барои "<1H OCEAN" ба 1 ва дар дигар ҳолатҳо ба 0 баробар мешавад; дигаре барои "INLAND" ва ғайра. Ин рамзгузории one-hot ном дорад: танҳо як атрибут 1, яъне «гарм», ва дигарон 0, яъне «сард», мешаванд. Онҳоро баъзан атрибутҳои сохта (dummy attributes) меноманд. Scikit-Learn барои ин OneHotEncoder дорад:

from sklearn.preprocessing import OneHotEncoder

cat_encoder = OneHotEncoder()
housing_cat_1hot = cat_encoder.fit_transform(housing_cat)

Натиҷаи пешфарз матритсаи тунуки SciPy аст, на массиви NumPy:

>>> housing_cat_1hot
<Compressed Sparse Row sparse matrix of dtype 'float64'
 with 16512 stored elements and shape (16512, 5)>

Матритсаи тунук (sparse matrix) барои матритсаҳои асосан сифрдор хеле самаранок аст: дар дохил танҳо қиматҳои ғайрисифрӣ ва мавқеъҳояшонро нигоҳ медорад. Агар атрибут садҳо ё ҳазорон категория дошта бошад, one-hot матритсаи азими пур аз сифр месозад, ки дар ҳар сатр танҳо як 1 дорад. Матритсаи тунук ҳам хотираро сарфа мекунад, ҳам ҳисобро метезонад. Бо он қариб мисли массиви одии дученака кор мекунед. Барои табдил ба массиви зичи NumPy toarray()-ро даъват кунед:

>>> housing_cat_1hot.toarray()
array([[0., 0., 0., 1., 0.],
       [1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       ...,
       [0., 0., 0., 0., 1.],
       [1., 0., 0., 0., 0.],
       [0., 0., 0., 0., 1.]], shape=(16512, 5))

Ё ҳангоми сохтани OneHotEncoder параметри sparse_output=False гузоред, то transform() бевосита массиви зич диҳад:

cat_encoder = OneHotEncoder(sparse_output=False)
housing_cat_1hot = cat_encoder.fit_transform(housing_cat)  # now a dense array

Мисли OrdinalEncoder, категорияҳо дар categories_ дастрасанд:

>>> cat_encoder.categories_
[array(['<1H OCEAN', 'INLAND', 'ISLAND', 'NEAR BAY', 'NEAR OCEAN'],
       dtype=object)]

Pandas ҳам get_dummies() дорад, ки барои ҳар категория хусусияти дуӣ сохта, рамзгузории one-hot мекунад:

>>> df_test = pd.DataFrame({"ocean_proximity": ["INLAND", "NEAR BAY"]})
>>> pd.get_dummies(df_test)
   ocean_proximity_INLAND  ocean_proximity_NEAR BAY
0                    True                     False
1                   False                      True

Сода менамояд; пас чаро онро ба ҷойи OneHotEncoder истифода набарем? Бартарии OneHotEncoder он аст, ки категорияҳои ҳангоми омӯзиш дидаашро дар хотир дорад. Дар муҳити воқеӣ модел бояд маҳз ҳамон хусусиятҳои омӯзиширо гирад: на зиёдтар, на камтар. cat_encoder-и омӯзонидашуда барои ҳамон df_test, бо transform(), на fit_transform(), чунин медиҳад:

>>> cat_encoder.transform(df_test)
array([[0., 1., 0., 0., 0.],
       [0., 0., 0., 1., 0.]])

get_dummies() танҳо ду категория дид ва ду сутун дод; OneHotEncoder барои ҳар категорияи омӯхтааш бо тартиби дуруст сутун дод. Агар ба get_dummies() категорияи ношинос, мисли "<2H OCEAN", диҳед, барои он ҳам сутун месозад:

>>> df_test_unknown = pd.DataFrame({"ocean_proximity": ["<2H OCEAN", "ISLAND"]})
>>> pd.get_dummies(df_test_unknown)
   ocean_proximity_<2H OCEAN  ocean_proximity_ISLAND
0                       True                   False
1                      False                    True

Аммо OneHotEncoder категорияи ношиносро ошкор карда, истисно мебарорад. Агар handle_unknown="ignore" гузоред, онро танҳо бо сифрҳо ифода мекунад:

>>> cat_encoder.handle_unknown = "ignore"
>>> cat_encoder.transform(df_test_unknown)
array([[0., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.]])

Маслиҳат. Агар атрибут категорияҳои бисёр дошта бошад, масалан рамзи кишвар, касб ё намуд, one-hot хусусиятҳои зиёд месозад ва метавонад омӯзишро сусту натиҷаро бад кунад. Метавон категорияро бо хусусиятҳои ададии муфид иваз кард: ocean_proximity-ро бо масофа то уқёнус, рамзи кишварро бо аҳолӣ ва ММД ба ҳар сари аҳолӣ. Ё рамзгузорҳои бастаи category_encoders-ро дар GitHub истифода баред. Барои шабакаҳои нейронӣ ҳар категорияро бо вектори камандозаи омӯхташаванда — ҷойгирсозӣ (embedding) — иваз кардан мумкин аст (боби 14). Ин намунаи омӯзиши намояндагӣ (representation learning) аст; дар боби 18 бештар мебинем.

Ҳангоми fit() бо DataFrame, арзёбандаи Scikit-Learn номҳои сутунҳоро дар feature_names_in_ нигоҳ медорад. Баъд месанҷад, ки DataFrame-ҳои ба transform() ё predict() додашуда ҳамон номҳоро дошта бошанд. Табдилдиҳандаҳо ҳам get_feature_names_out() доранд, то натиҷаро ба DataFrame табдил диҳед:

>>> cat_encoder.feature_names_in_
array(['ocean_proximity'], dtype=object)
>>> cat_encoder.get_feature_names_out()
array(['ocean_proximity_<1H OCEAN', 'ocean_proximity_INLAND',
       'ocean_proximity_ISLAND', 'ocean_proximity_NEAR BAY',
       'ocean_proximity_NEAR OCEAN'], dtype=object)
>>> df_output = pd.DataFrame(cat_encoder.transform(df_test_unknown),
...                          columns=cat_encoder.get_feature_names_out(),
...                          index=df_test_unknown.index)
...

Ин имконият аз номувофиқии сутунҳо пешгирӣ карда, ҳангоми ёфтани хатоҳо низ муфид аст.

Миқёсбандӣ ва табдили хусусиятҳо

Яке аз муҳимтарин табдилҳо миқёсбандии хусусиятҳо (feature scaling) аст. Бо истисноҳои кам алгоритмҳо ҳангоми хеле гуногун будани миқёси атрибутҳои ададӣ хуб кор намекунанд. Дар додаҳои манзил шумораи ҳуҷраҳо аз 2 то 39 320 ва медианаи даромад танҳо аз 0 то 15 аст. Бе миқёсбандӣ аксари моделҳо ба нодида гирифтани даромад ва таваҷҷуҳи бештар ба ҳуҷраҳо майл мекунанд.

Ду роҳи маъмули яксон кардани миқёсҳо миқёсбандии min-max ва стандартисозӣ мебошанд.

Огоҳӣ. Мисли ҳамаи арзёбандаҳо, миқёсбандҳоро танҳо бо додаҳои омӯзишӣ мутобиқ кунед: fit() ё fit_transform()-ро барои маҷмӯаҳои дигар истифода набаред. Пас аз омӯзиш бо transform() маҷмӯаҳои тасдиқӣ, санҷишӣ ва додаҳои навро табдил диҳед. Қиматҳои омӯзишӣ дар фосилаи муайяншуда меафтанд, аммо қиматҳои дури додаҳои нав метавонанд аз он берун шаванд. Барои пешгирӣ clip=True гузоред.

Min-max, ки бисёриҳо онро нормализатсия меноманд, содатарин роҳ аст: қиматҳои ҳар атрибут ба фосилаи 0–1 оварда мешаванд. Аз ҳар қимат хурдтарин қиматро тарҳ карда, натиҷаро ба фарқи калонтарин ва хурдтарин тақсим мекунанд. MinMaxScaler ин корро мекунад. Гиперпараметри feature_range фосиларо тағйир медиҳад. Масалан, шабакаҳои нейронӣ бо вурудҳои миёнаашон сифр беҳтар кор мекунанд, бинобар ин −1 то 1 афзал аст:

from sklearn.preprocessing import MinMaxScaler

min_max_scaler = MinMaxScaler(feature_range=(-1, 1))
housing_num_min_max_scaled = min_max_scaler.fit_transform(housing_num)

Стандартисозӣ аввал миёнаро тарҳ мекунад, то миёна сифр шавад, баъд ба инҳирофи стандартӣ тақсим мекунад, то он 1 шавад. Он қиматҳоро ба фосилаи мушаххас маҳдуд намекунад, аммо аз қиматҳои дур хеле камтар таъсир мегирад. Масалан, агар медианаи даромади ноҳия иштибоҳан 100 бошад, на дар фосилаи одии 0–15, min-max онро ба 1 ва ҳамаи дигаронро ба 0–0,15 фишурда мекунад. Стандартисозӣ он қадар таъсир намегирад. Барои он StandardScaler ҳаст:

from sklearn.preprocessing import StandardScaler

std_scaler = StandardScaler()
housing_num_std_scaled = std_scaler.fit_transform(housing_num)

Маслиҳат. Барои миқёсбандии матритсаи тунук бе зич кардани он StandardScaler(with_mean=False) истифода баред. Он танҳо ба инҳирофи стандартӣ тақсим мекунад ва миёнаро тарҳ намекунад, зеро тарҳкунӣ тунукиро вайрон мекунад.

Агар тақсимоти хусусият думи вазнин дошта бошад, яъне қиматҳои дур аз миёна ба таври экспоненсиалӣ камёб набошанд, ҳар ду усул аксари қиматҳоро ба фосилаи хурд фишурда мекунанд. Чунон ки дар боби 4 мебинед, моделҳо инро дӯст намедоранд. Пеш аз миқёсбандӣ думро кӯтоҳ ва, агар мумкин бошад, тақсимотро тақрибан симметрӣ кунед. Барои хусусияти мусбат бо думи рости вазнин аксар вақт решаи квадратӣ ё дараҷаи байни 0 ва 1 кумак мекунад. Агар дум хеле дарозу вазнин, масалан тақсимоти қонуни дараҷагӣ, бошад, логарифм муфид аст. Масалан, population тақрибан ба қонуни дараҷагӣ пайравӣ мекунад: ноҳияҳои 10 000-нафара нисбат ба ноҳияҳои 1 000-нафара танҳо 10 маротиба камёбанд, на ба таври экспоненсиалӣ. Расми 2.17 нишон медиҳад, ки пас аз логарифм тақсимот ба гауссӣ ё зангӯлашакл хеле наздик мешавад.

Гистограммаи аҳолӣ ва логарифми он

Расми 2.17. Табдили хусусият барои наздик кардани он ба тақсимоти гауссӣ.

Роҳи дигар ба фосилаҳо ҷудо кардан (bucketizing) аст: тақсимотро ба гурӯҳҳои тақрибан ҳамандоза ҷудо карда, ҳар қиматро бо индекси гурӯҳаш иваз мекунед, мисли income_cat, ки танҳо барои намунагирии қишрӣ истифода шуд. Масалан, ҳар қиматро бо персентилаш иваз кунед. Гурӯҳҳои ҳамандоза тақсимоти тақрибан яксон медиҳанд ва миқёсбандии дигар лозим нест. Ё индексҳоро ба шумораи гурӯҳҳо тақсим карда, ба 0–1 меоред.

Агар хусусият тақсимоти чандқуллагӣ (multimodal) дошта бошад, яъне ду ё зиёда қулла ё мода, мисли housing_median_age, гурӯҳбандӣ ҳам муфид аст. Аммо ин бор индексҳоро категория донед, на адад: онҳоро, масалан бо OneHotEncoder, рамзгузорӣ кунед. Аз ин рӯ, гурӯҳҳо одатан набояд аз ҳад зиёд бошанд. Модели регрессия қоидаҳои гуногуни фосилаҳои гуногунро осонтар меомӯзад. Масалан, шояд хонаҳои тақрибан 35 сол пеш сохташуда сабки аз мӯд баромада дошта, аз он чи танҳо синнашон мегӯяд, арзонтар бошанд.

Роҳи дигари кор бо тақсимоти чандқуллагӣ барои ҳар мода, ҳадди ақал асосиҳо, илова кардани хусусиятест, ки монандии синни медиании манзилро ба он мода чен мекунад. Одатан функсияи пояи радиалӣ (RBF) истифода мешавад: функсияе, ки танҳо ба фосилаи қимати вуруд аз нуқтаи собит вобаста аст. Маъруфтаринаш RBF-и гауссӣ мебошад, ки бо дур шудан аз нуқтаи собит баромадаш экспоненсиалӣ кам мешавад. Монандии синни x ба 35 чунин аст:

exp(−γ(x − 35)²).

Гиперпараметри γ — гамма — суръати коҳиши монандиро муайян мекунад. Бо rbf_kernel() хусусияти нав месозед:

from sklearn.metrics.pairwise import rbf_kernel

age_simil_35 = rbf_kernel(housing[["housing_median_age"]], [[35]], gamma=0.1)

Расми 2.18 хусусияти навро нисбат ба синни манзил бо хати яклухт ва натиҷаи гаммаи хурдтарро ҳам нишон медиҳад. Қулла дар 35 — наздики қуллаи тақсимоти синни манзил ҷойгир аст. Агар ин гурӯҳи синнӣ бо нархҳои паст ҳамбастагии хуб дошта бошад, хусусияти нав эҳтимол кумак мекунад.

Монандии RBF ба синни 35

Расми 2.18. Хусусияти RBF-и гауссӣ барои чен кардани монандии медианаи синни манзил ба 35.

То ин ҷо танҳо вурудҳоро дидем, аммо қиматҳои ҳадаф низ шояд ба табдил ниёз дошта бошанд. Агар тақсимоти ҳадаф думи вазнин дошта бошад, метавонед онро бо логарифм иваз кунед. Он гоҳ модел логарифми медианаи нархро пешгӯӣ мекунад ва барои гирифтани нархи аслӣ бояд экспонентаи пешгӯиро ҳисоб кунед.

Хушбахтона, аксари табдилдиҳандаҳои Scikit-Learn inverse_transform() доранд, ки табдили баръаксро осон мекунад. Рамзи зерин барчаспҳоро бо StandardScaler миқёсбандӣ мекунад, регрессияи содаи хаттиро меомӯзонад, дар додаҳои нав пешгӯӣ мекунад ва бо inverse_transform() ба миқёси аслӣ бармегардонад. Барчаспҳоро аз Series ба DataFrame мегузаронем, зеро StandardScaler вуруди дученака мехоҳад. Барои содагӣ танҳо хусусияти хоми медианаи даромадро истифода мекунем:

from sklearn.linear_model import LinearRegression

target_scaler = StandardScaler()
scaled_labels = target_scaler.fit_transform(housing_labels.to_frame())

model = LinearRegression()
model.fit(housing[["median_income"]], scaled_labels)
some_new_data = housing[["median_income"]].iloc[:5]  # pretend this is new data

scaled_predictions = model.predict(some_new_data)
predictions = target_scaler.inverse_transform(scaled_predictions)

Ин кор мекунад, аммо TransformedTargetRegressor содатару камхатотар буда, номувофиқии эҳтимолии миқёсҳоро пешгирӣ мекунад. Ба он модели регрессия ва табдилдиҳандаи барчаспҳоро медиҳед ва бо барчаспҳои аслии миқёсбандинашуда fit() мекунед. Он худкор барчаспҳоро табдил дода, моделро меомӯзонад. Ҳангоми пешгӯӣ predict()-и модел ва inverse_transform()-и миқёсбандро истифода мебарад:

from sklearn.compose import TransformedTargetRegressor

model = TransformedTargetRegressor(LinearRegression(),
                                   transformer=StandardScaler())
model.fit(housing[["median_income"]], housing_labels)
predictions = model.predict(some_new_data)

Табдилдиҳандаҳои фармоишӣ

Scikit-Learn табдилдиҳандаҳои муфиди зиёд дорад, аммо баъзан барои табдилҳои махсус, тозакунӣ ё якҷо кардани атрибутҳои муайян табдилдиҳандаи худатонро менависед.

Агар табдил ба омӯзиш ниёз надошта бошад, функсияе кофист, ки массиви NumPy гирифта, массиви табдилшударо диҳад. Масалан, барои хусусияти мусбат бо думи вазнини рост логарифм хуб аст. Табдилдиҳандаи логарифмӣ сохта, ба аҳолӣ татбиқ мекунем:

from sklearn.preprocessing import FunctionTransformer

log_transformer = FunctionTransformer(np.log, inverse_func=np.exp)
log_pop = log_transformer.transform(housing[["population"]])

inverse_func ихтиёрӣ аст ва функсияи баръаксро муайян мекунад, масалан барои истифода дар TransformedTargetRegressor.

Функсияи табдил метавонад гиперпараметрҳоро ҳамчун аргументҳои иловагӣ гирад. Ин табдилдиҳанда ҳамон монандии RBF-и гауссии пешинаро ҳисоб мекунад:

rbf_transformer = FunctionTransformer(rbf_kernel,
                                      kw_args=dict(Y=[[35.]], gamma=0.1))
age_simil_35 = rbf_transformer.transform(housing[["housing_median_age"]])

RBF функсияи баръакс надорад: дар фосилаи муайян аз нуқтаи собит ҳамеша ду қимат ҳаст, ба истиснои фосилаи 0. Ҳамчунин rbf_kernel() хусусиятҳоро ҷудогона коркард намекунад. Агар массиви ду хусусият диҳед, фосилаи эвклидии дученакаро истифода мебарад. Масалан, монандии ҷуғрофии ҳар ноҳия ба Сан-Франсискоро чунин месозед:

sf_coords = 37.7749, -122.41
sf_transformer = FunctionTransformer(rbf_kernel,
                                     kw_args=dict(Y=[sf_coords], gamma=0.1))
sf_simil = sf_transformer.transform(housing[["latitude", "longitude"]])

Табдилдиҳандаҳои фармоишӣ барои якҷо кардани хусусиятҳо низ муфиданд. Ин FunctionTransformer нисбати хусусиятҳои 0 ва 1-ро ҳисоб мекунад:

>>> ratio_transformer = FunctionTransformer(lambda X: X[:, [0]] / X[:, [1]])
>>> ratio_transformer.transform(np.array([[1., 2.], [3., 4.]]))
array([[0.5 ],
       [0.75]])

FunctionTransformer қулай аст, аммо агар хоҳед табдилдиҳанда дар fit() параметр омӯзад ва дар transform() истифода барад, бояд синфи фармоишӣ нависед.

Эзоҳ. Қисми боқимондаи ин бахш таърифи синфҳои табдилдиҳандаи фармоиширо мефаҳмонад. Аз ҷумла ноҳияҳоро ба 10 кластери ҷуғрофӣ ҷудо карда, фосилаи ҳар ноҳияро то марказҳои онҳо чен мекунад ва 10 хусусияти монандии RBF илова менамояд. Азбаски ин мавзуъ каме пешрафта аст, метавонед ба бахши навбатӣ гузаред ва ҳангоми зарурат баргардед.

Scikit-Learn ба duck typing такя мекунад, бинобар ин синфи фармоишӣ набояд ҳатман аз синфи пояи муайян мерос гирад. Танҳо fit(), ки бояд self баргардонад, transform() ва fit_transform() лозиманд. Бо илова кардани TransformerMixin ҳамчун синфи поя fit_transform()-ро тайёр мегиред: татбиқи пешфарз аввал fit(), баъд transform()-ро даъват мекунад. Бо иловаи BaseEstimator ва истифода накардани *args ва **kwargs дар созанда, get_params() ва set_params()-ро низ мегиред; онҳо барои танзими худкори гиперпараметрҳо муфиданд.

Масалан, ин табдилдиҳанда мисли StandardScaler амал мекунад:

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils.validation import check_array, check_is_fitted

class StandardScalerClone(BaseEstimator, TransformerMixin):
    def __init__(self, with_mean=True):  # no *args or **kwargs!
        self.with_mean = with_mean

    def fit(self, X, y=None):  # y is required even though we don't use it
        X = check_array(X)  # checks that X is an array with finite float values
        self.mean_ = X.mean(axis=0)
        self.scale_ = X.std(axis=0)
        self.n_features_in_ = X.shape[1]  # every estimator stores this in fit()
        return self  # always return self!

    def transform(self, X):
        check_is_fitted(self)  # looks for learned attributes (with trailing _)
        X = check_array(X)
        assert self.n_features_in_ == X.shape[1]
        if self.with_mean:
            X = X - self.mean_
        return X / self.scale_

Чанд нукта:

  • sklearn.utils.validation барои санҷиши вуруд функсияҳо дорад. Барои содагӣ дар идомаи китоб чунин санҷишҳоро намеорем, аммо рамзи муҳити воқеӣ бояд дошта бошад.
  • Пайплайнҳо талаб мекунанд, ки fit() аргументҳои X ва y дошта бошад; бинобар ин y=None лозим аст, гарчанде y истифода намешавад.
  • Ҳамаи арзёбандаҳо дар fit() қимати n_features_in_-ро муайян карда, шумораи хусусиятҳоро дар transform() ё predict() месанҷанд.
  • fit() бояд self баргардонад.
  • Ин татбиқ пурра нест: барои вуруди DataFrame бояд feature_names_in_ муайян шавад. Ҳар табдилдиҳанда бояд get_feature_names_out() ва, агар табдил баргардондашаванда бошад, inverse_transform() дошта бошад.

Табдилдиҳандаи фармоишӣ метавонад дар дохил арзёбандаҳои дигарро истифода барад ва аксар вақт ҳамин тавр мекунад. Масалан, ин синф дар fit() бо KMeans кластерҳои асосиро меёбад ва дар transform() бо rbf_kernel() монандии ҳар намунаро ба маркази ҳар кластер чен мекунад:

from sklearn.cluster import KMeans

class ClusterSimilarity(BaseEstimator, TransformerMixin):
    def __init__(self, n_clusters=10, gamma=1.0, random_state=None):
        self.n_clusters = n_clusters
        self.gamma = gamma
        self.random_state = random_state

    def fit(self, X, y=None, sample_weight=None):
        self.kmeans_ = KMeans(self.n_clusters, random_state=self.random_state)
        self.kmeans_.fit(X, sample_weight=sample_weight)
        return self  # always return self!

    def transform(self, X):
        return rbf_kernel(X, self.kmeans_.cluster_centers_, gamma=self.gamma)

    def get_feature_names_out(self, names=None):
        return [f"Cluster {i} similarity" for i in range(self.n_clusters)]

Маслиҳат. Барои санҷидани мувофиқати арзёбандаи худ ба API-и Scikit-Learn объекти онро ба check_estimator() аз sklearn.utils.estimator_checks диҳед. API-и пурра дар ҳуҷҷатгузории таҳиягарон аст.

Чунон ки дар боби 8 мебинед, k-means кластерҳоро меёбад; масалан, минтақаҳои сернуфуси Калифорнияро. n_clusters шумораи кластерҳоро идора мекунад. fit()-и KMeans аргументи ихтиёрии sample_weight дорад, ки вазни нисбии намунаҳоро муайян мекунад. Агар хоҳед кластерҳо ба ноҳияҳои доро майл кунанд, медианаи даромадро ҳамчун вазн медиҳед. Марказҳо баъди омӯзиш дар cluster_centers_ дастрасанд. k-means алгоритми стохастикӣ аст ва ба тасодуф такя мекунад; барои натиҷаи такроршаванда random_state гузоред. Бо вуҷуди мураккабии вазифа рамз сода аст. Онро истифода мекунем:

cluster_simil = ClusterSimilarity(n_clusters=10, gamma=1., random_state=42)
similarities = cluster_simil.fit_transform(housing[["latitude", "longitude"]])

Рамз ClusterSimilarity-ро бо 10 кластер месозад ва fit_transform()-ро бо арзу тӯли ҳамаи ноҳияҳои омӯзишӣ даъват мекунад. Метавонед вазндиҳиро аз рӯйи даромад санҷида, таъсирро бинед. Табдилдиҳанда кластерҳоро меёбад ва монандии гауссии ҳар ноҳияро ба ҳамаи 10 марказ ҳисоб мекунад. Натиҷа матритсаест бо як сатр барои ҳар ноҳия ва як сутун барои ҳар кластер. Се сатри аввал бо гирдкунӣ то ду рақами даҳӣ:

>>> similarities[:3].round(2)
array([[0.46, 0.  , 0.08, 0.  , 0.  , 0.  , 0.  , 0.98, 0.  , 0.  ],
       [0.  , 0.96, 0.  , 0.03, 0.04, 0.  , 0.  , 0.  , 0.11, 0.35],
       [0.34, 0.  , 0.45, 0.  , 0.  , 0.  , 0.01, 0.73, 0.  , 0.  ]])

Расми 2.19 марказҳои 10 кластерро нишон медиҳад. Ноҳияҳо аз рӯйи монандии ҷуғрофӣ ба наздиктарин марказ ранг шудаанд. Аксари кластерҳо дар минтақаҳои сернуфусанд.

Монандӣ ба марказҳои кластерҳо

Расми 2.19. Монандии RBF-и гауссӣ ба маркази наздиктарин кластер.

Пайплайнҳои табдил

Қадамҳои зиёди табдил бояд бо тартиби дуруст иҷро шаванд. Синфи Pipeline ёрӣ медиҳад. Ин пайплайни хурд барои атрибутҳои ададӣ аввал қиматҳои гумшударо пур ва баъд хусусиятҳоро миқёсбандӣ мекунад:

from sklearn.pipeline import Pipeline

num_pipeline = Pipeline([
    ("impute", SimpleImputer(strategy="median")),
    ("standardize", StandardScaler()),
])

Созандаи Pipeline рӯйхати ҷуфтҳои ном ва арзёбанда — кортежҳои дуунсура — мегирад. Номҳо метавонанд дилхоҳ бошанд, аммо бояд ягона буда, __ надошта бошанд. Баъдтар дар танзими гиперпараметрҳо муфид мешаванд. Ҳамаи арзёбандаҳо ғайр аз охирин бояд табдилдиҳанда бошанд, яъне fit_transform() дошта бошанд. Охирин метавонад табдилдиҳанда, пешгӯикунанда ё арзёбандаи дигар бошад.

Маслиҳат. Дар Jupyter баъди import sklearn ва sklearn.set_config(display="diagram") арзёбандаҳо ҳамчун диаграммаҳои интерактивӣ нишон дода мешаванд. Барои пайплайнҳо махсусан қулай аст. Барои дидани num_pipeline онро сатри охирини ҳуҷайра гузоред. Пахши арзёбанда тафсилотро нишон медиҳад.

Агар номгузорӣ нахоҳед, make_pipeline() табдилдиҳандаҳоро ҳамчун аргументҳои мавқеӣ гирифта, номҳои синфҳояшонро бо ҳарфҳои хурд ва бе зеркашида истифода мебарад, масалан "simpleimputer":

from sklearn.pipeline import make_pipeline

num_pipeline = make_pipeline(SimpleImputer(strategy="median"), StandardScaler())

Агар номҳо такрор шаванд, индекс илова мешавад: foo-1, foo-2 ва ғайра.

Ҳангоми fit()-и пайплайн барои ҳар табдилдиҳанда пайдарпай fit_transform() даъват мешавад ва баромади яке вуруди навбатист. Барои арзёбандаи охирин танҳо fit() даъват мешавад.

Пайплайн ҳамон методҳои арзёбандаи охиринро пешниҳод мекунад. Дар ин ҷо охирин StandardScaler аст, пас пайплайн низ табдилдиҳанда буда, transform() тамоми табдилҳоро пайдарпай татбиқ мекунад. Агар охирин пешгӯикунанда бошад, пайплайн ба ҷойи transform() методи predict() дорад: аввал додаҳоро табдил дода, баъд ба predict()-и пешгӯикунанда медиҳад.

fit_transform()-ро даъват карда, ду сатри аввалро то ду рақами даҳӣ мебинем:

>>> housing_num_prepared = num_pipeline.fit_transform(housing_num)
>>> housing_num_prepared[:2].round(2)
array([[-1.42,  1.01,  1.86,  0.31,  1.37,  0.14,  1.39, -0.94],
       [ 0.6 , -0.7 ,  0.91, -0.31, -0.44, -0.69, -0.37,  1.17]])

Барои барқарор кардани DataFrame аз get_feature_names_out() истифода баред:

df_housing_num_prepared = pd.DataFrame(
    housing_num_prepared, columns=num_pipeline.get_feature_names_out(),
    index=housing_num.index)

Пайплайнҳо индексгузориро дастгирӣ мекунанд: pipeline[1] арзёбандаи дуюм ва pipeline[:-1] пайплайни бе арзёбандаи охиринро медиҳад. steps рӯйхати ҷуфтҳои ном/арзёбанда ва named_steps луғати номҳо ба арзёбандаҳост. Масалан, num_pipeline["simpleimputer"] арзёбандаи ҳамин номро медиҳад.

То ин ҷо сутунҳои категориявӣ ва ададиро ҷудо коркард кардем. Як табдилдиҳандае, ки ба ҳар сутун амали мувофиқро татбиқ мекунад, қулайтар аст. Барои ин ColumnTransformer ҳаст. Масалан, ин рамз num_pipeline-ро ба сутунҳои ададӣ ва cat_pipeline-ро ба категориявӣ татбиқ мекунад:

from sklearn.compose import ColumnTransformer

num_attribs = ["longitude", "latitude", "housing_median_age", "total_rooms",
               "total_bedrooms", "population", "households", "median_income"]
cat_attribs = ["ocean_proximity"]

cat_pipeline = make_pipeline(
    SimpleImputer(strategy="most_frequent"),
    OneHotEncoder(handle_unknown="ignore"))

preprocessing = ColumnTransformer([
    ("num", num_pipeline, num_attribs),
    ("cat", cat_pipeline, cat_attribs),
])

Аввал синфро ворид мекунем, рӯйхатҳои сутунҳоро муайян карда, пайплайни содаи категориявиро месозем. Созандаи ColumnTransformer рӯйхати сегонаҳо мегирад: номи ягонаи бе __, табдилдиҳанда ва рӯйхати номҳо ё индексҳои сутунҳои мувофиқ.

Маслиҳат. Ба ҷойи табдилдиҳанда "drop" диҳед, то сутунҳо хориҷ шаванд, ё "passthrough", то бетағйир монанд. Сутунҳои номбарнашуда пешфарз хориҷ мешаванд. Барои кори дигар remainder-ро ба табдилдиҳанда ё "passthrough" гузоред.

Азбаски рӯйхат кардани ҳамаи номҳо қулай нест, make_column_selector метавонад хусусиятҳои навъи муайян, мисли ададӣ ё категориявиро худкор интихоб кунад. Онро ба ҷойи номҳо ё индексҳо медиҳед. Агар номгузории табдилдиҳандаҳо ҳам муҳим набошад, make_column_transformer() мисли make_pipeline() номҳоро интихоб мекунад. Ин мисол ҳамон ColumnTransformer-ро месозад, аммо бо номҳои худкори pipeline-1 ва pipeline-2 ба ҷойи num ва cat:

from sklearn.compose import make_column_selector, make_column_transformer

preprocessing = make_column_transformer(
    (num_pipeline, make_column_selector(dtype_include=np.number)),
    (cat_pipeline, make_column_selector(dtype_include=object)),
)

Акнун ба додаҳои манзил татбиқ мекунем:

housing_prepared = preprocessing.fit_transform(housing)

Пайплайни пешкоркард тамоми маҷмӯи омӯзиширо гирифта, ҳар табдилдиҳандаро ба сутунҳои мувофиқ татбиқ ва сутунҳои натиҷаро уфуқӣ якҷо мекунад. Табдилдиҳандаҳо набояд шумораи сатрҳоро тағйир диҳанд. Натиҷа боз массиви NumPy аст. Бо preprocessing.get_feature_names_out() номҳоро гирифта, мисли пеш DataFrame созед.

Эзоҳ. OneHotEncoder матритсаи тунук ва num_pipeline матритсаи зич медиҳанд. Ҳангоми омезиш ColumnTransformer зичии матритсаи ниҳоӣ (ҳиссаи қиматҳои ғайрисифрӣ)-ро ҳисоб мекунад. Агар аз ҳадди пешфарзи sparse_threshold=0.3 камтар бошад, матритсаи тунук медиҳад. Дар ин мисол натиҷа зич аст.

Лоиҳа хуб пеш меравад ва қариб барои омӯзонидани моделҳо омодаед! Акнун як пайплайн созед, ки ҳамаи табдилҳои санҷидашударо анҷом диҳад:

  • Қиматҳои гумшудаи ададӣ бо медиана ва категориявӣ бо категорияи сертакрор пур мешаванд, зеро аксари алгоритмҳо қимати гумшуда қабул намекунанд.
  • Хусусияти категориявӣ бо усули one-hot рамзгузорӣ мешавад, зеро аксари алгоритмҳо танҳо адад мегиранд.
  • Нисбатҳои bedrooms_ratio, rooms_per_house ва people_per_house илова мешаванд, бо умеди ҳамбастагии беҳтар бо арзиши манзил.
  • Хусусиятҳои монандӣ ба кластерҳо илова мешаванд; эҳтимол аз арзу тӯл муфидтаранд.
  • Хусусиятҳои думдароз бо логарифмашон иваз мешаванд, зеро аксари моделҳо тақсимоти тақрибан яксон ё гауссиро афзал медонанд.
  • Ҳамаи хусусиятҳои ададӣ стандартисозӣ мешаванд, зеро миқёси тақрибан яксон муносибтар аст.

Рамзи сохтани чунин пайплайн акнун бояд шинос бошад:

def column_ratio(X):
    return X[:, [0]] / X[:, [1]]

def ratio_name(function_transformer, feature_names_in):
    return ["ratio"]  # feature names out

def ratio_pipeline():
    return make_pipeline(
        SimpleImputer(strategy="median"),
        FunctionTransformer(column_ratio, feature_names_out=ratio_name),
        StandardScaler())

log_pipeline = make_pipeline(
    SimpleImputer(strategy="median"),
    FunctionTransformer(np.log, feature_names_out="one-to-one"),
    StandardScaler())
cluster_simil = ClusterSimilarity(n_clusters=10, gamma=1., random_state=42)
default_num_pipeline = make_pipeline(SimpleImputer(strategy="median"),
                                     StandardScaler())
preprocessing = ColumnTransformer([
        ("bedrooms", ratio_pipeline(), ["total_bedrooms", "total_rooms"]),
        ("rooms_per_house", ratio_pipeline(), ["total_rooms", "households"]),
        ("people_per_house", ratio_pipeline(), ["population", "households"]),
        ("log", log_pipeline, ["total_bedrooms", "total_rooms", "population",
                               "households", "median_income"]),
        ("geo", cluster_simil, ["latitude", "longitude"]),
        ("cat", cat_pipeline, make_column_selector(dtype_include=object)),
    ],
    remainder=default_num_pipeline)  # one column remaining: housing_median_age

Он ҳамаи табдилҳоро иҷро карда, массиви NumPy бо 24 хусусият медиҳад:

>>> housing_prepared = preprocessing.fit_transform(housing)
>>> housing_prepared.shape
(16512, 24)
>>> preprocessing.get_feature_names_out()
array(['bedrooms__ratio', 'rooms_per_house__ratio',
       'people_per_house__ratio', 'log__total_bedrooms',
       'log__total_rooms', 'log__population', 'log__households',
       'log__median_income', 'geo__Cluster 0 similarity', [...],
       'geo__Cluster 9 similarity', 'cat__ocean_proximity_<1H OCEAN',
       'cat__ocean_proximity_INLAND', 'cat__ocean_proximity_ISLAND',
       'cat__ocean_proximity_NEAR BAY', 'cat__ocean_proximity_NEAR OCEAN',
       'remainder__housing_median_age'], dtype=object)

Моделро интихоб ва омӯзонед

Ниҳоят! Масъаларо гузоштед, додаҳоро гирифтед ва таҳқиқ кардед, маҷмӯаҳои омӯзишӣ ва санҷишӣ сохтед ва пайплайни тозакуниву омодасозии худкор навиштед. Акнун барои интихоб ва омӯзонидани модел омодаед.

Омӯзиш ва арзёбӣ дар маҷмӯи омӯзишӣ

Ба шарофати қадамҳои пешина акнун кор осон аст. Барои оғоз регрессияи хеле содаи хаттиро меомӯзонед:

from sklearn.linear_model import LinearRegression

lin_reg = make_pipeline(preprocessing, LinearRegression())
lin_reg.fit(housing, housing_labels)

Тайёр! Модели коршоям доред. Панҷ пешгӯии аввалро дар маҷмӯи омӯзишӣ бо барчаспҳо муқоиса кунед:

>>> housing_predictions = lin_reg.predict(housing)
>>> housing_predictions[:5].round(-2)  # -2 = rounded to the nearest hundred
array([246000., 372700., 135700.,  91400., 330900.])
>>> housing_labels.iloc[:5].values
array([458300., 483800., 101700.,  96100., 361800.])

Кор мекунад, аммо на ҳамеша: пешгӯии аввал бештар аз 200 000 доллар фарқ дорад! Дигарон беҳтаранд: дуто тақрибан 25 фоиз ва дуто камтар аз 10 фоиз хато доранд. Меъёри интихобӣ RMSE буд; онро бо root_mean_squared_error() дар тамоми маҷмӯи омӯзишӣ чен мекунем:

>>> from sklearn.metrics import root_mean_squared_error
>>> lin_rmse = root_mean_squared_error(housing_labels, housing_predictions)
>>> lin_rmse
68972.88910758484

Маслиҳат. score()-ро истифода намебарем, зеро он RMSE не, коэффисиенти муайянкунии R²-ро медиҳад. Он ҳиссаи парокандагии додаҳоро ифода мекунад, ки модел шарҳ дода метавонад. Ҳар қадар ба ҳадди болоии 1 наздиктар бошад, беҳтар аст. Агар модел ҳамеша танҳо миёнаро пешгӯӣ кунад, ҳеҷ қисми парокандагиро шарҳ намедиҳад ва R² = 0 аст. Агар аз ин ҳам бадтар бошад, R² метавонад манфӣ ва ҳатто ба қадри дилхоҳ паст бошад.

Ин аз ҳеҷ чиз беҳтар аст, вале натиҷаи хуб нест: медианаи нархи аксари ноҳияҳо байни 120 000 ва 265 000 доллар аст ва хатои маъмулии 68 973 доллар қонеъкунанда нест. Ин каммутобиқшавӣ аст. Шояд хусусиятҳо маълумоти кофӣ надоранд ё модел тавоноии кофӣ надорад. Роҳҳои асосӣ интихоби модели тавонотар, хусусиятҳои беҳтар ё кам кардани маҳдудиятҳо мебошанд. Модел мунтазамсозӣ нашудааст, пас роҳи охир мувофиқ нест. Метавон хусусиятҳои бештар илова кард, аммо аввал модели мураккабтарро месанҷем.

DecisionTreeRegressor-ро интихоб мекунед: он тавоно буда, робитаҳои мураккаби ғайрихаттиро меёбад. Дар боби 5 дар бораи дарахтҳои қарор бештар мефаҳмед:

from sklearn.tree import DecisionTreeRegressor

tree_reg = make_pipeline(preprocessing, DecisionTreeRegressor(random_state=42))
tree_reg.fit(housing, housing_labels)

Пас аз омӯзиш дар маҷмӯи омӯзишӣ арзёбӣ мекунед:

>>> housing_predictions = tree_reg.predict(housing)
>>> tree_rmse = root_mean_squared_error(housing_labels, housing_predictions)
>>> tree_rmse
0.0

Чӣ? Умуман хато нест? Оё модел комил аст? Албатта, эҳтимолан ба додаҳо сахт аз ҳад мутобиқ шудааст. Чӣ тавр мутмаин мешавем? Маҷмӯи санҷиширо то омодагии модели боэътимод даст намезанем. Пас қисми додаҳои омӯзиширо барои омӯзиш ва қисми дигарро барои тасдиқ истифода мебарем.

Арзёбии беҳтар бо санҷиши салибӣ

Як роҳ ин аст, ки бо train_test_split() маҷмӯи омӯзиширо ба маҷмӯи хурдтари омӯзишӣ ва маҷмӯи тасдиқӣ тақсим кунед, моделро бо якум омӯзонед ва бо дуюм арзёбӣ намоед. Каме кор мехоҳад, аммо душвор нест ва хуб кор мекунад.

Интихоби аъло санҷиши салибии k-қисмӣ (k-fold cross-validation) аст. Маҷмӯи омӯзишӣ ба k қисми ҳамдигарро напӯшонанда — fold — ҷудо мешавад. Модел k бор омӯзонида ва арзёбӣ мешавад: ҳар бор як қисми дигар барои тасдиқ ва k − 1 қисми боқимонда барои омӯзиш истифода мешаванд. Натиҷа k баҳои арзёбӣ аст (расми 2.20).

Санҷиши салибии 10-қисмӣ

Расми 2.20. Санҷиши салибии k-қисмӣ бо k = 10.

cross_val_score() ин корро карда, массиви k баҳоро медиҳад. Масалан, дарахти регрессияро бо k = 10 месанҷем:

from sklearn.model_selection import cross_val_score

tree_rmses = -cross_val_score(tree_reg, housing, housing_labels,
                              scoring="neg_root_mean_squared_error", cv=10)

Огоҳӣ. Санҷиши салибии Scikit-Learn функсияи фоиданокиро интизор аст — бештар беҳтар — на хароҷотро — камтар беҳтар. Бинобар ин функсияи баҳодиҳӣ RMSE-и манфӣ медиҳад. Барои гирифтани RMSE аломатро баръакс кунед.

Натиҷаҳоро мебинем:

>>> pd.Series(tree_rmses).describe()
count       10.000000
mean     66573.734600
std       1103.402323
min      64607.896046
25%      66204.731788
50%      66388.272499
75%      66826.257468
max      68532.210664
dtype: float64

Акнун дарахт он қадар хуб наменамояд: қариб мисли регрессияи хаттӣ бад кор мекунад! Санҷиши салибӣ на танҳо самаранокиро, балки дақиқии тахмини онро тавассути инҳирофи стандартӣ нишон медиҳад. RMSE-и дарахт тақрибан 66 574 ва инҳирофи стандартӣ 1 103 аст. Бо танҳо як маҷмӯи тасдиқӣ ин маълумотро намегирифтед. Аммо чанд бор омӯзонидан хароҷот дорад ва ҳамеша имконпазир нест.

Барои регрессияи хаттӣ миёнаи RMSE 70 003 ва инҳирофи стандартӣ 4 182 мешавад. Пас дарахт каме беҳтар аст, аммо аз сабаби аз ҳад мутобиқшавии ҷиддӣ фарқ кам аст. Мушкилро аз он медонем, ки хатои омӯзиш паст — дар асл сифр — ва хатои тасдиқӣ баланд аст.

Боз як моделро месанҷем: RandomForestRegressor. Чунон ки дар боби 6 мебинед, ҷангали тасодуфӣ дарахтҳои зиёди қарорро бо зермаҷмӯаҳои тасодуфии хусусиятҳо меомӯзонад ва пешгӯиҳояшонро миёна мегирад. Моделҳои аз чанд модел таркибёфта ансамблҳо ном доранд. Агар моделҳои асосӣ гуногун бошанд, хатоҳояшон камҳамбаста мешаванд ва миёнагирӣ хатоҳоро ҳамвор карда, аз ҳад мутобиқшавиро кам ва самаранокиро беҳтар мекунад. Рамз монанд аст:

from sklearn.ensemble import RandomForestRegressor

forest_reg = make_pipeline(preprocessing,
                           RandomForestRegressor(random_state=42))
forest_rmses = -cross_val_score(forest_reg, housing, housing_labels,
                                scoring="neg_root_mean_squared_error", cv=10)

Баҳоҳо:

>>> pd.Series(forest_rmses).describe()
count       10.000000
mean     47038.092799
std       1021.491757
min      45495.976649
25%      46510.418013
50%      47118.719249
75%      47480.519175
max      49140.832210
dtype: float64

Хеле беҳтар! Ҷангалҳои тасодуфӣ барои ин вазифа умедбахшанд. Аммо агар онро омӯзонида, RMSE-и маҷмӯи омӯзиширо чен кунед, тақрибан 17 551 мегиред: хеле пасттар аст, пас ҳанӯз аз ҳад мутобиқшавӣ зиёд мебошад. Роҳҳои ҳал сода кардан, маҳдуд ё мунтазамсозӣ кардани модел ва ҷамъоварии додаҳои хеле бештаранд. Вале пеш аз амиқ шудан ба ҷангалҳои тасодуфӣ моделҳои гурӯҳҳои дигарро ҳам, масалан мошинҳои векторҳои такягоҳӣ бо ядроҳои гуногун ва шояд шабакаи нейрониро, санҷед. Барои танзими гиперпараметрҳо ҳоло вақти зиёд надиҳед. Ҳадаф рӯйхати кӯтоҳи ду то панҷ модели умедбахш аст.

Моделро танзими дақиқ кунед

Фарз мекунем акнун рӯйхати моделҳои умедбахш доред. Бояд онҳоро танзими дақиқ кунед. Чанд роҳро мебинем.

Ҷустуҷӯи шабакавӣ

Метавон гиперпараметрҳоро дастӣ тағйир дода, таркиби хуб ёфт. Аммо ин кори дилгиркунанда аст ва шояд барои санҷидани таркибҳои зиёд вақт нарасад.

Ба ҷойи он GridSearchCV-и Scikit-Learn ҷустуҷӯ мекунад. Танҳо гиперпараметрҳо ва қиматҳои санҷиданиро муайян мекунед ва он ҳамаи таркибҳоро бо санҷиши салибӣ арзёбӣ мекунад. Ин мисол беҳтарин таркибро барои RandomForestRegressor меҷӯяд:

from sklearn.model_selection import GridSearchCV

full_pipeline = Pipeline([
    ("preprocessing", preprocessing),
    ("random_forest", RandomForestRegressor(random_state=42)),
])
param_grid = [
    {'preprocessing__geo__n_clusters': [5, 8, 10],
     'random_forest__max_features': [4, 6, 8]},
    {'preprocessing__geo__n_clusters': [10, 15],
     'random_forest__max_features': [6, 8, 10]},
]
grid_search = GridSearchCV(full_pipeline, param_grid, cv=3,
                           scoring='neg_root_mean_squared_error')
grid_search.fit(housing, housing_labels)

Ба ҳар гиперпараметри ҳар арзёбандаи пайплайн муроҷиат карда метавонед, ҳатто агар дар чанд пайплайн ва табдилдиҳандаи сутунӣ ҷой гирифта бошад. Масалан, Scikit-Learn сатри "preprocessing__geo__n_clusters"-ро аз рӯйи __ ҷудо мекунад. Аввал дар пайплайн preprocessing-ро меёбад, ки ColumnTransformer аст; дар он geo-ро меёбад, ки ClusterSimilarity барои арзу тӯл аст; сипас n_clusters-и онро мегирад. Ҳамин тавр, random_forest__max_features ба гиперпараметри max_features-и модели бо номи random_forest ишора мекунад. Ин гиперпараметр дар боби 6 шарҳ дода мешавад.

Маслиҳат. Ҷойгир кардани пешкоркард дар пайплайн имкон медиҳад гиперпараметрҳои пешкоркард ва моделро якҷо танзим кунед. Онҳо аксар вақт ба ҳам таъсир мекунанд: масалан, афзоиши n_clusters шояд афзоиши max_features-ро ҳам талаб кунад. Агар омӯзонидани табдилдиҳандаҳо гарон бошад, memory-и пайплайнро ба роҳи феҳристи кэш гузоред. Scikit-Learn бори аввал табдилдиҳандаҳои омӯзонидашударо нигоҳ медорад ва ҳангоми омӯзиши нав бо ҳамон гиперпараметрҳо онҳоро аз кэш мегирад.

Дар param_grid ду луғат ҳаст. Аз якум 3 × 3 = 9 ва аз дуюм 2 × 3 = 6 таркиб санҷида мешавад: ҳамагӣ 15 таркиб. Бо санҷиши салибии сеқисмӣ ҳар таркиб се бор омӯзонида мешавад, яъне 15 × 3 = 45 даври омӯзиш! Мумкин аст вақт гирад. Баъд беҳтарин таркибро мегиред:

>>> grid_search.best_params_
{'preprocessing__geo__n_clusters': 15, 'random_forest__max_features': 6}

Дар ин мисол беҳтарин модел бо n_clusters=15 ва max_features=6 ҳосил мешавад.

Маслиҳат. Азбаски 15 бузургтарин қимати санҷидашудаи n_clusters аст, шояд ҷустуҷӯро бо қиматҳои баландтар такрор кунед: баҳо метавонад боз беҳтар шавад.

Беҳтарин арзёбанда дар grid_search.best_estimator_ дастрас аст. Агар refit=True бошад — қимати пешфарз — GridSearchCV баъди интихоби беҳтарин бо санҷиши салибӣ онро бо тамоми маҷмӯи омӯзишӣ боз меомӯзонад. Ин одатан хуб аст, зеро додаҳои бештар метавонанд самаранокиро беҳтар кунанд.

Баҳоҳо дар grid_search.cv_results_ ҳастанд. Он луғат аст; бо табдил ба DataFrame рӯйхати баҳои ҳар таркиб, ҳар тақсимот ва миёнаи ҳамаи тақсимотҳоро мегиред:

>>> cv_res = pd.DataFrame(grid_search.cv_results_)
>>> cv_res.sort_values(by="mean_test_score", ascending=False, inplace=True)
>>> [...]  # change column names to fit on this page, and show rmse = -score
>>> cv_res.head()  # note: the 1st column is the row ID
    n_clusters  max_features  split0  split1  split2  mean_test_rmse
12          15             6   42725   43708   44335           43590
13          15             8   43486   43820   44900           44069
6           10             4   43798   44036   44961           44265
9           10             6   43710   44163   44967           44280
7           10             6   43710   44163   44967           44280

Миёнаи RMSE-и беҳтарин модел 43 590 аст, ки аз 47 038-и параметрҳои пешфарз беҳтар мебошад. Табрик, беҳтарин моделро бомуваффақият танзими дақиқ кардед!

Ҷустуҷӯи тасодуфӣ

Ҷустуҷӯи шабакавӣ барои таркибҳои нисбатан кам хуб аст, аммо RandomizedSearchCV, махсусан дар фазои калони гиперпараметрҳо, аксар вақт беҳтар аст. Истифодааш монанд мебошад, вале ба ҷойи ҳамаи таркибҳо шумораи муайяни онҳоро арзёбӣ мекунад ва ҳар давр барои ҳар гиперпараметр қимати тасодуфӣ мегирад. Ин чанд бартарӣ дорад:

  • Агар гиперпараметр пайваста ё дискретӣ бо қиматҳои бисёр бошад, 1 000 давр 1 000 қимати гуногуни онро таҳқиқ мекунад. Ҷустуҷӯи шабакавӣ танҳо чанд қимати рӯйхатшударо месанҷад.
  • Агар гиперпараметр дар асл таъсири кам дошта бошад, аммо инро ҳанӯз надонед, илова кардани 10 қимати он ба ҷустуҷӯи шабакавӣ омӯзишро 10 маротиба дароз мекунад. Ба ҷустуҷӯи тасодуфӣ илова кардан шумораи даврҳоро тағйир намедиҳад.
  • Барои 6 гиперпараметри ҳар кадом дорои 10 қимат, ҷустуҷӯи шабакавӣ як миллион омӯзиш талаб мекунад. Ҷустуҷӯи тасодуфиро бо ҳар шумораи дилхоҳи давр иҷро карда метавонед.

Барои ҳар гиперпараметр рӯйхати қиматҳо ё тақсимоти эҳтимолият диҳед:

from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint

param_distribs = {'preprocessing__geo__n_clusters': randint(low=3, high=50),
                  'random_forest__max_features': randint(low=2, high=20)}

rnd_search = RandomizedSearchCV(
    full_pipeline, param_distributions=param_distribs, n_iter=10, cv=3,
    scoring='neg_root_mean_squared_error', random_state=42)

rnd_search.fit(housing, housing_labels)

Scikit-Learn ҳамчунин HalvingRandomSearchCV ва HalvingGridSearchCV дорад. Онҳо захираҳоро самараноктар истифода мекунанд, то тезтар омӯзанд ё фазои калонтарро санҷанд. Дар даври аввал таркибҳои зиёди гиперпараметрҳо — «номзадҳо» — бо усули шабакавӣ ё тасодуфӣ сохта мешаванд. Моделҳо бо онҳо омӯзонида шуда, бо санҷиши салибӣ арзёбӣ мешаванд, аммо бо захираҳои маҳдуд. Пешфарз ин маънои истифодаи қисми хурди маҷмӯи омӯзиширо дорад. Маҳдудиятҳои дигар, масалан кам кардани даврҳои омӯзиш, агар гиперпараметри мувофиқ бошад, низ имконпазиранд. Танҳо номзадҳои беҳтарин ба даври дуюм бо захираҳои бештар мегузаранд. Пас аз чанд давр номзадҳои ниҳоӣ бо тамоми захираҳо арзёбӣ мешаванд. Ин метавонад вақти танзимро сарфа кунад.

Усулҳои ансамблӣ

Роҳи дигари беҳтарсозӣ якҷо кардани моделҳои беҳтарин аст. Гурӯҳ ё ансамбл аксар вақт аз беҳтарин модели алоҳида беҳтар кор мекунад, мисли ҷангали тасодуфӣ нисбат ба дарахтҳои алоҳида, махсусан агар моделҳо хатоҳои хеле гуногун кунанд. Масалан, модели k ҳамсояи наздиктаринро омӯзонидаву танзим карда, ансамбле созед, ки миёнаи пешгӯии он ва ҷангали тасодуфиро мебарорад. Дар боби 6 бештар мебинем.

Таҳлили моделҳои беҳтарин ва хатоҳои онҳо

Таҳлили моделҳои беҳтарин аксар вақт фаҳмиши хуб медиҳад. Масалан, RandomForestRegressor аҳаммияти нисбии атрибутҳоро барои пешгӯии дуруст нишон медиҳад:

>>> final_model = rnd_search.best_estimator_  # includes preprocessing
>>> feature_importances = final_model["random_forest"].feature_importances_
>>> feature_importances.round(2)
array([0.07, 0.05, 0.05, 0.01, 0.01, 0.01, 0.01, 0.19, [...], 0.  , 0.01])

Баҳоҳои аҳаммиятро камшаванда мураттаб карда, бо номҳои хусусиятҳо нишон медиҳем:

>>> sorted(zip(feature_importances,
...            final_model["preprocessing"].get_feature_names_out()),
...        reverse=True)
...
[(np.float64(0.18599734460509476), 'log__median_income'),
 (np.float64(0.07338850855844489), 'cat__ocean_proximity_INLAND'),
 (np.float64(0.06556941990883976), 'bedrooms__ratio'),
 (np.float64(0.053648710076725316), 'rooms_per_house__ratio'),
 (np.float64(0.04598870861894749), 'people_per_house__ratio'),
 (np.float64(0.04175269214442519), 'geo__Cluster 30 similarity'),
 (np.float64(0.025976797232869678), 'geo__Cluster 25 similarity'),
 (np.float64(0.023595895886342255), 'geo__Cluster 36 similarity'),
 [...]
 (np.float64(0.0004325970342247361), 'cat__ocean_proximity_NEAR BAY'),
 (np.float64(3.0190221102670295e-05), 'cat__ocean_proximity_ISLAND')]

Бо ин маълумот метавонед хориҷ кардани хусусиятҳои камфоидаро санҷед. Масалан, зоҳиран танҳо як категорияи ocean_proximity воқеан муфид аст ва дигаронро хориҷ кардан мумкин аст.

Маслиҳат. sklearn.feature_selection.SelectFromModel хусусиятҳои камфоидаро худкор хориҷ карда метавонад. Ҳангоми fit() модел, одатан ҷангали тасодуфӣ, меомӯзонад, feature_importances_-ро мебинад ва муфидтаринҳоро интихоб мекунад. Ҳангоми transform() дигаронро хориҷ мекунад.

Хатоҳои мушаххаси системаро низ бинед ва бифаҳмед, ки чаро рух медиҳанд ва чӣ ислоҳ мекунад: илова кардани хусусиятҳо, хориҷ кардани хусусиятҳои бемаълумот, тоза кардани қиматҳои дур ва ғайра.

Ин вақти муносиб барои санҷиши адолатнокии модел низ ҳаст. Он на танҳо ба ҳисоби миёна, балки барои гурӯҳҳои гуногуни ноҳияҳо ҳам бояд хуб кор кунад: деҳотӣ ё шаҳрӣ, доро ё камбизоат, шимолӣ ё ҷанубӣ, дорои ақаллиятҳо ё дигарҳо. Барои ин таҳлили муфассали ғараз лозим аст: аз маҷмӯи тасдиқӣ барои ҳар категория зермаҷмӯа сохта, натиҷаро таҳлил кунед. Кор зиёд аст, вале муҳим мебошад. Агар модел барои тамоми як гурӯҳ бад кор кунад, эҳтимол то ислоҳи мушкил набояд ҷойгир шавад ё ҳадди ақал барои он гурӯҳ истифода нашавад, зеро зиёнаш метавонад аз фоида бештар бошад.

Системаро дар маҷмӯи санҷишӣ арзёбӣ кунед

Пас аз танзим ниҳоят система ба қадри кофӣ хуб кор мекунад. Акнун модели ниҳоиро дар маҷмӯи санҷишӣ арзёбӣ мекунед. Раванд махсус нест: пешгӯикунандаҳо ва барчаспҳоро ҷудо карда, бо final_model табдилу пешгӯӣ ва баъд арзёбӣ мекунед:

X_test = strat_test_set.drop("median_house_value", axis=1)
y_test = strat_test_set["median_house_value"].copy()

final_predictions = final_model.predict(X_test)

final_rmse = root_mean_squared_error(y_test, final_predictions)
print(final_rmse)  # prints 41445.533268606625

Баъзан тахмини нуқтагии хатои умумиятдиҳӣ барои қарори ба кор даровардан кофӣ нест: агар модел аз модели фаъол танҳо 0,1 фоиз беҳтар бошад, чӣ? Шояд дақиқии тахминро фаҳмидан хоҳед. Бо scipy.stats.bootstrap() фосилаи эътимоди 95-фоиза-ро ҳисоб мекунед. Фосила нисбатан васеъ, аз 39 521 то 43 702, мешавад ва тахмини нуқтагии 41 445 тақрибан дар миёнаи он аст:

from scipy import stats

def rmse(squared_errors):
    return np.sqrt(np.mean(squared_errors))

confidence = 0.95
squared_errors = (final_predictions - y_test) ** 2
boot_result = stats.bootstrap([squared_errors], rmse,
                              confidence_level=confidence, random_state=42)
rmse_lower, rmse_upper = boot_result.confidence_interval

Агар гиперпараметрҳоро бисёр танзим кунед, самаранокии ниҳоӣ одатан аз санҷиши салибӣ каме бадтар мешавад. Система ба додаҳои тасдиқӣ хуб мутобиқ шуда, шояд дар додаҳои ношинос ҳамон қадар хуб набошад. Дар ин мисол чунин нест: RMSE-и санҷишӣ аз тасдиқӣ пасттар аст. Аммо агар чунин шавад, ба васвасаи тағйир додани гиперпараметрҳо барои зеботар шудани рақамҳои санҷишӣ дода нашавед: эҳтимол беҳбудӣ ба додаҳои нав умумият намеёбад.

Акнун марҳилаи пеш аз ба кор даровардан меояд. Пешниҳоди самараноки роҳи ҳал мутахассиси аълоро аз мутахассиси хуб фарқ мекунад. Ҳисоботи кӯтоҳ дар Markdown, PDF ё слайд созед, хулосаҳои калидиро бо Matplotlib, Seaborn ё Tableau тасвирсозӣ кунед ва ба шунаванда мутобиқ намоед: барои ҳамкорон техникӣ, барои ҷонибҳои манфиатдор умумӣ. Ҷумлаҳои таъсирбахшу дар хотир монданӣ диҳед, масалан «медианаи даромад муҳимтарин пешгӯикунандаи нархи манзил аст». Фаҳмонед, ки чӣ омӯхтед, чӣ кор карду чӣ накард, кадом фарзияҳо гузошта шуданд ва маҳдудиятҳои система чистанд.

Натиҷаҳо бояд то ҳадди имкон такроршаванда бошанд. Рамзро, масалан дар GitHub, ба гурӯҳ дастрас кунед. README-и сохтордор барои қадамҳои насб нависед. Дафтарҳои равшани Jupyter бо рамз, шарҳ ва натиҷаҳо пешниҳод кунед; рамз тоза ва шарҳдор бошад. Дар requirements.txt ё environment.yml ҳамаи китобхонаҳо ва версияҳои дақиқро муайян кунед ё тасвири Docker созед. Тухмҳои генераторҳои тасодуфиро гузоред ва манбаъҳои дигари тағйирпазириро бартараф кунед.

Дар мисоли Калифорния натиҷаи ниҳоӣ аз тахмини коршиносон, ки аксар вақт 30 фоиз хато дошт, чандон беҳтар нест. Аммо ба кор даровардан ҳанӯз метавонад хуб бошад, махсусан агар вақти коршиносонро барои вазифаҳои ҷолибтару самараноктар озод кунад.

Системаро ба кор дароред, назорат кунед ва нигоҳ доред

Аъло, иҷозаи ба кор дароварданро гирифтед! Акнун роҳи ҳалро барои муҳити воқеӣ омода кунед: рамзро такмил диҳед, ҳуҷҷатгузорӣ ва санҷишҳо нависед ва ғайра. Сипас моделро ҷойгир мекунед. Роҳи одитарин нигоҳ доштани беҳтарин модели омӯзонидашуда, интиқоли файл ба муҳити истифода ва бор кардани он аст. Барои нигоҳдорӣ joblib-ро истифода баред:

import joblib

joblib.dump(final_model, "my_california_housing_model.pkl")

Маслиҳат. Аксар вақт нигоҳ доштани ҳамаи моделҳои санҷидашуда хуб аст, то ба ҳар кадом осон баргардед. Баҳоҳои санҷиши салибӣ ва шояд худи пешгӯиҳои маҷмӯи тасдиқиро ҳам нигоҳ доред. Он гоҳ баҳоҳо ва навъҳои хатоҳои моделҳои гуногунро осон муқоиса мекунед.

Пас аз интиқол моделро бор карда, истифода мебаред. Аввал ҳамаи синфу функсияҳои фармоишии заруриро ворид кунед — яъне рамзашонро ҳам интиқол диҳед — ва баъд бо joblib моделро бор карда, пешгӯӣ кунед:

import joblib
[...]  # import KMeans, BaseEstimator, TransformerMixin, rbf_kernel, etc.

def column_ratio(X): [...]
def ratio_name(function_transformer, feature_names_in): [...]
class ClusterSimilarity(BaseEstimator, TransformerMixin): [...]

final_model_reloaded = joblib.load("my_california_housing_model.pkl")

new_data = [...]  # some new districts to make predictions for
predictions = final_model_reloaded.predict(new_data)

Масалан, модел шояд дар сомона истифода шавад: корбар маълумоти ноҳияи навро ворид карда, Estimate Price — Тахмини нарх-ро пахш мекунад. Дархости додаҳо ба вебсервер, баъд ба веббарнома меравад ва рамзи шумо predict()-и моделро даъват мекунад. Моделро ҳангоми оғоз шудани сервер бор кунед, на ҳар дафъаи истифода.

Ё моделро дар вебхидмати алоҳида ҷойгир кунед, ки веббарнома тавассути REST API ба он муроҷиат мекунад (расми 2.21). Навсозии модел бе қатъи барномаи асосӣ осонтар мешавад. Васеъ кардани миқёс ҳам осон аст: вебхидматҳоро ба шумораи зарурӣ оғоз карда, дархостҳоро байни онҳо тақсим мекунед. Ғайр аз ин, веббарнома метавонад бо ҳар забон навишта шавад, на танҳо Python.

Модел ҳамчун вебхидмат

Расми 2.21. Модели ҳамчун вебхидмат ҷойгиршуда, ки веббарнома истифода мебарад.

Стратегияи дигари маъмул ҷойгиркунӣ дар абр аст, масалан Vertex AI-и Google, ки пештар Google Cloud AI Platform ва Google Cloud ML Engine ном дошт. Моделро бо joblib нигоҳ дошта, ба Google Cloud Storage — GCS — бор мекунед. Баъд дар Vertex AI версияи нави модел сохта, файли GCS-ро нишон медиҳед. Ҳамин! Вебхидмати содае мегиред, ки тақсими сарборӣ ва васеъ кардани миқёсро худаш идора мекунад. Дархостҳои JSON-и дорои додаҳои вуруд, масалан ноҳия, гирифта, ҷавобҳои JSON-и пешгӯиро бармегардонад. Онро дар сомона ё муҳити дигари истифода татбиқ мекунед.

Аммо ҷойгиркунӣ анҷоми кор нест. Бояд рамзи назорат нависед, ки самаранокии воқеиро мунтазам санҷад ва ҳангоми пастравӣ огоҳӣ диҳад. Он метавонад зуд, масалан бо вайроншавии ҷузъи инфрасохтор, ё хеле оҳиста паст шавад ва муддати дароз ноаён монад. Сабаби маъмулаш ҷойивазкунии додаҳо (data drift) аст: модели бо додаҳои соли гузашта омӯзонидашуда шояд ба додаҳои имрӯза мувофиқ набошад.

Самаранокии воқеиро чӣ гуна назорат мекунед? Ин ба ҳолат вобаста аст. Баъзан онро аз нишондиҳандаҳои баъдии система фаҳмидан мумкин аст. Масалан, агар модел маҳсулот тавсия диҳад, шумораи маҳсулоти тавсияшудаи ҳар рӯз фурӯхташударо назорат кардан осон аст. Агар ин шумора нисбат ба маҳсулоти тавсиянашуда кам шавад, гумонбари асосӣ модел аст. Шояд пайплайн вайрон шудааст ё модел ба бозомӯзӣ бо додаҳои нав ниёз дорад.

Баъзан таҳлили инсонӣ низ зарур аст. Масалан, фарз кунед модели таснифбандии тасвирро (чунин моделҳоро дар боби 3 мебинем) барои ёфтани нуқсонҳои маҳсулот дар хатти истеҳсол омӯзонидаед. Пеш аз фиристодани ҳазорон маҳсулоти нуқсондор ба муштариён чӣ гуна аз пастравии модел огоҳ мешавед? Як роҳ фиристодани намунаи аксҳои таснифшуда ба арзёбандагони инсонӣ аст, махсусан аксҳое, ки модел ба онҳо чандон бовар надошт. Вобаста ба вазифа коршинос ё ғайримутахассис, масалан корманди платформаи краудсорсинги Amazon Mechanical Turk, лозим мешавад. Дар баъзе барномаҳо худи корбарон бо пурсиш ё CAPTCHA-и ба мақсади дигар мутобиқшуда арзёбӣ мекунанд.

Ба ҳар ҳол, системаи назорат бо арзёбандагони инсонӣ ё бе онҳо ва равандҳои муайянкунандаи амал дар ҳолати нокомӣ ва омодагӣ ба онро бояд таъсис диҳед. Мутаассифона, ин кори зиёд аст; аксар вақт аз сохтани модел ва омӯзонидани он ҳам бештар.

Агар додаҳо тағйир ёбанд, маҷмӯаҳоро нав ва моделро мунтазам бозомӯзӣ мекунед. То ҳадди имкон тамоми равандро худкор созед. Масалан:

  1. Додаҳои навро мунтазам ҷамъ ва барчаспгузорӣ кунед, масалан бо арзёбандагони инсонӣ.
  2. Скрипти омӯзиш ва танзими худкори гиперпараметрҳо нависед. Он вобаста ба ниёз ҳар рӯз ё ҳар ҳафта иҷро шуда метавонад.
  3. Скрипти дигар модели нав ва пешинаро дар маҷмӯи санҷишии навшуда арзёбӣ карда, агар самаранокӣ паст нашуда бошад, модели навро ҷойгир кунад. Агар паст шавад, сабабро таҳқиқ кунед. Скрипт беҳтараш зермаҷмӯаҳои гуногун, аз ҷумла ноҳияҳои камбизоату доро ва деҳотию шаҳриро ҳам бисанҷад.

Сифати додаҳои вурудиро ҳам арзёбӣ кунед. Баъзан сигнали бесифат — сенсори вайрон бо қиматҳои тасодуфӣ ё баромади куҳнаи гурӯҳи дигар — аввал самаранокиро каме паст мекунад ва то ҳадди фаъол шудани огоҳӣ вақт мегузарад. Назорати вурудҳо барвақттар ошкор мекунад. Масалан, ҳангоми зиёд шудани қиматҳои гумшуда, аз маҷмӯи омӯзишӣ хеле дур шудани миёна ё инҳирофи стандартӣ ё пайдо шудани категорияҳои нав огоҳӣ диҳед.

Ниҳоят, нусхаи эҳтиётии ҳар моделро нигоҳ доред ва раванду воситаҳои бозгашти зуд ба модели пешинаро дошта бошед, агар модели нав бо ягон сабаб сахт ноком шавад. Нусхаҳо муқоисаи моделҳои наву пешинаро низ осон мекунанд. Аз ҳар версияи маҷмӯаҳои додаҳо ҳам нусха гиред, то агар маҷмӯи нав вайрон шавад, масалан додаҳои иловашуда пур аз қиматҳои дур бошанд, ба пешина баргардед. Бо ин роҳ ҳар моделро дар ҳар маҷмӯи пешина низ арзёбӣ карда метавонед.

Чунон ки мебинед, омӯзиши мошинӣ инфрасохтори зиёдро дар бар мегирад. Ин мавзуи фарох амалиёти омӯзиши мошинӣ (MLOps) ном дорад ва сазовори китоби алоҳида аст. Пас, ҳайрон нашавед, агар сохтани лоиҳаи аввал ва ҷойгиркунии он вақт ва заҳмати зиёд талаб кунад. Хушбахтона, баъди омода шудани инфрасохтор гузаштан аз андеша ба муҳити воқеӣ хеле тезтар мешавад.

Худатон санҷед!

Умедворам ин боб тасаввури хуби лоиҳаи омӯзиши мошиниро дод ва чанд воситаи омӯзонидани системаи хубро нишон дод. Чунон ки мебинед, қисми зиёди кор ба омодасозии додаҳо, сохтани воситаҳои назорат, ташкили пайплайнҳои арзёбии инсонӣ ва худкор кардани омӯзиши мунтазам рост меояд. Алгоритмҳо албатта муҳиманд, аммо шояд беҳтар бошад тамоми равандро хуб фаҳмед ва се-чор алгоритмро хуб донед, аз он ки тамоми вақтро ба алгоритмҳои пешрафта сарф кунед.

Пас, агар ҳанӯз накарда бошед, ноутбукро гиред, маҷмӯи ҷолиберо интихоб кунед ва тамоми равандро аз аввал то охир санҷед. Сомонаи мусобиқае мисли Kaggle ҷойи хуби оғоз аст: додаҳо барои таҷриба, ҳадафи равшан ва одамоне доред, ки таҷрибаро бо онҳо мубодила мекунед. Бароятон таҷрибаи шавқовар мехоҳам!

пешина
аз 20
навбатӣ