{"id":502650,"date":"2026-11-11T10:14:27","date_gmt":"2026-11-11T07:14:27","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=502650"},"modified":"2026-11-11T10:14:27","modified_gmt":"2026-11-11T07:14:27","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=502650","title":{"rendered":"\u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0430\u0441\u0445\u043e\u0434\u0430 \u0444\u0435\u0440\u0440\u043e\u043c\u0430\u0440\u0433\u0430\u043d\u0446\u0430 \u0432 \u0414\u0421\u041f-3 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Catboost"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u044d\u0442\u043e \u0420\u0430\u043c\u0438\u043b\u044c \u041c\u0430\u043a\u0441\u044e\u0442\u043e\u0432 \u0441\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u0446\u0438\u043a\u043b\u0430 \u043f\u0440\u043e \u043f\u043b\u0430\u0432\u043a\u0438 \u0432 \u0414\u0421\u041f-3. \u041f\u0435\u0440\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0442\u0443\u0442: <a href=\"https:\/\/habr.com\/ru\/articles\/1105616\/\" rel=\"noopener nofollow\">https:\/\/habr.com\/ru\/articles\/1105616\/<\/a><br \/>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0443\u0447\u0438\u043c CatBoost \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0434\u043e\u0437\u0443 \u0444\u0435\u0440\u0440\u043e\u043c\u0430\u0440\u0433\u0430\u043d\u0446\u0430 \u0434\u043b\u044f \u0432\u044b\u043f\u043b\u0430\u0432\u043a\u0438 \u043e\u0442\u043b\u0438\u0432\u043a\u0438 \u0438\u0437 \u0441\u0442\u0430\u043b\u0438 35\u041b \u0432 \u0434\u0443\u0433\u043e\u0432\u043e\u0439 \u0441\u0442\u0430\u043b\u0435\u043f\u043b\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0447\u0438 \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u0442\u0435\u0440\u043e\u0432\u043a\u043e\u0439.<\/p>\n<h3>\u0427\u0442\u043e \u043c\u044b \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c<\/h3>\n<p>\u0426\u0435\u043b\u044c \u2014 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u0437\u0430 \u0424\u041c\u043d78, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u0432\u043e\u0434\u0438\u0442 \u043c\u0430\u0440\u0433\u0430\u043d\u0435\u0446 \u0440\u043e\u0432\u043d\u043e \u0434\u043e \u043d\u0438\u0436\u043d\u0435\u0439 \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u0413\u041e\u0421\u0422 977-88 (0,45 %) \u043f\u0440\u0438 \u0442\u043e\u043c \u0443\u0441\u0432\u043e\u0435\u043d\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043b\u0430\u0432\u043a\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0438\u043c\u0435\u043b\u0430:<\/p>\n<p><img decoding=\"async\" class=\"formula\" source=\"m_{min} = \\frac{(Mn_{low} - Mn_{res}) \/ 100 \\cdot M_{steel}}{w_{FeMn} \\cdot r_{Mn}}\" alt=\"m_{min} = \\frac{(Mn_{low} - Mn_{res}) \/ 100 \\cdot M_{steel}}{w_{FeMn} \\cdot r_{Mn}}\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1\/17\/17a\/17a090e2a1ecf8e713e905f4921d7e89.svg\" width=\"303\" height=\"42\" data-width=\"37.928\" data-height=\"5.212\" data-vertical-align=\"-2.04\" style=\"width: 37.928ex; height: 5.212ex; vertical-align: -2.04ex\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1\/17\/17a\/17a090e2a1ecf8e713e905f4921d7e89.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1\/17\/17a\/17a090e2a1ecf8e713e905f4921d7e89.svg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<p>\u0417\u0434\u0435\u0441\u044c Mn_low = 0,45 % \u2014 \u043d\u0438\u0436\u043d\u044f\u044f \u0433\u0440\u0430\u043d\u0438\u0446\u0430, Mn_res \u2014 \u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u044b\u0439 \u043c\u0430\u0440\u0433\u0430\u043d\u0435\u0446 \u043e\u0442 \u0448\u0438\u0445\u0442\u044b, M_steel \u2014 \u043c\u0430\u0441\u0441\u0430 \u0436\u0438\u0434\u043a\u043e\u0439 \u0441\u0442\u0430\u043b\u0438 (\u043e\u043a\u043e\u043b\u043e 3000 \u043a\u0433), w_FeMn \u2014 \u0434\u043e\u043b\u044f \u043c\u0430\u0440\u0433\u0430\u043d\u0446\u0430 \u0432 \u0424\u041c\u043d78 (0,78), r_Mn \u2014 \u0443\u0441\u0432\u043e\u0435\u043d\u0438\u0435 \u043c\u0430\u0440\u0433\u0430\u043d\u0446\u0430. \u041c\u0430\u0441\u0442\u0435\u0440 \u0443\u0441\u0432\u043e\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442, \u0438 \u0432 \u044d\u0442\u043e\u043c \u0432\u0441\u044f \u0437\u0430\u0434\u0430\u0447\u0430: \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0446\u0435\u043d\u0438\u0442\u044c m_min \u043f\u043e \u0432\u0435\u043b\u0438\u0447\u0438\u043d\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b \u0434\u043e \u0434\u043e\u0431\u0430\u0432\u043a\u0438.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0447\u0438\u0442\u0430\u043b\u0438 \u043f\u0435\u0440\u0432\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e: <a href=\"https:\/\/habr.com\/ru\/articles\/1105616\/#:~:text=%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%B8%D1%82%D0%B5%20%D0%B2%D0%BD%D0%B8%D0%BC%D0%B0%D0%BD%D0%B8%D0%B5%20%D0%BD%D0%B0,%D0%B1%D1%83%D0%B4%D0%B5%D1%82%20%D0%BF%D1%8B%D1%82%D0%B0%D1%82%D1%8C%D1%81%D1%8F%20%D0%BE%D1%86%D0%B5%D0%BD%D0%B8%D1%82%D1%8C.\" rel=\"noopener nofollow\">\u0443\u0441\u0432\u043e\u0435\u043d\u0438\u0435 \u0432 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0435 \u043f\u0430\u0434\u0430\u0435\u0442 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0433\u0440\u0435\u0432\u0435, \u0438\u0437\u0431\u044b\u0442\u043a\u0435 \u043a\u0438\u0441\u043b\u043e\u0440\u043e\u0434\u0430 \u0438 \u043d\u0438\u0437\u043a\u043e\u0439 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u0448\u043b\u0430\u043a\u0430<\/a>. \u041c\u043e\u0434\u0435\u043b\u044c \u044d\u0442\u0438\u0445 \u043f\u0440\u0430\u0432\u0438\u043b \u043d\u0435 \u0432\u0438\u0434\u0438\u0442 \u0438 \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u0445 \u043f\u043e \u0434\u0430\u043d\u043d\u044b\u043c.<\/p>\n<h3>\u0427\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u0438\u0434\u0438\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434\u0435<\/h3>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p>\u041f\u0440\u0438\u0437\u043d\u0430\u043a<\/p>\n<\/th>\n<th>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0434\u043e \u0434\u043e\u0431\u0430\u0432\u043a\u0438<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">scrap_2a_kg, scrap_6a_kg, pig_iron_kg<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0432\u0435\u0441\u0430 \u0437\u0430\u0432\u0430\u043b\u043a\u0438 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b \u0441 \u0432\u0435\u0441\u043e\u0432\u043e\u0439<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">oxygen_m3<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0440\u0430\u0441\u0445\u043e\u0434\u043e\u043c\u0435\u0440 \u043a\u0438\u0441\u043b\u043e\u0440\u043e\u0434\u0430 \u043f\u0438\u0448\u0435\u0442 \u043e\u0431\u044a\u0451\u043c \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0434\u0443\u0432\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">slag_basicity<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u043f\u0443\u0441\u043a\u043e\u043c \u0438\u0437\u043c\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u043f\u043e \u043f\u0440\u043e\u0431\u0435 \u0448\u043b\u0430\u043a\u0430<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">tap_temp_c<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u043e\u0433\u0440\u0443\u0436\u043d\u043e\u0439 \u0442\u0435\u0440\u043c\u043e\u043f\u0430\u0440\u043e\u0439 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043c\u0435\u0440 \u0434\u043e \u0434\u043e\u0431\u0430\u0432\u043a\u0438 \u0444\u0435\u0440\u0440\u043e\u0441\u043f\u043b\u0430\u0432\u043e\u0432 \u0432 \u043a\u043e\u0432\u0448<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">carbon_pct<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u044d\u043a\u0441\u043f\u0440\u0435\u0441\u0441-\u043f\u0440\u043e\u0431\u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0434\u0443\u0432\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0412 \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u0438 \u043d\u0435 \u043f\u043e\u043f\u0430\u043b\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u00ab\u0438\u0437 \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e\u00bb: \u043d\u0438 \u0434\u043e\u0437\u0430 femn78_kg, \u043d\u0438 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 manganese_pct, \u043d\u0438 mn_recovery, \u043d\u0438 \u043b\u0438\u043a\u0432\u0438\u0434\u0443\u0441, \u043d\u0438 \u043f\u0435\u0440\u0435\u0433\u0440\u0435\u0432, \u043d\u0438 gost_pass. \u0415\u0441\u043b\u0438 \u043f\u043e\u0434\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438 mn_recovery, \u043e\u043d\u0430 \u043f\u043e\u043a\u0430\u0436\u0435\u0442 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u0440\u0438\u043a\u0438. \u042d\u0442\u043e \u0441\u0430\u043c\u0430\u044f \u0447\u0430\u0441\u0442\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u0442\u0430\u043a\u0438\u0445 \u0437\u0430\u0434\u0430\u0447\u0430\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432 \u0432 \u043a\u043e\u0434\u0435 \u0437\u0430\u0434\u0430\u043d \u044f\u0432\u043d\u043e.<\/p>\n<h3>\u0420\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/h3>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0431\u044b\u043b\u0430 eval_set \u0434\u043b\u044f \u0440\u0430\u043d\u043d\u0435\u0439 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a. \u0422\u0430\u043a\u0430\u044f \u043e\u0446\u0435\u043d\u043a\u0430 \u0447\u0443\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u043d\u0430: \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u0447\u0438\u0441\u043b\u043e \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u043f\u043e \u0442\u0435\u043c \u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u043c, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u0442\u043e\u043c \u043e\u0446\u0435\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f. \u0422\u0435\u043f\u0435\u0440\u044c \u0442\u0440\u0438 \u0447\u0430\u0441\u0442\u0438:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p>\u0427\u0430\u0441\u0442\u044c<\/p>\n<\/th>\n<th>\n<p>\u041f\u043b\u0430\u0432\u043e\u043a<\/p>\n<\/th>\n<th>\n<p>\u0414\u043b\u044f \u0447\u0435\u0433\u043e<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">train<\/p>\n<\/td>\n<td>\n<p align=\"left\">1280<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">validation<\/p>\n<\/td>\n<td>\n<p align=\"left\">320<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0440\u0430\u043d\u043d\u044f\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u0432\u044b\u0431\u043e\u0440 \u043b\u0443\u0447\u0448\u0435\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">test<\/p>\n<\/td>\n<td>\n<p align=\"left\">400<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u0440\u0438\u043a\u0438, \u043c\u043e\u0434\u0435\u043b\u044c \u0435\u0451 \u043d\u0435 \u0432\u0438\u0434\u0435\u043b\u0430<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h3>\u041a\u043e\u0434 model.py<\/h3>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432 \u0438 \u0444\u043e\u0440\u043c\u0443\u043b\u0430 \u0446\u0435\u043b\u0438. \u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0431\u0435\u0440\u0443\u0442\u0441\u044f \u0438\u0437 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430, \u0447\u0442\u043e\u0431\u044b \u0446\u0435\u043b\u044c \u0441\u0447\u0438\u0442\u0430\u043b\u0430\u0441\u044c \u043f\u043e \u0442\u0435\u043c \u0436\u0435 \u0447\u0438\u0441\u043b\u0430\u043c, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0438\u0441\u044c \u0434\u0430\u043d\u043d\u044b\u0435:<\/p>\n<pre><code class=\"python\">from __future__ import annotationsimport argparseimport jsonfrom pathlib import Pathimport numpy as npimport pandas as pdfrom catboost import CatBoostRegressor, Poolfrom sklearn.metrics import mean_absolute_error, mean_squared_error, r2_scorefrom sklearn.model_selection import train_test_splitfrom .generator import (    FEMN_MN_CONTENT,    GOST_MANGANESE,    LIQUID_STEEL_KG,    RESIDUAL_MN,)FEATURES = [    \"scrap_2a_kg\",    \"scrap_6a_kg\",    \"pig_iron_kg\",    \"oxygen_m3\",    \"slag_basicity\",    \"tap_temp_c\",    \"carbon_pct\",]TARGET = \"femn78_min_kg\"HEADROOM = \"femn78_headroom_kg\"def min_femn_dose(mn_recovery):    \"\"\"FeMn78 dose (kg) that lands manganese on the lower GOST limit.\"\"\"    needed_pct = GOST_MANGANESE[0] - RESIDUAL_MN    return needed_pct \/ 100.0 * LIQUID_STEEL_KG \/ (FEMN_MN_CONTENT * mn_recovery)def add_targets(df: pd.DataFrame) -&gt; pd.DataFrame:    out = df.copy()    out[TARGET] = min_femn_dose(out[\"mn_recovery\"])    out[HEADROOM] = out[\"femn78_kg\"] - out[TARGET]    return out<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper\"><\/span><\/a><\/div><\/pre>\n<p>HEADROOM \u2014 \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u043c\u0435\u0436\u0434\u0443 \u0442\u0435\u043c, \u0447\u0442\u043e \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438, \u0438 \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u043e\u043c. \u041e \u0442\u043e\u043c, \u043a\u0430\u043a \u0435\u0451 \u0447\u0438\u0442\u0430\u0442\u044c, \u2014 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0430.<\/p>\n<p>\u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"python\">def train(    df: pd.DataFrame,    seed: int = 42,    iterations: int = 1000,) -&gt; tuple[CatBoostRegressor, dict]:    data = add_targets(df)    dev, test = train_test_split(data, test_size=0.2, random_state=seed)    train_part, val = train_test_split(dev, test_size=0.2, random_state=seed)    model = CatBoostRegressor(        iterations=iterations,        learning_rate=0.05,        depth=6,        loss_function=\"MAE\",        random_seed=seed,        verbose=0,        allow_writing_files=False,    )    model.fit(        Pool(train_part[FEATURES], train_part[TARGET]),        eval_set=Pool(val[FEATURES], val[TARGET]),        early_stopping_rounds=100,        use_best_model=True,    )    pred = model.predict(test[FEATURES])    mse = mean_squared_error(test[TARGET], pred)    baseline = np.full(len(test), train_part[TARGET].median())    importance = model.get_feature_importance()    metrics = {        \"n_rows\": int(len(data)),        \"n_train\": int(len(train_part)),        \"n_val\": int(len(val)),        \"n_test\": int(len(test)),        \"best_iteration\": int(model.get_best_iteration()),        \"test_mae_kg\": float(mean_absolute_error(test[TARGET], pred)),        \"test_rmse_kg\": float(np.sqrt(mse)),        \"test_r2\": float(r2_score(test[TARGET], pred)),        \"baseline_mae_kg\": float(mean_absolute_error(test[TARGET], baseline)),        \"target_std_kg\": float(data[TARGET].std()),        \"gost_pass_rate\": float(data[\"gost_pass\"].mean()),        \"headroom_true_mean_kg\": float(data[HEADROOM].mean()),        \"headroom_predicted_test_mean_kg\": float((test[\"femn78_kg\"] - pred).mean()),        \"feature_importance\": {            name: float(value) for name, value in zip(FEATURES, importance)        },    }    return model, metrics<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0427\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>loss_function=&#187;MAE&#187; \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0441\u0440\u0435\u0434\u043d\u044e\u044e \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u0443\u044e \u043e\u0448\u0438\u0431\u043a\u0443 \u0432 \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435.<\/p>\n<\/li>\n<li>\n<p>allow_writing_files=False \u043d\u0435 \u0434\u0430\u0451\u0442 CatBoost \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u043f\u0430\u043f\u043a\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 catboost_info.<\/p>\n<\/li>\n<li>\n<p>baseline \u2014 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0434\u0438\u0430\u043d\u0443 \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0439 \u0432\u044b\u0431\u043e\u0440\u043a\u0438. \u0411\u0435\u0437 \u043d\u0435\u0451 \u0446\u0438\u0444\u0440\u0430 MAE \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0447\u0438\u0442: 0,35 \u043a\u0433 \u2014 \u044d\u0442\u043e \u043c\u0430\u043b\u043e \u0438\u043b\u0438 \u043c\u043d\u043e\u0433\u043e? \u041d\u0430\u0434\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0441 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0435\u0439 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043e\u0439.<\/p>\n<\/li>\n<li>\n<p>get_best_iteration() \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0433\u0434\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u0440\u0430\u043d\u043d\u044f\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430. \u0423 \u043c\u0435\u043d\u044f \u043e\u043d\u0430 \u043d\u0430 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 164 \u0438\u0437 1000.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435, \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0435:<\/p>\n<pre><code class=\"python\">def load_model(path: str | Path) -&gt; CatBoostRegressor:    model = CatBoostRegressor()    model.load_model(str(path))    return modeldef predict_min_dose(model: CatBoostRegressor, **features: float) -&gt; float:    row = pd.DataFrame([features], columns=FEATURES)    return float(model.predict(row)[0])def main() -&gt; None:    parser = argparse.ArgumentParser(description=\"Train the minimum FeMn78 dose model.\")    parser.add_argument(\"--data\", type=Path, default=Path(\"data\/eaf_melts_2000.csv\"))    parser.add_argument(\"--model\", type=Path, default=Path(\"models\/fmn78_model.cbm\"))    parser.add_argument(\"--metrics\", type=Path, default=Path(\"models\/metrics.json\"))    parser.add_argument(\"--seed\", type=int, default=42)    args = parser.parse_args()    df = pd.read_csv(args.data)    model, metrics = train(df, seed=args.seed)    args.model.parent.mkdir(parents=True, exist_ok=True)    model.save_model(str(args.model))    args.metrics.write_text(json.dumps(metrics, indent=2, ensure_ascii=False))    print(f\"test MAE:      {metrics['test_mae_kg']:.3f} kg\")    print(f\"test RMSE:     {metrics['test_rmse_kg']:.3f} kg\")    print(f\"test R2:       {metrics['test_r2']:.3f}\")    print(f\"baseline MAE:  {metrics['baseline_mae_kg']:.3f} kg (train median)\")    print(f\"saved model to {args.model}, metrics to {args.metrics}\")if __name__ == \"__main__\":    main()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0440\u043e\u0434\u043d\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 CatBoost (.cbm), \u0430 \u043d\u0435 \u0432 pickle. Pickle \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0444\u0430\u0439\u043b \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b.<\/p>\n<pre><code class=\"bash\">python -m eafsim.model<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<pre><code>test MAE:      0.352 kgtest RMSE:     0.442 kgtest R2:       0.836baseline MAE:  0.873 kg (train median)saved model to models\/fmn78_model.cbm, metrics to models\/metrics.json<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<h3>\u041a\u0430\u043a \u0447\u0438\u0442\u0430\u0442\u044c \u043c\u0435\u0442\u0440\u0438\u043a\u0438<\/h3>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p>\u041c\u0435\u0442\u0440\u0438\u043a\u0430<\/p>\n<\/th>\n<th>\n<p>\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">MAE \u043d\u0430 \u0442\u0435\u0441\u0442\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">0,352 \u043a\u0433<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">MAE \u043f\u0440\u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0438 \u043c\u0435\u0434\u0438\u0430\u043d\u044b \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0439 \u0432\u044b\u0431\u043e\u0440\u043a\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">0,873 \u043a\u0433<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">RMSE \u043d\u0430 \u0442\u0435\u0441\u0442\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">0,442 \u043a\u0433<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">R\u00b2 \u043d\u0430 \u0442\u0435\u0441\u0442\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">0,836<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u0435 \u0446\u0435\u043b\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">1,073 \u043a\u0433<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c \u043e\u0448\u0438\u0431\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u043d\u0430 0,35 \u043a\u0433, \u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u043c\u0435\u0434\u0438\u0430\u043d\u0430 \u2014 \u043d\u0430 0,87 \u043a\u0433, \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0432 2,5 \u0440\u0430\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0435. \u0414\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0448\u0443\u043c\u043e\u043c \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442, \u043d\u043e \u043d\u0430\u0434\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c: \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430, \u0437\u0430\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0432 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0435, \u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u0438\u0434\u0451\u0442 \u043e\u0442 \u0448\u0443\u043c\u0430 furnace_noise, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044e \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c.<\/p>\n<h3>\u0412\u0430\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432<\/h3>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p>\u041f\u0440\u0438\u0437\u043d\u0430\u043a<\/p>\n<\/th>\n<th>\n<p>\u0412\u0430\u0436\u043d\u043e\u0441\u0442\u044c, %<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">slag_basicity<\/p>\n<\/td>\n<td>\n<p align=\"left\">69,7<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">oxygen_m3<\/p>\n<\/td>\n<td>\n<p align=\"left\">10,8<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">pig_iron_kg<\/p>\n<\/td>\n<td>\n<p align=\"left\">6,6<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">tap_temp_c<\/p>\n<\/td>\n<td>\n<p align=\"left\">3,7<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">carbon_pct<\/p>\n<\/td>\n<td>\n<p align=\"left\">3,4<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">scrap_6a_kg<\/p>\n<\/td>\n<td>\n<p align=\"left\">3,0<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">scrap_2a_kg<\/p>\n<\/td>\n<td>\n<p align=\"left\">2,8<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c, \u0438 \u044d\u0442\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430: \u0438\u0437 \u0442\u0440\u0451\u0445 \u0448\u0442\u0440\u0430\u0444\u043e\u0432 \u043d\u0430 \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043e\u0434\u0438\u043d. \u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430 \u0438 \u043a\u0438\u0441\u043b\u043e\u0440\u043e\u0434 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0435 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043e\u043d\u0438 \u043d\u0435\u0432\u0430\u0436\u043d\u044b \u0432 \u043f\u0435\u0447\u0438, \u0430 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0432 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u043b\u0430\u0432\u043a\u0430\u0445 \u043e\u043d\u0438 \u043d\u0435 \u0437\u0430\u0445\u043e\u0434\u044f\u0442 \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u044c, \u0433\u0434\u0435 \u0448\u0442\u0440\u0430\u0444 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u2014 \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 <a href=\"https:\/\/habr.com\/ru\/articles\/1105616\/#:~:text=COLUMNS%3A%20dict%5Bstr,%D0%BE%D0%B4%D0%BD%D0%BE%D0%B2%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%20%D0%B2%20%D0%B4%D0%BE%D0%BF%D1%83%D1%81%D0%BA%D0%B5.%22%2C%0A%20%20%20%20%7D%2C%0A%7D\" rel=\"noopener nofollow\">\u043f\u0440\u043e \u0434\u0430\u043d\u043d\u044b\u0435<\/a>.<\/p>\n<h3>\u0427\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u00ab\u0437\u0430\u043f\u0430\u0441\u00bb \u0432 \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u0445<\/h3>\n<p>\u0412 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0435 \u043c\u0430\u0441\u0442\u0435\u0440 \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 26,9 \u043a\u0433 \u0424\u041c\u043d78, \u0430 \u0440\u0430\u0441\u0447\u0451\u0442\u043d\u044b\u0439 \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0430 17 \u043a\u0433. \u0420\u0430\u0437\u043d\u0438\u0446\u0430 (HEADROOM) \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u0440\u0430\u0432\u043d\u0430 9,84 \u043a\u0433 \u043d\u0430 \u043f\u043b\u0430\u0432\u043a\u0443, \u0430 \u043f\u043e \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430\u043c \u043c\u043e\u0434\u0435\u043b\u0438 \u043d\u0430 \u0442\u0435\u0441\u0442\u0435 \u2014 9,96 \u043a\u0433.<\/p>\n<p>\u042d\u0442\u043e <strong>\u0432\u0435\u0440\u0445\u043d\u044f\u044f \u043e\u0446\u0435\u043d\u043a\u0430!!!<\/strong>, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0433\u043d\u043e\u0437 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438. \u0426\u0435\u043b\u044c \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0440\u043e\u0432\u043d\u043e \u043d\u0438\u0436\u043d\u0435\u0439 \u0433\u0440\u0430\u043d\u0438\u0446\u044b 0,45 %, \u0431\u0435\u0437 \u0437\u0430\u043f\u0430\u0441\u0430 \u043d\u0430\u0434\u0451\u0436\u043d\u043e\u0441\u0442\u0438. \u0412 \u0446\u0435\u0445\u0435 \u0442\u0430\u043a \u0434\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f: \u043b\u044e\u0431\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u043c\u0438\u043d\u0443\u0441 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0431\u0440\u0430\u043a \u043f\u043e \u043c\u0430\u0440\u0433\u0430\u043d\u0446\u0443. \u0420\u0430\u0431\u043e\u0447\u0443\u044e \u0434\u043e\u0437\u0443 \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u043a\u0430\u043a \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0435 \u043f\u043b\u044e\u0441 \u0437\u0430\u043f\u0430\u0441 (\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043e\u043d \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044f \u043f\u043e\u043b\u0437\u0443\u043d\u043a\u043e\u043c), \u0438 \u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430\u043f\u0430\u0441, \u0442\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u044f.<\/p>\n<h3>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 Streamlit<\/h3>\n<p>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043b\u0435\u0436\u0438\u0442 \u0432 app.py \u0440\u044f\u0434\u043e\u043c \u0441 \u043f\u0430\u043a\u0435\u0442\u043e\u043c \u0438 \u0447\u0438\u0442\u0430\u0435\u0442 \u0442\u0440\u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u0430: data\/eaf_melts_2000.csv, models\/fmn78_model.cbm \u0438 models\/metrics.json. \u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043e\u0431\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043b\u0435\u0442\u0443, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e, \u0430 \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0440\u043e\u0432\u043d\u043e \u0442\u0435, \u0447\u0442\u043e \u043d\u0430\u043f\u0435\u0447\u0430\u0442\u0430\u043b \u0441\u043a\u0440\u0438\u043f\u0442 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041d\u0430 \u0447\u0435\u0442\u044b\u0440\u0451\u0445 \u0432\u043a\u043b\u0430\u0434\u043a\u0430\u0445:<\/p>\n<ul>\n<li>\n<p><strong>\u041e\u0431\u0437\u043e\u0440<\/strong> \u2014 \u043c\u0435\u0442\u0440\u0438\u043a\u0438, \u0432\u0430\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432 \u0438 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0437\u0430\u043f\u0430\u0441\u0430;<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u0430\u0442\u0430\u0441\u0435\u0442<\/strong> \u2014 \u0442\u0430\u0431\u043b\u0438\u0446\u0430, \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0438 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u043a\u043e\u043b\u043e\u043d\u043e\u043a;<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u0430\u043b\u044c\u043a\u0443\u043b\u044f\u0442\u043e\u0440<\/strong> \u2014 \u043f\u043e\u043b\u0437\u0443\u043d\u043a\u0438 \u0448\u0438\u0445\u0442\u044b \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043f\u043b\u0430\u0432\u043a\u0438, \u043e\u0442\u0432\u0435\u0442 \u0432 \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u0445;<\/p>\n<\/li>\n<li>\n<p><strong>\u041e \u043f\u0440\u043e\u0435\u043a\u0442\u0435<\/strong> \u2014 \u0447\u0442\u043e \u044d\u0442\u043e \u0438 \u0447\u0435\u043c \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ul>\n<h4>\u0418\u043c\u043f\u043e\u0440\u0442\u044b, \u043f\u0443\u0442\u0438 \u0438 \u0442\u0435\u043a\u0441\u0442\u044b<\/h4>\n<p>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u0432\u0443\u044f\u0437\u044b\u0447\u043d\u043e\u0435 (\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439 \u0438 \u0440\u0443\u0441\u0441\u043a\u0438\u0439). \u0412\u0441\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043b\u0435\u0436\u0430\u0442 \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435 TEXT, \u043a\u043b\u044e\u0447\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0434\u043b\u044f \u043e\u0431\u043e\u0438\u0445 \u044f\u0437\u044b\u043a\u043e\u0432. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u043d\u0435 \u043f\u0440\u0438\u0432\u043e\u0436\u0443: \u043e\u043d \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u043a\u043e\u043b\u043e 180 \u0441\u0442\u0440\u043e\u043a \u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043f\u043e\u0434\u043f\u0438\u0441\u0435\u0439 \u0438 \u043f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u0439. \u0412\u043e\u0442 \u0435\u0433\u043e \u0444\u043e\u0440\u043c\u0430:<\/p>\n<pre><code class=\"python\">import jsonfrom pathlib import Pathimport pandas as pdimport plotly.express as pximport streamlit as stfrom eafsim.generator import CHARGE_KG, COLUMNS, FEMN_RANGE, SCRAP_2A_RANGEfrom eafsim.model import FEATURES, HEADROOM, add_targets, load_model, predict_min_doseROOT = Path(__file__).parentDATA_PATH = ROOT \/ \"data\" \/ \"eaf_melts_2000.csv\"MODEL_PATH = ROOT \/ \"models\" \/ \"fmn78_model.cbm\"METRICS_PATH = ROOT \/ \"models\" \/ \"metrics.json\"st.set_page_config(page_title=\"EAF melt simulator\", page_icon=\"\ud83d\udd25\", layout=\"wide\")TEXT = {    \"en\": {\"title\": \"...\", \"tab_overview\": \"Overview\", \"m_mae\": \"Test MAE, kg\", ...},    \"ru\": {\"title\": \"...\", \"tab_overview\": \"\u041e\u0431\u0437\u043e\u0440\", \"m_mae\": \"MAE \u043d\u0430 \u0442\u0435\u0441\u0442\u0435, \u043a\u0433\", ...},}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u2014 \u0432 app.py \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u041f\u043e\u0434\u043f\u0438\u0441\u0438 \u0441 \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u043e\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, warn_low) \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 {lo:.0f} \u0438 {hi:.0f}: \u0438\u0445 \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 str.format, \u043a\u043e\u0433\u0434\u0430 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0434\u043e\u0437\u0430 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0438\u0436\u0435 \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0430.<\/p>\n<h4>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438 \u043e\u0431\u0449\u0438\u0439 \u043a\u0430\u0440\u043a\u0430\u0441<\/h4>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u0438 \u043c\u043e\u0434\u0435\u043b\u044c \u043a\u044d\u0448\u0438\u0440\u0443\u044e\u0442\u0441\u044f: st.cache_data \u0434\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b, st.cache_resource \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 CatBoost. \u0415\u0441\u043b\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0442\u0440\u0451\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0435\u0442, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0442\u0440\u0435\u0439\u0441\u0431\u0435\u043a\u043e\u043c, \u0430 \u0433\u043e\u0432\u043e\u0440\u0438\u0442, \u0447\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c.<\/p>\n<pre><code class=\"python\">@st.cache_datadef load_data(path: Path) -&gt; pd.DataFrame:    return pd.read_csv(path)@st.cache_resourcedef get_model(path: Path):    return load_model(path)missing = [p.name for p in (DATA_PATH, MODEL_PATH, METRICS_PATH) if not p.exists()]if missing:    st.error(        f\"Missing files: {', '.join(missing)}. Run \"        \"`python -m eafsim.generator` and `python -m eafsim.model` first.\"    )    st.stop()lang_label = st.radio(\"Language \/ \u042f\u0437\u044b\u043a\", [\"English\", \"\u0420\u0443\u0441\u0441\u043a\u0438\u0439\"], horizontal=True)t = TEXT[\"en\" if lang_label == \"English\" else \"ru\"]lang = \"en\" if lang_label == \"English\" else \"ru\"df = load_data(DATA_PATH)model = get_model(MODEL_PATH)metrics = json.loads(METRICS_PATH.read_text())enriched = add_targets(df)st.title(t[\"title\"])st.markdown(t[\"subtitle\"])tab_overview, tab_dataset, tab_calc, tab_about = st.tabs(    [t[\"tab_overview\"], t[\"tab_dataset\"], t[\"tab_calc\"], t[\"tab_about\"]])<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<h4>\u0412\u043a\u043b\u0430\u0434\u043a\u0430 \u00ab\u041e\u0431\u0437\u043e\u0440\u00bb<\/h4>\n<p>\u041f\u044f\u0442\u044c \u043c\u0435\u0442\u0440\u0438\u043a \u0441\u0432\u0435\u0440\u0445\u0443, \u043f\u043e\u0434 \u043d\u0438\u043c\u0438 \u0432\u0430\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432 \u0438 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0437\u0430\u043f\u0430\u0441\u0430. \u041c\u0435\u0442\u0440\u0438\u043a\u0438 \u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0438\u0437 metrics.json, \u0430 \u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f: \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0440\u043e\u0432\u043d\u043e \u0442\u0435 \u0447\u0438\u0441\u043b\u0430, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u0441\u043a\u0440\u0438\u043f\u0442.<\/p>\n<pre><code class=\"python\">with tab_overview:    c1, c2, c3, c4, c5 = st.columns(5)    c1.metric(t[\"m_heats\"], f\"{metrics['n_rows']:,}\".replace(\",\", \" \"))    c2.metric(t[\"m_pass\"], f\"{metrics['gost_pass_rate']:.1%}\")    c3.metric(t[\"m_mae\"], f\"{metrics['test_mae_kg']:.3f}\", help=t[\"m_mae_help\"])    c4.metric(t[\"m_baseline\"], f\"{metrics['baseline_mae_kg']:.3f}\", help=t[\"m_baseline_help\"])    c5.metric(t[\"m_headroom\"], f\"{metrics['headroom_true_mean_kg']:.2f}\", help=t[\"m_headroom_help\"])    left, right = st.columns(2)    with left:        st.subheader(t[\"importance\"])        imp = pd.DataFrame(            {                \"feature\": list(metrics[\"feature_importance\"]),                \"importance\": list(metrics[\"feature_importance\"].values()),            }        )        fig = px.bar(imp, x=\"importance\", y=\"feature\", orientation=\"h\", labels={\"importance\": t[\"importance_x\"], \"feature\": \"\"})        fig.update_layout(yaxis={\"categoryorder\": \"total ascending\"}, height=340, margin={\"l\": 0, \"r\": 0, \"t\": 10, \"b\": 0})        st.plotly_chart(fig, width=\"stretch\")    with right:        st.subheader(t[\"headroom_hist\"])        fig = px.histogram(enriched, x=HEADROOM, nbins=40, labels={HEADROOM: t[\"headroom_x\"]})        fig.update_layout(height=340, margin={\"l\": 0, \"r\": 0, \"t\": 10, \"b\": 0}, yaxis_title=\"\")        st.plotly_chart(fig, width=\"stretch\")    st.caption(t[\"overview_note\"])<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<h4>\u0412\u043a\u043b\u0430\u0434\u043a\u0430 \u00ab\u0414\u0430\u0442\u0430\u0441\u0435\u0442\u00bb<\/h4>\n<p>\u041f\u0435\u0440\u0432\u044b\u0435 200 \u0441\u0442\u0440\u043e\u043a, \u043a\u043d\u043e\u043f\u043a\u0430 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430-\u0441\u043b\u043e\u0432\u0430\u0440\u044c \u043a\u043e\u043b\u043e\u043d\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043f\u0440\u044f\u043c\u043e \u0438\u0437 COLUMNS \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430. \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043d\u0435 \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u044e\u0442\u0441\u044f: \u043f\u043e\u043c\u0435\u043d\u044f\u043b \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u043e\u0431\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u0438 README, \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<pre><code class=\"python\">with tab_dataset:    st.subheader(t[\"dataset_header\"])    st.dataframe(df.head(200), width=\"stretch\")    st.download_button(t[\"download\"], df.to_csv(index=False).encode(\"utf-8\"), \"eaf_melts_2000.csv\", \"text\/csv\")    st.subheader(t[\"columns_header\"])    schema = pd.DataFrame(        [            {t[\"col_name\"]: name, t[\"col_unit\"]: spec[\"unit\"], t[\"col_desc\"]: spec[lang]}            for name, spec in COLUMNS.items()        ]    )    st.dataframe(schema, width=\"stretch\", hide_index=True)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<h4>\u041a\u0430\u043b\u044c\u043a\u0443\u043b\u044f\u0442\u043e\u0440<\/h4>\n<p>\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0434\u0430\u0451\u0442 \u0448\u0438\u0445\u0442\u0443 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u043b\u0430\u0432\u043a\u0438, \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u0437\u043e\u0439 \u0424\u041c\u043d78. \u041b\u043e\u043c 2\u0410 \u043d\u0435 \u0432\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0430 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043e\u0441\u0442\u0430\u0442\u043e\u043a \u043e\u0442 3300 \u043a\u0433: \u0442\u0430\u043a \u0441\u0443\u043c\u043c\u0430 \u0448\u0438\u0445\u0442\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0445\u043e\u0434\u0438\u0442\u0441\u044f, \u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043f\u043b\u0430\u0432\u043a\u0443, \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0443\u044e \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0438\u0439\u0441\u044f 2\u0410 \u0432\u043d\u0435 \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0433\u043e \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0430, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0435: \u043c\u043e\u0434\u0435\u043b\u044c \u0432 \u044d\u0442\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u044d\u043a\u0441\u0442\u0440\u0430\u043f\u043e\u043b\u0438\u0440\u0443\u0435\u0442.<\/p>\n<pre><code class=\"python\">with tab_calc:    st.subheader(t[\"calc_header\"])    st.caption(t[\"calc_hint\"])    col_a, col_b = st.columns(2)    with col_a:        scrap_6a = st.slider(t[\"s_6a\"], 400, 1300, 900, 10)        pig_iron = st.slider(t[\"s_pig\"], 200, 400, 250, 5)        scrap_2a = CHARGE_KG - scrap_6a - pig_iron        st.metric(t[\"derived_2a\"], f\"{scrap_2a:.0f}\")        if not SCRAP_2A_RANGE[0] &lt;= scrap_2a &lt;= SCRAP_2A_RANGE[1]:            st.warning(t[\"warn_2a\"])        carbon = st.slider(t[\"s_carbon\"], 0.30, 0.42, 0.36, 0.005)    with col_b:        oxygen = st.slider(t[\"s_o2\"], 35.0, 75.0, 42.0, 0.5)        basicity = st.slider(t[\"s_basicity\"], 1.8, 2.9, 2.4, 0.05)        tap_temp = st.slider(t[\"s_temp\"], 1530, 1660, 1558, 1)        reference = st.number_input(t[\"ref_dose\"], value=27.0, step=0.5)        margin = st.slider(t[\"margin\"], 0.0, 3.0, 0.5, 0.1)    recommended = predict_min_dose(        model,        scrap_2a_kg=scrap_2a,        scrap_6a_kg=scrap_6a,        pig_iron_kg=pig_iron,        oxygen_m3=oxygen,        slag_basicity=basicity,        tap_temp_c=tap_temp,        carbon_pct=carbon,    )    with_margin = recommended + margin    r1, r2, r3 = st.columns(3)    r1.metric(t[\"r_min\"], f\"{recommended:.2f} kg\")    r2.metric(t[\"r_margin\"], f\"{with_margin:.2f} kg\")    r3.metric(t[\"r_delta\"], f\"{reference - with_margin:.2f} kg\")    if recommended &lt; FEMN_RANGE[0]:        st.info(t[\"warn_low\"].format(lo=FEMN_RANGE[0], hi=FEMN_RANGE[1]))with tab_about:    st.markdown(t[\"about\"])<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"bash\">streamlit run app.py<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<h3>\u0422\u0435\u0441\u0442\u044b<\/h3>\n<p>\u0412\u043e\u0441\u0435\u043c\u044c \u0442\u0435\u0441\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u043d\u0435 \u00ab\u043a\u043e\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f\u00bb, \u0430 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0447\u0435\u0441\u0442\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430: \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c, \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 (\u0440\u043e\u0432\u043d\u043e \u0442\u043e\u0442 <a href=\"https:\/\/habr.com\/ru\/articles\/1105616\/#:~:text=%D0%93%D1%80%D0%B0%D0%B1%D0%BB%D0%B8%3A%20%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C%20%D1%81%C2%A0%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%BE%D0%B9%200%2C02%C2%A0%D0%BA%D0%B3%2C%20%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D0%B0%D1%8F%20%D0%BD%D0%B8%D1%87%D0%B5%D0%BC%D1%83%20%D0%BD%D0%B5%C2%A0%D0%BD%D0%B0%D1%83%D1%87%D0%B8%D0%BB%D0%B0%D1%81%D1%8C\" rel=\"noopener nofollow\">\u0434\u0435\u0444\u0435\u043a\u0442 \u0441\u043e \u0441\u0442\u0443\u043f\u0435\u043d\u0447\u0430\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439<\/a>), \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0441\u043e \u0441\u043b\u043e\u0432\u0430\u0440\u0451\u043c, \u0438 \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u0441\u043b\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u0451\u0442 \u0442\u0435 \u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f.<\/p>\n<pre><code class=\"python\">import numpy as npimport pandas as pdimport pytestfrom eafsim.generator import (    COLUMNS,    PIG_IRON_RANGE,    SCRAP_2A_RANGE,    SCRAP_6A_RANGE,    simulate,)from eafsim.model import FEATURES, TARGET, add_targets, load_model, predict_min_dose, train@pytest.fixture(scope=\"module\")def heats() -&gt; pd.DataFrame:    return simulate(n=600, seed=7)def test_simulation_is_reproducible():    pd.testing.assert_frame_equal(simulate(n=200, seed=1), simulate(n=200, seed=1))def test_different_seeds_differ():    assert not simulate(n=200, seed=1).equals(simulate(n=200, seed=2))def test_columns_are_documented(heats):    assert list(heats.columns) == list(COLUMNS)def test_charge_is_fixed_and_within_ranges(heats):    total = heats[\"scrap_2a_kg\"] + heats[\"scrap_6a_kg\"] + heats[\"pig_iron_kg\"]    assert total.between(3300 - 2, 3300 + 2).all()    assert heats[\"scrap_2a_kg\"].between(*SCRAP_2A_RANGE).all()    assert heats[\"scrap_6a_kg\"].between(*SCRAP_6A_RANGE).all()    assert heats[\"pig_iron_kg\"].between(*PIG_IRON_RANGE).all()def test_both_outcomes_present(heats):    rate = heats[\"gost_pass\"].mean()    assert 0.5 &lt; rate &lt; 1.0def test_recovery_has_many_distinct_values(heats):    assert heats[\"mn_recovery\"].nunique() &gt; 50def test_min_dose_is_below_actual_dose_on_average(heats):    enriched = add_targets(heats)    assert (enriched[\"femn78_kg\"] - enriched[TARGET]).mean() &gt; 0def test_train_save_load_predict(tmp_path, heats):    model, metrics = train(heats, seed=0, iterations=150)    assert np.isfinite(metrics[\"test_mae_kg\"])    assert metrics[\"test_mae_kg\"] &lt; metrics[\"baseline_mae_kg\"]    path = tmp_path \/ \"model.cbm\"    model.save_model(str(path))    restored = load_model(path)    row = heats.iloc[0][FEATURES].to_dict()    assert predict_min_dose(restored, **row) == pytest.approx(predict_min_dose(model, **row))<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0421\u0430\u043c\u044b\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u2014 test_recovery_has_many_distinct_values: \u043e\u043d \u043b\u043e\u0432\u0438\u0442 \u0432\u044b\u0440\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0446\u0435\u043b\u0438 \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0438\u0437-\u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0443 \u043c\u0435\u043d\u044f \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043b\u043e\u0436\u043d\u044b\u0439 MAE.<\/p>\n<h3>\u0418\u0442\u043e\u0433\u0438<\/h3>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0434\u043e\u0437\u0443 \u0424\u041c\u043d78 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 0,35 \u043a\u0433 \u043f\u0440\u043e\u0442\u0438\u0432 0,87 \u043a\u0433 \u0443 \u043c\u0435\u0434\u0438\u0430\u043d\u044b. \u0425\u043e\u0440\u043e\u0448\u0430\u044f \u043c\u0435\u0442\u0440\u0438\u043a\u0430 \u043d\u0430 \u0441\u0438\u043d\u0442\u0435\u0442\u0438\u043a\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0447\u0438: \u043c\u043e\u0434\u0435\u043b\u044c \u0443\u0447\u0438\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430. \u0426\u0435\u043d\u043d\u043e \u0442\u043e, \u0447\u0442\u043e \u0442\u0435\u0445\u043d\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442: \u0447\u0435\u0441\u0442\u043d\u044b\u0439 \u0441\u043f\u043b\u0438\u0442 \u043d\u0430 \u0442\u0440\u0438 \u0447\u0430\u0441\u0442\u0438, \u0431\u0435\u0439\u0437\u043b\u0430\u0439\u043d, \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u00ab\u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e\u00bb.<\/p>\n<p>\u041a\u0443\u0434\u0430 \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u044b \u0438 \u043f\u043e\u0440\u043e\u0433\u0438 \u0441 \u043f\u0435\u0447\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c\u044b, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0448\u0442\u0440\u0430\u0444\u044b \u0437\u0430 \u043f\u0435\u0440\u0435\u0433\u0440\u0435\u0432 \u0438 \u043a\u0438\u0441\u043b\u043e\u0440\u043e\u0434 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 \u043a\u0432\u0430\u043d\u0442\u0438\u043b\u044c\u043d\u0443\u044e \u0440\u0435\u0433\u0440\u0435\u0441\u0441\u0438\u044e (\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e).<\/p>\n<\/li>\n<li>\n<p>\u0421\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0441 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043b\u0430\u0432\u043a\u0430\u043c\u0438, \u0435\u0441\u043b\u0438 \u043a\u0442\u043e-\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0438\u0445 \u0434\u0430\u0442\u044c.<\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u0438 \u043a\u043e\u0434: <a href=\"https:\/\/github.com\/RomulusBadass\/eaf-melt-sim\" rel=\"noopener nofollow\">GitHub<\/a>, <a href=\"https:\/\/www.kaggle.com\/datasets\/romulusbadass\/synthetic-eaf-steel-melts-35l-gost-977-88\" rel=\"noopener nofollow\">Kaggle<\/a>. <\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1106372\/\">https:\/\/habr.com\/ru\/articles\/1106372\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u044d\u0442\u043e \u0420\u0430\u043c\u0438\u043b\u044c \u041c\u0430\u043a\u0441\u044e\u0442\u043e\u0432 \u0441\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u0446\u0438\u043a\u043b\u0430 \u043f\u0440\u043e \u043f\u043b\u0430\u0432\u043a\u0438 \u0432 \u0414\u0421\u041f-3. \u041f\u0435\u0440\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0442\u0443\u0442: https:\/\/habr.com\/ru\/articles\/1105616\/\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0443\u0447\u0438\u043c CatBoost \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0434\u043e\u0437\u0443 \u0444\u0435\u0440\u0440\u043e\u043c\u0430\u0440\u0433\u0430\u043d\u0446\u0430 \u0434\u043b\u044f \u0432\u044b\u043f\u043b\u0430\u0432\u043a\u0438 \u043e\u0442\u043b\u0438\u0432\u043a\u0438 \u0438\u0437 \u0441\u0442\u0430\u043b\u0438 35\u041b \u0432 \u0434\u0443\u0433\u043e\u0432\u043e\u0439 \u0441\u0442\u0430\u043b\u0435\u043f\u043b\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0447\u0438 \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u0442\u0435\u0440\u043e\u0432\u043a\u043e\u0439.\u0427\u0442\u043e \u043c\u044b \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u0426\u0435\u043b\u044c \u2014 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u0437\u0430 \u0424\u041c\u043d78, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u0432\u043e\u0434\u0438\u0442 \u043c\u0430\u0440\u0433\u0430\u043d\u0435\u0446 \u0440\u043e\u0432\u043d\u043e \u0434\u043e \u043d\u0438\u0436\u043d\u0435\u0439 \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u0413\u041e\u0421\u0422 977-88 (0,45 %) \u043f\u0440\u0438 \u0442\u043e\u043c \u0443\u0441\u0432\u043e\u0435\u043d\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043b\u0430\u0432\u043a\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0438\u043c\u0435\u043b\u0430:\u0417\u0434\u0435\u0441\u044c Mn_low = 0,45 % \u2014 \u043d\u0438\u0436\u043d\u044f\u044f \u0433\u0440\u0430\u043d\u0438\u0446\u0430, Mn_res \u2014 \u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u044b\u0439 \u043c\u0430\u0440\u0433\u0430\u043d\u0435\u0446 \u043e\u0442 \u0448\u0438\u0445\u0442\u044b, M_steel \u2014 \u043c\u0430\u0441\u0441\u0430 \u0436\u0438\u0434\u043a\u043e\u0439 \u0441\u0442\u0430\u043b\u0438 (\u043e\u043a\u043e\u043b\u043e 3000 \u043a\u0433), w_FeMn \u2014 \u0434\u043e\u043b\u044f \u043c\u0430\u0440\u0433\u0430\u043d\u0446\u0430 \u0432 \u0424\u041c\u043d78 (0,78), r_Mn \u2014 \u0443\u0441\u0432\u043e\u0435\u043d\u0438\u0435 \u043c\u0430\u0440\u0433\u0430\u043d\u0446\u0430. \u041c\u0430\u0441\u0442\u0435\u0440 \u0443\u0441\u0432\u043e\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442, \u0438 \u0432 \u044d\u0442\u043e\u043c \u0432\u0441\u044f \u0437\u0430\u0434\u0430\u0447\u0430: \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0446\u0435\u043d\u0438\u0442\u044c m_min \u043f\u043e \u0432\u0435\u043b\u0438\u0447\u0438\u043d\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b \u0434\u043e \u0434\u043e\u0431\u0430\u0432\u043a\u0438.\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0447\u0438\u0442\u0430\u043b\u0438 \u043f\u0435\u0440\u0432\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e: \u0443\u0441\u0432\u043e\u0435\u043d\u0438\u0435 \u0432 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0435 \u043f\u0430\u0434\u0430\u0435\u0442 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0433\u0440\u0435\u0432\u0435, \u0438\u0437\u0431\u044b\u0442\u043a\u0435 \u043a\u0438\u0441\u043b\u043e\u0440\u043e\u0434\u0430 \u0438 \u043d\u0438\u0437\u043a\u043e\u0439 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u0448\u043b\u0430\u043a\u0430. \u041c\u043e\u0434\u0435\u043b\u044c \u044d\u0442\u0438\u0445 \u043f\u0440\u0430\u0432\u0438\u043b \u043d\u0435 \u0432\u0438\u0434\u0438\u0442 \u0438 \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u0445 \u043f\u043e \u0434\u0430\u043d\u043d\u044b\u043c.\u0427\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u0438\u0434\u0438\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434\u0435\u041f\u0440\u0438\u0437\u043d\u0430\u043a\u041f\u043e\u0447\u0435\u043c\u0443 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0434\u043e \u0434\u043e\u0431\u0430\u0432\u043a\u0438scrap_2a_kg, scrap_6a_kg, pig_iron_kg\u0432\u0435\u0441\u0430 \u0437\u0430\u0432\u0430\u043b\u043a\u0438 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b \u0441 \u0432\u0435\u0441\u043e\u0432\u043e\u0439oxygen_m3\u0440\u0430\u0441\u0445\u043e\u0434\u043e\u043c\u0435\u0440 \u043a\u0438\u0441\u043b\u043e\u0440\u043e\u0434\u0430 \u043f\u0438\u0448\u0435\u0442 \u043e\u0431\u044a\u0451\u043c \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0434\u0443\u0432\u043a\u0438slag_basicity\u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u043f\u0443\u0441\u043a\u043e\u043c \u0438\u0437\u043c\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u043f\u043e \u043f\u0440\u043e\u0431\u0435 \u0448\u043b\u0430\u043a\u0430tap_temp_c\u043f\u043e\u0433\u0440\u0443\u0436\u043d\u043e\u0439 \u0442\u0435\u0440\u043c\u043e\u043f\u0430\u0440\u043e\u0439 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043c\u0435\u0440 \u0434\u043e \u0434\u043e\u0431\u0430\u0432\u043a\u0438 \u0444\u0435\u0440\u0440\u043e\u0441\u043f\u043b\u0430\u0432\u043e\u0432 \u0432 \u043a\u043e\u0432\u0448carbon_pct\u044d\u043a\u0441\u043f\u0440\u0435\u0441\u0441-\u043f\u0440\u043e\u0431\u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0434\u0443\u0432\u043a\u0438\u0412 \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u0438 \u043d\u0435 \u043f\u043e\u043f\u0430\u043b\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u00ab\u0438\u0437 \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e\u00bb: \u043d\u0438 \u0434\u043e\u0437\u0430 femn78_kg, \u043d\u0438 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 manganese_pct, \u043d\u0438 mn_recovery, \u043d\u0438 \u043b\u0438\u043a\u0432\u0438\u0434\u0443\u0441, \u043d\u0438 \u043f\u0435\u0440\u0435\u0433\u0440\u0435\u0432, \u043d\u0438 gost_pass. \u0415\u0441\u043b\u0438 \u043f\u043e\u0434\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438 mn_recovery, \u043e\u043d\u0430 \u043f\u043e\u043a\u0430\u0436\u0435\u0442 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u0440\u0438\u043a\u0438. \u042d\u0442\u043e \u0441\u0430\u043c\u0430\u044f \u0447\u0430\u0441\u0442\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u0442\u0430\u043a\u0438\u0445 \u0437\u0430\u0434\u0430\u0447\u0430\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432 \u0432 \u043a\u043e\u0434\u0435 \u0437\u0430\u0434\u0430\u043d \u044f\u0432\u043d\u043e.\u0420\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445\u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0431\u044b\u043b\u0430 eval_set \u0434\u043b\u044f \u0440\u0430\u043d\u043d\u0435\u0439 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a. \u0422\u0430\u043a\u0430\u044f \u043e\u0446\u0435\u043d\u043a\u0430 \u0447\u0443\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0441\u0442\u0438\u0447\u043d\u0430: \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u0447\u0438\u0441\u043b\u043e \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u043f\u043e \u0442\u0435\u043c \u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u043c, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u0442\u043e\u043c \u043e\u0446\u0435\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f. \u0422\u0435\u043f\u0435\u0440\u044c \u0442\u0440\u0438 \u0447\u0430\u0441\u0442\u0438:\u0427\u0430\u0441\u0442\u044c\u041f\u043b\u0430\u0432\u043e\u043a\u0414\u043b\u044f \u0447\u0435\u0433\u043etrain1280\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432validation320\u0440\u0430\u043d\u043d\u044f\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u0432\u044b\u0431\u043e\u0440 \u043b\u0443\u0447\u0448\u0435\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438test400\u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u0440\u0438\u043a\u0438, \u043c\u043e\u0434\u0435\u043b\u044c \u0435\u0451 \u043d\u0435 \u0432\u0438\u0434\u0435\u043b\u0430\u041a\u043e\u0434 model.py\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u044b, \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432 \u0438 \u0444\u043e\u0440\u043c\u0443\u043b\u0430 \u0446\u0435\u043b\u0438. \u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0431\u0435\u0440\u0443\u0442\u0441\u044f \u0438\u0437 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430, \u0447\u0442\u043e\u0431\u044b \u0446\u0435\u043b\u044c \u0441\u0447\u0438\u0442\u0430\u043b\u0430\u0441\u044c \u043f\u043e \u0442\u0435\u043c \u0436\u0435 \u0447\u0438\u0441\u043b\u0430\u043c, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0438\u0441\u044c \u0434\u0430\u043d\u043d\u044b\u0435:from __future__ import annotationsimport argparseimport jsonfrom pathlib import Pathimport numpy as npimport pandas as pdfrom catboost import CatBoostRegressor, Poolfrom sklearn.metrics import mean_absolute_error, mean_squared_error, r2_scorefrom sklearn.model_selection import train_test_splitfrom .generator import (    FEMN_MN_CONTENT,    GOST_MANGANESE,    LIQUID_STEEL_KG,    RESIDUAL_MN,)FEATURES = [    &#171;scrap_2a_kg&#187;,    &#171;scrap_6a_kg&#187;,    &#171;pig_iron_kg&#187;,    &#171;oxygen_m3&#187;,    &#171;slag_basicity&#187;,    &#171;tap_temp_c&#187;,    &#171;carbon_pct&#187;,]TARGET = &#171;femn78_min_kg&#187;HEADROOM = &#171;femn78_headroom_kg&#187;def min_femn_dose(mn_recovery):    &#171;&#187;&#187;FeMn78 dose (kg) that lands manganese on the lower GOST limit.&#187;&#187;&#187;    needed_pct = GOST_MANGANESE[0] &#8212; RESIDUAL_MN    return needed_pct \/ 100.0 * LIQUID_STEEL_KG \/ (FEMN_MN_CONTENT * mn_recovery)def add_targets(df: pd.DataFrame) -&gt; pd.DataFrame:    out = df.copy()    out[TARGET] = min_femn_dose(out[&#171;mn_recovery&#187;])    out[HEADROOM] = out[&#171;femn78_kg&#187;] &#8212; out[TARGET]    return outHEADROOM \u2014 \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u043c\u0435\u0436\u0434\u0443 \u0442\u0435\u043c, \u0447\u0442\u043e \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438, \u0438 \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u043e\u043c. \u041e \u0442\u043e\u043c, \u043a\u0430\u043a \u0435\u0451 \u0447\u0438\u0442\u0430\u0442\u044c, \u2014 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0430.\u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435:def train(    df: pd.DataFrame,    seed: int = 42,    iterations: int = 1000,) -&gt; tuple[CatBoostRegressor, dict]:    data = add_targets(df)    dev, test = train_test_split(data, test_size=0.2, random_state=seed)    train_part, val = train_test_split(dev, test_size=0.2, random_state=seed)    model = CatBoostRegressor(        iterations=iterations,        learning_rate=0.05,        depth=6,        loss_function=&#187;MAE&#187;,        random_seed=seed,        verbose=0,        allow_writing_files=False,    )    model.fit(        Pool(train_part[FEATURES], train_part[TARGET]),        eval_set=Pool(val[FEATURES], val[TARGET]),        early_stopping_rounds=100,        use_best_model=True,    )    pred = model.predict(test[FEATURES])    mse = mean_squared_error(test[TARGET], pred)    baseline = np.full(len(test), train_part[TARGET].median())    importance = model.get_feature_importance()    metrics = {        &#171;n_rows&#187;: int(len(data)),        &#171;n_train&#187;: int(len(train_part)),        &#171;n_val&#187;: int(len(val)),        &#171;n_test&#187;: int(len(test)),        &#171;best_iteration&#187;: int(model.get_best_iteration()),        &#171;test_mae_kg&#187;: float(mean_absolute_error(test[TARGET], pred)),        &#171;test_rmse_kg&#187;: float(np.sqrt(mse)),        &#171;test_r2&#187;: float(r2_score(test[TARGET], pred)),        &#171;baseline_mae_kg&#187;: float(mean_absolute_error(test[TARGET], baseline)),        &#171;target_std_kg&#187;: float(data[TARGET].std()),        &#171;gost_pass_rate&#187;: float(data[&#171;gost_pass&#187;].mean()),        &#171;headroom_true_mean_kg&#187;: float(data[HEADROOM].mean()),        &#171;headroom_predicted_test_mean_kg&#187;: float((test[&#171;femn78_kg&#187;] &#8212; pred).mean()),        &#171;feature_importance&#187;: {            name: float(value) for name, value in zip(FEATURES, importance)        },    }    return model, metrics\u0427\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c:loss_function=&#187;MAE&#187; \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0441\u0440\u0435\u0434\u043d\u044e\u044e \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u0443\u044e \u043e\u0448\u0438\u0431\u043a\u0443 \u0432 \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435.allow_writing_files=False \u043d\u0435 \u0434\u0430\u0451\u0442 CatBoost \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u043f\u0430\u043f\u043a\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 catboost_info.baseline \u2014 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0434\u0438\u0430\u043d\u0443 \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0439 \u0432\u044b\u0431\u043e\u0440\u043a\u0438. \u0411\u0435\u0437 \u043d\u0435\u0451 \u0446\u0438\u0444\u0440\u0430 MAE \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0447\u0438\u0442: 0,35 \u043a\u0433 \u2014 \u044d\u0442\u043e \u043c\u0430\u043b\u043e \u0438\u043b\u0438 \u043c\u043d\u043e\u0433\u043e? \u041d\u0430\u0434\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0441 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0435\u0439 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043e\u0439.get_best_iteration() \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0433\u0434\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u0440\u0430\u043d\u043d\u044f\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430. \u0423 \u043c\u0435\u043d\u044f \u043e\u043d\u0430 \u043d\u0430 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 164 \u0438\u0437 1000.\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435, \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0435:def load_model(path: str | Path) -&gt; CatBoostRegressor:    model = CatBoostRegressor()    model.load_model(str(path))    return modeldef predict_min_dose(model: CatBoostRegressor, **features: float) -&gt; float:    row = pd.DataFrame([features], columns=FEATURES)    return float(model.predict(row)[0])def main() -&gt; None:    parser = argparse.ArgumentParser(description=&#187;Train the minimum FeMn78 dose model.&#187;)    parser.add_argument(&#171;&#8212;data&#187;, type=Path, default=Path(&#171;data\/eaf_melts_2000.csv&#187;))    parser.add_argument(&#171;&#8212;model&#187;, type=Path, default=Path(&#171;models\/fmn78_model.cbm&#187;))    parser.add_argument(&#171;&#8212;metrics&#187;, type=Path, default=Path(&#171;models\/metrics.json&#187;))    parser.add_argument(&#171;&#8212;seed&#187;, type=int, default=42)    args = parser.parse_args()    df = pd.read_csv(args.data)    model, metrics = train(df, seed=args.seed)    args.model.parent.mkdir(parents=True, exist_ok=True)    model.save_model(str(args.model))    args.metrics.write_text(json.dumps(metrics, indent=2, ensure_ascii=False))    print(f&#187;test MAE:      {metrics[&#8216;test_mae_kg&#8217;]:.3f} kg&#187;)    print(f&#187;test RMSE:     {metrics[&#8216;test_rmse_kg&#8217;]:.3f} kg&#187;)    print(f&#187;test R2:       {metrics[&#8216;test_r2&#8217;]:.3f}&#187;)    print(f&#187;baseline MAE:  {metrics[&#8216;baseline_mae_kg&#8217;]:.3f} kg (train median)&#187;)    print(f&#187;saved model to {args.model}, metrics to {args.metrics}&#187;)if __name__ == &#171;__main__&#187;:    main()\u041c\u043e\u0434\u0435\u043b\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0440\u043e\u0434\u043d\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 CatBoost (.cbm), \u0430 \u043d\u0435 \u0432 pickle. Pickle \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0444\u0430\u0439\u043b \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b.python -m eafsim.modeltest MAE:      0.352 kgtest RMSE:     0.442 kgtest R2:       0.836baseline MAE:  0.873 kg (train median)saved model to models\/fmn78_model.cbm, metrics to models\/metrics.json\u041a\u0430\u043a \u0447\u0438\u0442\u0430\u0442\u044c \u043c\u0435\u0442\u0440\u0438\u043a\u0438\u041c\u0435\u0442\u0440\u0438\u043a\u0430\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435MAE \u043d\u0430 \u0442\u0435\u0441\u0442\u04350,352 \u043a\u0433MAE \u043f\u0440\u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0438 \u043c\u0435\u0434\u0438\u0430\u043d\u044b \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0439 \u0432\u044b\u0431\u043e\u0440\u043a\u04380,873 \u043a\u0433RMSE \u043d\u0430 \u0442\u0435\u0441\u0442\u04350,442 \u043a\u0433R\u00b2 \u043d\u0430 \u0442\u0435\u0441\u0442\u04350,836\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u0435 \u0446\u0435\u043b\u04381,073 \u043a\u0433\u041c\u043e\u0434\u0435\u043b\u044c \u043e\u0448\u0438\u0431\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u043d\u0430 0,35 \u043a\u0433, \u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u043c\u0435\u0434\u0438\u0430\u043d\u0430 \u2014 \u043d\u0430 0,87 \u043a\u0433, \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0432 2,5 \u0440\u0430\u0437\u0430 \u0431\u043e\u043b\u044c\u0448\u0435. \u0414\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0448\u0443\u043c\u043e\u043c \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442, \u043d\u043e \u043d\u0430\u0434\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c: \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430, \u0437\u0430\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0432 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0435, \u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u0438\u0434\u0451\u0442 \u043e\u0442 \u0448\u0443\u043c\u0430 furnace_noise, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044e \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c.\u0412\u0430\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432\u041f\u0440\u0438\u0437\u043d\u0430\u043a\u0412\u0430\u0436\u043d\u043e\u0441\u0442\u044c, %slag_basicity69,7oxygen_m310,8pig_iron_kg6,6tap_temp_c3,7carbon_pct3,4scrap_6a_kg3,0scrap_2a_kg2,8\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c, \u0438 \u044d\u0442\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430: \u0438\u0437 \u0442\u0440\u0451\u0445 \u0448\u0442\u0440\u0430\u0444\u043e\u0432 \u043d\u0430 \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043e\u0434\u0438\u043d. \u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430 \u0438 \u043a\u0438\u0441\u043b\u043e\u0440\u043e\u0434 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0435 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043e\u043d\u0438 \u043d\u0435\u0432\u0430\u0436\u043d\u044b \u0432 \u043f\u0435\u0447\u0438, \u0430 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0432 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u043b\u0430\u0432\u043a\u0430\u0445 \u043e\u043d\u0438 \u043d\u0435 \u0437\u0430\u0445\u043e\u0434\u044f\u0442 \u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u044c, \u0433\u0434\u0435 \u0448\u0442\u0440\u0430\u0444 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u2014 \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043f\u0440\u043e \u0434\u0430\u043d\u043d\u044b\u0435.\u0427\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u00ab\u0437\u0430\u043f\u0430\u0441\u00bb \u0432 \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u0445\u0412 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0435 \u043c\u0430\u0441\u0442\u0435\u0440 \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 26,9 \u043a\u0433 \u0424\u041c\u043d78, \u0430 \u0440\u0430\u0441\u0447\u0451\u0442\u043d\u044b\u0439 \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0430 17 \u043a\u0433. \u0420\u0430\u0437\u043d\u0438\u0446\u0430 (HEADROOM) \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u0440\u0430\u0432\u043d\u0430 9,84 \u043a\u0433 \u043d\u0430 \u043f\u043b\u0430\u0432\u043a\u0443, \u0430 \u043f\u043e \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430\u043c \u043c\u043e\u0434\u0435\u043b\u0438 \u043d\u0430 \u0442\u0435\u0441\u0442\u0435 \u2014 9,96 \u043a\u0433.\u042d\u0442\u043e \u0432\u0435\u0440\u0445\u043d\u044f\u044f \u043e\u0446\u0435\u043d\u043a\u0430!!!, \u0430 \u043d\u0435 \u043f\u0440\u043e\u0433\u043d\u043e\u0437 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438. \u0426\u0435\u043b\u044c \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0440\u043e\u0432\u043d\u043e \u043d\u0438\u0436\u043d\u0435\u0439 \u0433\u0440\u0430\u043d\u0438\u0446\u044b 0,45 %, \u0431\u0435\u0437 \u0437\u0430\u043f\u0430\u0441\u0430 \u043d\u0430\u0434\u0451\u0436\u043d\u043e\u0441\u0442\u0438. \u0412 \u0446\u0435\u0445\u0435 \u0442\u0430\u043a \u0434\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f: \u043b\u044e\u0431\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u043c\u0438\u043d\u0443\u0441 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0431\u0440\u0430\u043a \u043f\u043e \u043c\u0430\u0440\u0433\u0430\u043d\u0446\u0443. \u0420\u0430\u0431\u043e\u0447\u0443\u044e \u0434\u043e\u0437\u0443 \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u043a\u0430\u043a \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0435 \u043f\u043b\u044e\u0441 \u0437\u0430\u043f\u0430\u0441 (\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043e\u043d \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044f \u043f\u043e\u043b\u0437\u0443\u043d\u043a\u043e\u043c), \u0438 \u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430\u043f\u0430\u0441, \u0442\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u044f.\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 Streamlit\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043b\u0435\u0436\u0438\u0442 \u0432 app.py \u0440\u044f\u0434\u043e\u043c \u0441 \u043f\u0430\u043a\u0435\u0442\u043e\u043c \u0438 \u0447\u0438\u0442\u0430\u0435\u0442 \u0442\u0440\u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u0430: data\/eaf_melts_2000.csv, models\/fmn78_model.cbm \u0438 models\/metrics.json. \u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043e\u0431\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043b\u0435\u0442\u0443, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e, \u0430 \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0440\u043e\u0432\u043d\u043e \u0442\u0435, \u0447\u0442\u043e \u043d\u0430\u043f\u0435\u0447\u0430\u0442\u0430\u043b \u0441\u043a\u0440\u0438\u043f\u0442 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f.\u041d\u0430 \u0447\u0435\u0442\u044b\u0440\u0451\u0445 \u0432\u043a\u043b\u0430\u0434\u043a\u0430\u0445:\u041e\u0431\u0437\u043e\u0440 \u2014 \u043c\u0435\u0442\u0440\u0438\u043a\u0438, \u0432\u0430\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u043e\u0432 \u0438 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0437\u0430\u043f\u0430\u0441\u0430;\u0414\u0430\u0442\u0430\u0441\u0435\u0442 \u2014 \u0442\u0430\u0431\u043b\u0438\u0446\u0430, \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0438 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u043a\u043e\u043b\u043e\u043d\u043e\u043a;\u041a\u0430\u043b\u044c\u043a\u0443\u043b\u044f\u0442\u043e\u0440 \u2014 \u043f\u043e\u043b\u0437\u0443\u043d\u043a\u0438 \u0448\u0438\u0445\u0442\u044b \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043f\u043b\u0430\u0432\u043a\u0438, \u043e\u0442\u0432\u0435\u0442 \u0432 \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u0445;\u041e \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u2014 \u0447\u0442\u043e \u044d\u0442\u043e \u0438 \u0447\u0435\u043c \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f.\u0418\u043c\u043f\u043e\u0440\u0442\u044b, \u043f\u0443\u0442\u0438 \u0438 \u0442\u0435\u043a\u0441\u0442\u044b\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u0432\u0443\u044f\u0437\u044b\u0447\u043d\u043e\u0435 (\u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439 \u0438 \u0440\u0443\u0441\u0441\u043a\u0438\u0439). \u0412\u0441\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043b\u0435\u0436\u0430\u0442 \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435 TEXT, \u043a\u043b\u044e\u0447\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0434\u043b\u044f \u043e\u0431\u043e\u0438\u0445 \u044f\u0437\u044b\u043a\u043e\u0432. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u043d\u0435 \u043f\u0440\u0438\u0432\u043e\u0436\u0443: \u043e\u043d \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u043a\u043e\u043b\u043e 180 \u0441\u0442\u0440\u043e\u043a \u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043f\u043e\u0434\u043f\u0438\u0441\u0435\u0439 \u0438 \u043f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u0439. \u0412\u043e\u0442 \u0435\u0433\u043e \u0444\u043e\u0440\u043c\u0430:import jsonfrom pathlib import Pathimport pandas as pdimport plotly.express as pximport streamlit as stfrom eafsim.generator import CHARGE_KG, COLUMNS, FEMN_RANGE, SCRAP_2A_RANGEfrom eafsim.model import FEATURES, HEADROOM, add_targets, load_model, predict_min_doseROOT = Path(__file__).parentDATA_PATH = ROOT \/ &#171;data&#187; \/&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-502650","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/502650","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=502650"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/502650\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=502650"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=502650"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=502650"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}