Initial commit: добавление проекта predictV1
Включает модели ML для предсказаний, API маршруты, скрипты обучения и данные. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
.venv/
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# CatBoost
|
||||
catboost_info/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
34
BD.txt
Normal file
34
BD.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
CREATE TABLE hero (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name VARCHAR(255)
|
||||
);
|
||||
|
||||
CREATE TABLE matches (
|
||||
id BIGINT PRIMARY KEY,
|
||||
start_time INTEGER,
|
||||
leagueid INTEGER,
|
||||
radiant_team_id INTEGER,
|
||||
dire_team_id INTEGER,
|
||||
radiant_win BOOLEAN,
|
||||
source VARCHAR(255)
|
||||
);
|
||||
|
||||
CREATE TABLE details_match (
|
||||
match_id BIGINT,
|
||||
hero_id INTEGER,
|
||||
team INTEGER,
|
||||
"order" INTEGER,
|
||||
players_id BIGINT,
|
||||
pos INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE teams (
|
||||
id BIGINT PRIMARY KEY,
|
||||
name VARCHAR(255)
|
||||
);
|
||||
|
||||
CREATE TABLE pro_players (
|
||||
id BIGINT PRIMARY KEY,
|
||||
name VARCHAR(255),
|
||||
team_id BIGINT
|
||||
);
|
||||
226
artifacts/feature_importance_bag_of_heroes.csv
Normal file
226
artifacts/feature_importance_bag_of_heroes.csv
Normal file
@@ -0,0 +1,226 @@
|
||||
feature,importance
|
||||
radiant_hero_96,3.5448903148379154
|
||||
is_first_pick_radiant,3.1565223041927504
|
||||
radiant_hero_137,2.0235517900167266
|
||||
radiant_hero_106,1.987790361290638
|
||||
dire_hero_96,1.960286880219167
|
||||
dire_hero_95,1.9082867265736683
|
||||
dire_hero_64,1.7996110650970016
|
||||
radiant_hero_29,1.7315926094694511
|
||||
radiant_hero_72,1.6448044545454794
|
||||
radiant_hero_114,1.6441341241899101
|
||||
dire_hero_13,1.6043480443067073
|
||||
dire_hero_29,1.5796733982550784
|
||||
dire_hero_100,1.5595810413341753
|
||||
radiant_hero_120,1.5349678998581766
|
||||
radiant_hero_126,1.4997652826627643
|
||||
dire_hero_10,1.4639340774176453
|
||||
dire_hero_137,1.4356855498450338
|
||||
dire_hero_37,1.3886017253491347
|
||||
dire_hero_49,1.374665187198288
|
||||
radiant_hero_102,1.3283477995280788
|
||||
dire_hero_45,1.3278670924698959
|
||||
dire_hero_17,1.2812245277976781
|
||||
dire_hero_79,1.2784221281359065
|
||||
dire_hero_39,1.2667408091038088
|
||||
radiant_hero_49,1.2632189131127254
|
||||
radiant_hero_38,1.1962602198205863
|
||||
dire_hero_123,1.1872109503677573
|
||||
dire_hero_102,1.1228931434997156
|
||||
radiant_hero_18,1.1174737519883087
|
||||
dire_hero_87,1.077588910539817
|
||||
radiant_hero_129,1.0219559481460052
|
||||
radiant_hero_46,1.0018953069589642
|
||||
dire_hero_38,0.9996211369063055
|
||||
radiant_hero_37,0.993539916392573
|
||||
dire_hero_120,0.9862796010369532
|
||||
dire_hero_66,0.9376575493895805
|
||||
dire_hero_3,0.9028065601906793
|
||||
dire_hero_2,0.901682474329439
|
||||
dire_hero_28,0.8948171866399827
|
||||
radiant_hero_89,0.89147406950863
|
||||
radiant_hero_53,0.8648249886966961
|
||||
radiant_hero_98,0.8585308463944029
|
||||
radiant_hero_87,0.8381995066812421
|
||||
radiant_hero_66,0.8232327944369873
|
||||
radiant_hero_39,0.8207115488272696
|
||||
dire_hero_94,0.8003485263994297
|
||||
dire_hero_129,0.7788770107522424
|
||||
radiant_hero_28,0.7776717128986811
|
||||
dire_hero_8,0.7691400847093839
|
||||
dire_hero_62,0.7635947687074511
|
||||
dire_hero_16,0.7634034659406227
|
||||
radiant_hero_8,0.7619724662859222
|
||||
dire_hero_77,0.7528422859580692
|
||||
dire_hero_59,0.7508683533785772
|
||||
radiant_hero_17,0.7476607306553408
|
||||
radiant_hero_77,0.7441942841775127
|
||||
dire_hero_53,0.7276366474281736
|
||||
dire_hero_99,0.7233076956342283
|
||||
radiant_hero_13,0.7193942058596804
|
||||
radiant_hero_128,0.7001897029702516
|
||||
radiant_hero_70,0.6938372976032963
|
||||
radiant_hero_64,0.6691934104513008
|
||||
radiant_hero_123,0.638529772522028
|
||||
dire_hero_98,0.6319093349534167
|
||||
radiant_hero_45,0.6062424683655009
|
||||
radiant_hero_79,0.5868955332730199
|
||||
radiant_hero_52,0.5840206533460277
|
||||
dire_hero_72,0.5806209726259308
|
||||
dire_hero_89,0.5790685908445176
|
||||
dire_hero_18,0.5722360992240108
|
||||
radiant_hero_95,0.5635903439598497
|
||||
dire_hero_70,0.5583839849822786
|
||||
dire_hero_69,0.5520070584047531
|
||||
dire_hero_46,0.5396131611619958
|
||||
dire_hero_119,0.5358381979706183
|
||||
radiant_hero_65,0.5192645247152368
|
||||
radiant_hero_62,0.5183279865244088
|
||||
radiant_hero_135,0.49936800424506134
|
||||
radiant_hero_2,0.4817157203218963
|
||||
radiant_hero_69,0.4674047119278839
|
||||
dire_hero_105,0.4672531552610654
|
||||
dire_hero_128,0.46490506129257847
|
||||
dire_hero_52,0.45906683460354497
|
||||
dire_hero_131,0.4519549389897154
|
||||
radiant_hero_100,0.4237007080091267
|
||||
radiant_hero_3,0.4200207882294507
|
||||
dire_hero_58,0.41845651287518343
|
||||
dire_hero_101,0.39098204345118254
|
||||
radiant_hero_58,0.36615994337973956
|
||||
radiant_hero_90,0.3654215922377207
|
||||
radiant_hero_109,0.36114422894241377
|
||||
radiant_hero_85,0.3397063517524785
|
||||
dire_hero_47,0.33120483123859173
|
||||
dire_hero_65,0.3201442668327861
|
||||
radiant_hero_16,0.3054077635508628
|
||||
dire_hero_51,0.27585362626776144
|
||||
dire_hero_126,0.273936700171308
|
||||
radiant_hero_145,0.27080666451804547
|
||||
dire_hero_50,0.24193256479700528
|
||||
dire_hero_14,0.2307593677866238
|
||||
dire_hero_138,0.22995826671565825
|
||||
dire_hero_108,0.22299160580230648
|
||||
radiant_hero_50,0.22224984591119692
|
||||
radiant_hero_55,0.22024426849261636
|
||||
radiant_hero_110,0.21815464793464948
|
||||
dire_hero_145,0.21662542865055226
|
||||
dire_hero_109,0.21105314668783304
|
||||
dire_hero_71,0.2037500212802944
|
||||
radiant_hero_51,0.20131521608992764
|
||||
radiant_hero_99,0.1878406955271859
|
||||
dire_hero_114,0.18771311441859298
|
||||
radiant_hero_61,0.18042090494382437
|
||||
radiant_hero_19,0.17972494076335502
|
||||
dire_hero_135,0.17674176940995884
|
||||
radiant_hero_138,0.17638797830930697
|
||||
radiant_hero_11,0.17173288969835926
|
||||
radiant_hero_131,0.17163285185364796
|
||||
radiant_hero_71,0.1690626448094322
|
||||
dire_hero_63,0.1677136535489791
|
||||
dire_hero_136,0.1665628310620548
|
||||
radiant_hero_59,0.15482478477426076
|
||||
dire_hero_1,0.14761511544285089
|
||||
radiant_hero_47,0.14432777647536155
|
||||
dire_hero_74,0.14328897339865496
|
||||
radiant_hero_60,0.1350544787435433
|
||||
dire_hero_54,0.13444883015330528
|
||||
radiant_hero_33,0.13418407698461643
|
||||
radiant_hero_14,0.13062864684037695
|
||||
dire_hero_55,0.11982716113335097
|
||||
dire_hero_41,0.11590519381635243
|
||||
radiant_hero_101,0.11145841473118147
|
||||
radiant_hero_26,0.11042331242123556
|
||||
radiant_hero_121,0.10624052682211534
|
||||
dire_hero_73,0.10523838204127042
|
||||
dire_hero_85,0.10116628070719334
|
||||
radiant_hero_75,0.0990778076023039
|
||||
radiant_hero_136,0.0971404322283737
|
||||
dire_hero_121,0.0882738489185766
|
||||
radiant_hero_48,0.08644988028482627
|
||||
radiant_hero_105,0.08636504455479098
|
||||
dire_hero_78,0.086083302792892
|
||||
dire_hero_112,0.08186185440747837
|
||||
radiant_hero_21,0.08031441854242871
|
||||
dire_hero_11,0.08022938628242476
|
||||
radiant_hero_1,0.07993183126994755
|
||||
radiant_hero_73,0.07987048197448883
|
||||
dire_hero_26,0.0751263061140198
|
||||
radiant_hero_40,0.07500706396983621
|
||||
radiant_hero_88,0.06448627461148718
|
||||
radiant_hero_103,0.0596421467981599
|
||||
radiant_hero_35,0.05811051984217868
|
||||
radiant_hero_108,0.05783500222406305
|
||||
radiant_hero_10,0.048789752327982654
|
||||
dire_hero_21,0.04778443130941926
|
||||
dire_hero_6,0.04540743981832734
|
||||
dire_hero_106,0.04419874118360171
|
||||
radiant_hero_9,0.04183971731090627
|
||||
dire_hero_7,0.04151823003037786
|
||||
radiant_hero_36,0.04071609662932216
|
||||
dire_hero_93,0.03917124022761937
|
||||
radiant_hero_57,0.03746648579498447
|
||||
dire_hero_32,0.035168701377993536
|
||||
radiant_hero_54,0.03379848987272846
|
||||
radiant_hero_83,0.031345340329813724
|
||||
dire_hero_103,0.03072106078174553
|
||||
dire_hero_60,0.030582548339197258
|
||||
radiant_hero_32,0.029014217937254724
|
||||
radiant_hero_80,0.026474334315182813
|
||||
dire_hero_33,0.02517097042722223
|
||||
radiant_hero_78,0.024575425448720087
|
||||
radiant_hero_82,0.022026769618172896
|
||||
dire_hero_86,0.021481951040091762
|
||||
dire_hero_88,0.020529621747134498
|
||||
radiant_hero_68,0.019783709474760987
|
||||
dire_hero_75,0.019335981384286435
|
||||
radiant_hero_63,0.018498391135059748
|
||||
radiant_hero_5,0.018167936059773637
|
||||
dire_hero_40,0.01747482989495453
|
||||
radiant_hero_41,0.01742109465745823
|
||||
radiant_hero_23,0.015723888573406297
|
||||
radiant_hero_97,0.014281791505775597
|
||||
dire_hero_68,0.012826265095086503
|
||||
radiant_hero_27,0.012675770453317775
|
||||
dire_hero_110,0.012543695625851782
|
||||
radiant_hero_15,0.011406703339127508
|
||||
dire_hero_19,0.010305059042443747
|
||||
dire_hero_97,0.010205238293995356
|
||||
dire_hero_104,0.009982129745724043
|
||||
radiant_hero_74,0.009456035513835673
|
||||
dire_hero_91,0.007828627023014963
|
||||
dire_hero_35,0.007655784085914658
|
||||
radiant_hero_104,0.0072801341665292155
|
||||
dire_hero_82,0.0066323538462641
|
||||
dire_hero_23,0.0060004954896882255
|
||||
radiant_hero_86,0.005622298563036045
|
||||
radiant_hero_25,0.005493482170013952
|
||||
radiant_hero_22,0.0054192470856789625
|
||||
dire_hero_48,0.0051407952840448615
|
||||
radiant_hero_7,0.005138603464622757
|
||||
dire_hero_90,0.005123300607378032
|
||||
radiant_hero_67,0.004597631094333278
|
||||
dire_hero_36,0.002401848761390748
|
||||
dire_hero_61,0.00032280295629982147
|
||||
dire_hero_43,0.0
|
||||
radiant_hero_56,0.0
|
||||
dire_hero_67,0.0
|
||||
dire_hero_56,0.0
|
||||
dire_hero_9,0.0
|
||||
dire_hero_5,0.0
|
||||
dire_hero_57,0.0
|
||||
radiant_hero_6,0.0
|
||||
dire_hero_80,0.0
|
||||
radiant_hero_112,0.0
|
||||
dire_hero_22,0.0
|
||||
dire_hero_25,0.0
|
||||
radiant_hero_43,0.0
|
||||
dire_hero_15,0.0
|
||||
radiant_hero_91,0.0
|
||||
radiant_hero_93,0.0
|
||||
radiant_hero_94,0.0
|
||||
dire_hero_34,0.0
|
||||
radiant_hero_34,0.0
|
||||
radiant_hero_119,0.0
|
||||
dire_hero_27,0.0
|
||||
dire_hero_83,0.0
|
||||
|
411
artifacts/feature_importance_db.csv
Normal file
411
artifacts/feature_importance_db.csv
Normal file
@@ -0,0 +1,411 @@
|
||||
feature,importance
|
||||
radiant_h126_p2,5.8458473601590715
|
||||
radiant_h96_p4,5.2413063229870165
|
||||
dire_h10_p3,4.904683311960459
|
||||
dire_h37_p3,4.8751699328103335
|
||||
radiant_h89_p1,2.4715406190858067
|
||||
radiant_h46_p1,2.455964779498448
|
||||
radiant_h29_p4,2.3728880092419993
|
||||
dire_h95_p3,2.230103174869408
|
||||
radiant_h100_p1,2.055912748373654
|
||||
radiant_h137_p2,2.011249388205107
|
||||
radiant_h114_p1,1.8834632265713043
|
||||
radiant_h106_p2,1.862418726366778
|
||||
radiant_h18_p1,1.859907271551847
|
||||
radiant_h120_p4,1.768662877638573
|
||||
radiant_h37_p1,1.7297278884453906
|
||||
radiant_h8_p1,1.4434684244563847
|
||||
dire_h94_p3,1.394179590286315
|
||||
radiant_h110_p1,1.3797194949204172
|
||||
dire_h13_p2,1.364320358951324
|
||||
dire_h137_p2,1.3423520562699351
|
||||
radiant_h128_p1,1.2200491444875372
|
||||
radiant_h38_p2,1.1861633538551983
|
||||
dire_h29_p5,1.1845192629048282
|
||||
radiant_h95_p1,1.1685338110028223
|
||||
radiant_h114_p2,1.108551650488793
|
||||
dire_h45_p3,1.0881588369614426
|
||||
radiant_h16_p4,1.0870253279315796
|
||||
dire_h105_p5,1.026037232399492
|
||||
dire_h64_p3,0.9866609384774393
|
||||
dire_h50_p3,0.9397591580025132
|
||||
dire_h126_p2,0.9309916370809915
|
||||
dire_h100_p3,0.8936596185436807
|
||||
radiant_h128_p4,0.8909609351058465
|
||||
dire_h69_p5,0.7665391285229455
|
||||
dire_h62_p5,0.7160026508265112
|
||||
radiant_h135_p4,0.6826178347246731
|
||||
dire_h129_p5,0.6618225408354624
|
||||
radiant_h13_p2,0.6453650965826967
|
||||
radiant_h100_p2,0.643789764434119
|
||||
dire_h101_p3,0.6268127211790587
|
||||
dire_h2_p5,0.6256596657614748
|
||||
radiant_h79_p1,0.6062709463538
|
||||
radiant_h48_p1,0.5665592628123931
|
||||
radiant_h72_p1,0.5643459637965885
|
||||
dire_h59_p2,0.5592053371112652
|
||||
dire_h123_p3,0.538750259730039
|
||||
radiant_h49_p1,0.5323370766514985
|
||||
radiant_h96_p2,0.5268237229744013
|
||||
radiant_h16_p2,0.5227450878750749
|
||||
dire_h96_p5,0.5144175057861532
|
||||
dire_h79_p3,0.5140812953951107
|
||||
dire_h102_p3,0.5001100296143036
|
||||
dire_h58_p5,0.49248173684856916
|
||||
dire_h96_p2,0.49046939907184245
|
||||
dire_h38_p5,0.4900988922655234
|
||||
radiant_h62_p4,0.4693824339639839
|
||||
dire_h108_p5,0.4481346895143821
|
||||
dire_h51_p3,0.42574007658374796
|
||||
radiant_h101_p4,0.41274612052046733
|
||||
dire_h16_p5,0.3991129414642077
|
||||
dire_h98_p2,0.38203893761032565
|
||||
radiant_h102_p4,0.3789026178513027
|
||||
dire_h33_p5,0.37858029577187385
|
||||
radiant_h66_p4,0.36920914966145385
|
||||
dire_h79_p5,0.368997590165472
|
||||
dire_h14_p2,0.36729790467873835
|
||||
dire_h53_p2,0.3575502549625211
|
||||
dire_h14_p5,0.3489320324776503
|
||||
dire_h131_p5,0.33238827327668086
|
||||
radiant_h64_p1,0.31654185831002823
|
||||
dire_h145_p3,0.31636605491217396
|
||||
dire_h66_p5,0.3056930294825178
|
||||
dire_h49_p3,0.30216040809135813
|
||||
radiant_h98_p2,0.2983369585155709
|
||||
dire_h119_p5,0.2969651388369031
|
||||
radiant_h51_p4,0.29503345298908507
|
||||
dire_h123_p5,0.29457863284774666
|
||||
radiant_h138_p4,0.28462730610184617
|
||||
dire_h38_p3,0.28411522961712354
|
||||
radiant_h129_p4,0.28071616499432145
|
||||
radiant_h87_p1,0.2772353555717822
|
||||
dire_h71_p2,0.2771697129061259
|
||||
dire_h65_p2,0.2671044075454367
|
||||
radiant_h28_p4,0.26180741762762
|
||||
dire_h3_p3,0.24847447988978347
|
||||
dire_h66_p3,0.24572704845069399
|
||||
dire_h98_p5,0.23450022414707072
|
||||
radiant_h121_p4,0.23225208934071856
|
||||
dire_h41_p3,0.22719989028850499
|
||||
dire_h128_p3,0.22553985774297788
|
||||
dire_h123_p2,0.22489449839123
|
||||
radiant_h85_p4,0.22098025932507387
|
||||
radiant_h100_p4,0.21314814210252667
|
||||
dire_h64_p5,0.2124310360629601
|
||||
radiant_h137_p4,0.21077351042091994
|
||||
dire_h54_p3,0.20960551422486035
|
||||
dire_h77_p5,0.20917567201529455
|
||||
dire_h74_p2,0.20900629651347968
|
||||
radiant_h62_p2,0.20047283058947185
|
||||
dire_h72_p3,0.19963348230418612
|
||||
radiant_h17_p2,0.19943046071083703
|
||||
dire_h1_p3,0.1989514989016405
|
||||
dire_h112_p3,0.189525683304801
|
||||
dire_h135_p5,0.18660153542829755
|
||||
radiant_h51_p1,0.1839451724510298
|
||||
dire_h17_p2,0.18144460466176354
|
||||
radiant_h39_p2,0.1773343712477707
|
||||
dire_h128_p5,0.1716387627657839
|
||||
radiant_h59_p2,0.1658113264628484
|
||||
radiant_h123_p4,0.16524458827289465
|
||||
dire_h136_p3,0.16428663110142036
|
||||
dire_h99_p3,0.15563937327452676
|
||||
radiant_h28_p2,0.1552433245712145
|
||||
radiant_h110_p4,0.1481849002793656
|
||||
radiant_h109_p1,0.1480295895745146
|
||||
dire_h114_p3,0.14642637091481026
|
||||
radiant_h136_p1,0.14475648830556773
|
||||
dire_h6_p3,0.14266759350968217
|
||||
radiant_h10_p1,0.1407809735639152
|
||||
dire_h21_p5,0.14009499849996965
|
||||
radiant_h19_p4,0.13554800050635046
|
||||
radiant_h45_p1,0.1260353455334229
|
||||
dire_h62_p2,0.12444567821891489
|
||||
dire_h87_p3,0.12400854793721895
|
||||
dire_h47_p2,0.12322736048740845
|
||||
radiant_h64_p4,0.12025364829699399
|
||||
dire_h28_p2,0.1167194303132419
|
||||
radiant_h79_p4,0.11126994656278297
|
||||
dire_h65_p3,0.11001179790040895
|
||||
radiant_h55_p4,0.109830151464457
|
||||
radiant_h123_p1,0.10923279779321164
|
||||
radiant_h5_p1,0.10825087911784789
|
||||
dire_h52_p2,0.10721595385915003
|
||||
radiant_h47_p4,0.10657272981209304
|
||||
dire_h99_p5,0.10521485722571794
|
||||
dire_h58_p3,0.10339880809387055
|
||||
radiant_h80_p1,0.10303018459499493
|
||||
radiant_h3_p1,0.10205005418627881
|
||||
radiant_h77_p4,0.10129398823464544
|
||||
dire_h55_p5,0.10110820227360126
|
||||
dire_h120_p2,0.09822231013289165
|
||||
radiant_h58_p1,0.09653167031005891
|
||||
radiant_h65_p2,0.09466007371296598
|
||||
dire_h26_p3,0.09409797989341304
|
||||
radiant_h49_p2,0.09291996782584751
|
||||
dire_h89_p3,0.09133770378009658
|
||||
radiant_h65_p4,0.08943794758237843
|
||||
radiant_h99_p1,0.08531614935843866
|
||||
radiant_h119_p4,0.08499065485609215
|
||||
dire_h128_p2,0.08468309192671122
|
||||
dire_h103_p3,0.08321942302625805
|
||||
dire_h131_p3,0.07824810644437837
|
||||
dire_h3_p5,0.07781846172892126
|
||||
radiant_h21_p1,0.07714277136775362
|
||||
dire_h17_p3,0.07665703405232827
|
||||
dire_h79_p2,0.07223633538998198
|
||||
radiant_h128_p2,0.07148459937706637
|
||||
dire_h11_p2,0.0699511983979549
|
||||
dire_h138_p3,0.06729258112518181
|
||||
radiant_h53_p2,0.06426211048703748
|
||||
dire_h38_p2,0.06328898002223096
|
||||
radiant_h87_p4,0.06045458721975193
|
||||
dire_h8_p3,0.06008848291210074
|
||||
dire_h85_p5,0.05701646690525239
|
||||
dire_h59_p3,0.05695578045236214
|
||||
dire_h33_p2,0.05685990074342323
|
||||
dire_h145_p2,0.05685848500238464
|
||||
radiant_h35_p2,0.0563485612274038
|
||||
dire_h80_p3,0.054475049923284107
|
||||
dire_h37_p5,0.05412797726459125
|
||||
dire_h51_p2,0.05238656751072729
|
||||
radiant_h21_p2,0.04891215667599588
|
||||
radiant_h70_p1,0.048388185285702684
|
||||
radiant_h131_p4,0.04632085263177447
|
||||
radiant_h7_p4,0.045736550588018905
|
||||
dire_h50_p2,0.04486684683506996
|
||||
dire_h32_p2,0.044500529959637526
|
||||
dire_h109_p3,0.04413961848243405
|
||||
radiant_h131_p1,0.043885261597800616
|
||||
radiant_h2_p1,0.04229473461558145
|
||||
radiant_h59_p1,0.04001087584966364
|
||||
dire_h58_p2,0.03949191457469012
|
||||
dire_h137_p5,0.0391094560324883
|
||||
dire_h136_p5,0.03900219076238762
|
||||
radiant_h129_p2,0.03894637522695674
|
||||
dire_h51_p5,0.03759830461523884
|
||||
radiant_h50_p1,0.03759053956597159
|
||||
dire_h72_p5,0.03489297482691151
|
||||
dire_h29_p3,0.03282918656004574
|
||||
dire_h69_p2,0.032820814888430985
|
||||
dire_h40_p5,0.03222312506053804
|
||||
dire_h126_p3,0.030721958885042398
|
||||
dire_h7_p2,0.030039091015776988
|
||||
radiant_h99_p4,0.029512814453624206
|
||||
radiant_h90_p4,0.028939315633782634
|
||||
radiant_h38_p4,0.028884251904941007
|
||||
radiant_h145_p4,0.02867246389735757
|
||||
radiant_h52_p2,0.028327909211325466
|
||||
radiant_h41_p1,0.02830912056061567
|
||||
dire_h65_p5,0.02654669563264836
|
||||
radiant_h3_p2,0.02638330196290669
|
||||
radiant_h101_p2,0.02629175112197391
|
||||
dire_h16_p2,0.025772625978061615
|
||||
dire_h89_p5,0.025423167507288597
|
||||
dire_h56_p3,0.023965420375433373
|
||||
dire_h27_p5,0.023630615883621444
|
||||
radiant_h14_p4,0.023577743244984795
|
||||
dire_h46_p2,0.02351381664660187
|
||||
radiant_h145_p1,0.022954662063548625
|
||||
radiant_h105_p1,0.02172386381775776
|
||||
dire_h101_p2,0.021665429499901225
|
||||
dire_h138_p2,0.020603105835900505
|
||||
radiant_h80_p2,0.020205886463181916
|
||||
radiant_h45_p4,0.019873648320156683
|
||||
dire_h75_p3,0.019095868018218366
|
||||
dire_h71_p5,0.01883594340373369
|
||||
radiant_h50_p4,0.01851801278627182
|
||||
dire_h82_p2,0.016021411378539022
|
||||
radiant_h14_p1,0.015638780734061875
|
||||
radiant_h7_p2,0.015228489858375386
|
||||
dire_h35_p2,0.014581160993008303
|
||||
dire_h37_p2,0.014149570144541398
|
||||
dire_h19_p5,0.014128813027374842
|
||||
radiant_h68_p4,0.013874112600904527
|
||||
dire_h73_p5,0.01370357622392973
|
||||
dire_h45_p2,0.013429139431625712
|
||||
dire_h121_p2,0.012720482369728212
|
||||
dire_h103_p2,0.012580245658732822
|
||||
dire_h78_p5,0.011479650208403117
|
||||
radiant_h75_p1,0.011279211658043697
|
||||
radiant_h87_p2,0.011009288964859922
|
||||
radiant_h70_p4,0.010970134670089926
|
||||
radiant_h15_p4,0.010315240629483772
|
||||
dire_h82_p3,0.010238889513433087
|
||||
dire_h86_p3,0.010192656397498409
|
||||
radiant_h71_p2,0.01016778152865779
|
||||
radiant_h83_p1,0.01012520567813156
|
||||
dire_h48_p3,0.009918647322710925
|
||||
radiant_h6_p1,0.009671953743806175
|
||||
dire_h100_p2,0.009571320930816713
|
||||
radiant_h90_p1,0.009527065031710249
|
||||
dire_h119_p3,0.009483840085729776
|
||||
dire_h11_p3,0.009196223596199492
|
||||
radiant_h3_p4,0.008785437579069688
|
||||
radiant_h126_p4,0.008492948766508739
|
||||
dire_h90_p3,0.007462288997548156
|
||||
dire_h36_p2,0.007168244918332031
|
||||
radiant_h65_p1,0.007075073353615007
|
||||
dire_h110_p2,0.007058771939753352
|
||||
radiant_h88_p1,0.006970413712592924
|
||||
dire_h3_p2,0.006770288324985224
|
||||
radiant_h75_p4,0.005605529479664017
|
||||
dire_h49_p2,0.005416375206431143
|
||||
dire_h18_p3,0.004093083977963181
|
||||
radiant_h54_p1,0.0037737028436135673
|
||||
dire_h46_p3,0.0035428141984589754
|
||||
dire_h63_p3,0.0024149663125720977
|
||||
radiant_h67_p1,0.0023868366959004647
|
||||
radiant_h33_p4,0.000814854247060661
|
||||
radiant_h62_p1,0.00025903618440001206
|
||||
dire_h88_p5,0.0002260965151758602
|
||||
radiant_h98_p1,0.00013342577498281341
|
||||
dire_h26_p5,9.687953196849277e-05
|
||||
radiant_h94_p1,3.0479330214625887e-05
|
||||
radiant_h138_p2,1.2930866595732473e-06
|
||||
dire_h23_p5,0.0
|
||||
radiant_h53_p1,0.0
|
||||
dire_h91_p3,0.0
|
||||
dire_h14_p3,0.0
|
||||
dire_h68_p3,0.0
|
||||
dire_h120_p5,0.0
|
||||
dire_h53_p5,0.0
|
||||
dire_h85_p3,0.0
|
||||
radiant_h71_p4,0.0
|
||||
radiant_h27_p1,0.0
|
||||
radiant_h23_p4,0.0
|
||||
dire_h97_p5,0.0
|
||||
dire_h70_p3,0.0
|
||||
dire_h13_p5,0.0
|
||||
radiant_h73_p4,0.0
|
||||
dire_h110_p3,0.0
|
||||
dire_h39_p2,0.0
|
||||
dire_h28_p5,0.0
|
||||
dire_h131_p2,0.0
|
||||
radiant_h71_p1,0.0
|
||||
dire_h21_p2,0.0
|
||||
radiant_h102_p1,0.0
|
||||
radiant_h40_p1,0.0
|
||||
radiant_h32_p1,0.0
|
||||
dire_h40_p2,0.0
|
||||
radiant_h66_p1,0.0
|
||||
dire_h70_p5,0.0
|
||||
radiant_h51_p2,0.0
|
||||
dire_h27_p3,0.0
|
||||
dire_h19_p3,0.0
|
||||
dire_h129_p2,0.0
|
||||
radiant_h11_p2,0.0
|
||||
radiant_h79_p2,0.0
|
||||
radiant_h88_p2,0.0
|
||||
dire_h18_p5,0.0
|
||||
dire_h104_p5,0.0
|
||||
dire_h77_p2,0.0
|
||||
radiant_h89_p4,0.0
|
||||
dire_h138_p5,0.0
|
||||
radiant_h73_p1,0.0
|
||||
radiant_h19_p2,0.0
|
||||
dire_h105_p3,0.0
|
||||
radiant_h17_p1,0.0
|
||||
dire_h68_p2,0.0
|
||||
dire_h19_p2,0.0
|
||||
dire_h39_p3,0.0
|
||||
radiant_h47_p2,0.0
|
||||
radiant_h9_p2,0.0
|
||||
dire_h47_p5,0.0
|
||||
dire_h114_p5,0.0
|
||||
dire_h88_p2,0.0
|
||||
dire_h49_p5,0.0
|
||||
radiant_h58_p2,0.0
|
||||
radiant_h61_p1,0.0
|
||||
dire_h23_p2,0.0
|
||||
radiant_h64_p2,0.0
|
||||
dire_h100_p5,0.0
|
||||
radiant_h73_p2,0.0
|
||||
radiant_h78_p4,0.0
|
||||
radiant_h129_p1,0.0
|
||||
dire_h64_p2,0.0
|
||||
radiant_h1_p1,0.0
|
||||
radiant_h32_p4,0.0
|
||||
radiant_h120_p2,0.0
|
||||
radiant_h22_p2,0.0
|
||||
dire_h60_p5,0.0
|
||||
dire_h69_p3,0.0
|
||||
radiant_h66_p5,0.0
|
||||
radiant_h61_p2,0.0
|
||||
radiant_h103_p4,0.0
|
||||
radiant_h108_p4,0.0
|
||||
radiant_h82_p1,0.0
|
||||
dire_h61_p3,0.0
|
||||
radiant_h138_p1,0.0
|
||||
radiant_h9_p1,0.0
|
||||
dire_h121_p5,0.0
|
||||
dire_h89_p2,0.0
|
||||
radiant_h36_p1,0.0
|
||||
dire_h103_p5,0.0
|
||||
radiant_h97_p4,0.0
|
||||
radiant_h114_p4,0.0
|
||||
radiant_h36_p2,0.0
|
||||
radiant_h85_p1,0.0
|
||||
dire_h43_p2,0.0
|
||||
radiant_h58_p4,0.0
|
||||
radiant_h69_p4,0.0
|
||||
radiant_h39_p1,0.0
|
||||
radiant_h74_p2,0.0
|
||||
dire_h102_p5,0.0
|
||||
radiant_h123_p2,0.0
|
||||
radiant_h2_p4,0.0
|
||||
radiant_h57_p1,0.0
|
||||
radiant_h98_p4,0.0
|
||||
radiant_h119_p1,0.0
|
||||
dire_h86_p5,0.0
|
||||
radiant_h61_p4,0.0
|
||||
radiant_h14_p2,0.0
|
||||
radiant_h60_p4,0.0
|
||||
radiant_h103_p1,0.0
|
||||
radiant_h104_p4,0.0
|
||||
dire_h53_p3,0.0
|
||||
radiant_h136_p4,0.0
|
||||
dire_h106_p2,0.0
|
||||
radiant_h68_p1,0.0
|
||||
radiant_h63_p1,0.0
|
||||
radiant_h105_p4,0.0
|
||||
dire_h34_p2,0.0
|
||||
radiant_h72_p4,0.0
|
||||
dire_h101_p5,0.0
|
||||
radiant_h121_p1,0.0
|
||||
dire_h93_p5,0.0
|
||||
dire_h10_p2,0.0
|
||||
radiant_h21_p4,0.0
|
||||
radiant_h101_p1,0.0
|
||||
radiant_h126_p1,0.0
|
||||
radiant_h37_p2,0.0
|
||||
radiant_h131_p2,0.0
|
||||
radiant_h11_p1,0.0
|
||||
radiant_h66_p2,0.0
|
||||
dire_h62_p3,0.0
|
||||
radiant_h60_p1,0.0
|
||||
radiant_h52_p4,0.0
|
||||
dire_h95_p5,0.0
|
||||
radiant_h90_p2,0.0
|
||||
radiant_h88_p4,0.0
|
||||
dire_h114_p2,0.0
|
||||
radiant_h33_p2,0.0
|
||||
radiant_h26_p4,0.0
|
||||
radiant_h39_p4,0.0
|
||||
dire_h9_p3,0.0
|
||||
radiant_h13_p4,0.0
|
||||
dire_h126_p5,0.0
|
||||
dire_h7_p5,0.0
|
||||
radiant_h40_p2,0.0
|
||||
dire_h87_p5,0.0
|
||||
dire_h21_p3,0.0
|
||||
radiant_h86_p4,0.0
|
||||
dire_h85_p2,0.0
|
||||
radiant_h49_p4,0.0
|
||||
dire_h41_p5,0.0
|
||||
dire_h98_p3,0.0
|
||||
dire_h73_p3,0.0
|
||||
dire_h45_p5,0.0
|
||||
radiant_h69_p1,0.0
|
||||
radiant_h25_p2,0.0
|
||||
|
4
artifacts/feature_importance_stacking.csv
Normal file
4
artifacts/feature_importance_stacking.csv
Normal file
@@ -0,0 +1,4 @@
|
||||
feature,importance
|
||||
pred_with_positions,2.8814398908281142
|
||||
pred_bag_of_heroes,6.656601650820854
|
||||
pred_with_players,0.3906490762854252
|
||||
|
4509
artifacts/feature_importance_with_players.csv
Normal file
4509
artifacts/feature_importance_with_players.csv
Normal file
File diff suppressed because it is too large
Load Diff
226
artifacts/feature_order_bag_of_heroes.csv
Normal file
226
artifacts/feature_order_bag_of_heroes.csv
Normal file
@@ -0,0 +1,226 @@
|
||||
feature
|
||||
is_first_pick_radiant
|
||||
radiant_hero_1
|
||||
dire_hero_1
|
||||
radiant_hero_2
|
||||
dire_hero_2
|
||||
radiant_hero_3
|
||||
dire_hero_3
|
||||
radiant_hero_5
|
||||
dire_hero_5
|
||||
radiant_hero_6
|
||||
dire_hero_6
|
||||
radiant_hero_7
|
||||
dire_hero_7
|
||||
radiant_hero_8
|
||||
dire_hero_8
|
||||
radiant_hero_9
|
||||
dire_hero_9
|
||||
radiant_hero_10
|
||||
dire_hero_10
|
||||
radiant_hero_11
|
||||
dire_hero_11
|
||||
radiant_hero_13
|
||||
dire_hero_13
|
||||
radiant_hero_14
|
||||
dire_hero_14
|
||||
radiant_hero_15
|
||||
dire_hero_15
|
||||
radiant_hero_16
|
||||
dire_hero_16
|
||||
radiant_hero_17
|
||||
dire_hero_17
|
||||
radiant_hero_18
|
||||
dire_hero_18
|
||||
radiant_hero_19
|
||||
dire_hero_19
|
||||
radiant_hero_21
|
||||
dire_hero_21
|
||||
radiant_hero_22
|
||||
dire_hero_22
|
||||
radiant_hero_23
|
||||
dire_hero_23
|
||||
radiant_hero_25
|
||||
dire_hero_25
|
||||
radiant_hero_26
|
||||
dire_hero_26
|
||||
radiant_hero_27
|
||||
dire_hero_27
|
||||
radiant_hero_28
|
||||
dire_hero_28
|
||||
radiant_hero_29
|
||||
dire_hero_29
|
||||
radiant_hero_32
|
||||
dire_hero_32
|
||||
radiant_hero_33
|
||||
dire_hero_33
|
||||
radiant_hero_34
|
||||
dire_hero_34
|
||||
radiant_hero_35
|
||||
dire_hero_35
|
||||
radiant_hero_36
|
||||
dire_hero_36
|
||||
radiant_hero_37
|
||||
dire_hero_37
|
||||
radiant_hero_38
|
||||
dire_hero_38
|
||||
radiant_hero_39
|
||||
dire_hero_39
|
||||
radiant_hero_40
|
||||
dire_hero_40
|
||||
radiant_hero_41
|
||||
dire_hero_41
|
||||
radiant_hero_43
|
||||
dire_hero_43
|
||||
radiant_hero_45
|
||||
dire_hero_45
|
||||
radiant_hero_46
|
||||
dire_hero_46
|
||||
radiant_hero_47
|
||||
dire_hero_47
|
||||
radiant_hero_48
|
||||
dire_hero_48
|
||||
radiant_hero_49
|
||||
dire_hero_49
|
||||
radiant_hero_50
|
||||
dire_hero_50
|
||||
radiant_hero_51
|
||||
dire_hero_51
|
||||
radiant_hero_52
|
||||
dire_hero_52
|
||||
radiant_hero_53
|
||||
dire_hero_53
|
||||
radiant_hero_54
|
||||
dire_hero_54
|
||||
radiant_hero_55
|
||||
dire_hero_55
|
||||
radiant_hero_56
|
||||
dire_hero_56
|
||||
radiant_hero_57
|
||||
dire_hero_57
|
||||
radiant_hero_58
|
||||
dire_hero_58
|
||||
radiant_hero_59
|
||||
dire_hero_59
|
||||
radiant_hero_60
|
||||
dire_hero_60
|
||||
radiant_hero_61
|
||||
dire_hero_61
|
||||
radiant_hero_62
|
||||
dire_hero_62
|
||||
radiant_hero_63
|
||||
dire_hero_63
|
||||
radiant_hero_64
|
||||
dire_hero_64
|
||||
radiant_hero_65
|
||||
dire_hero_65
|
||||
radiant_hero_66
|
||||
dire_hero_66
|
||||
radiant_hero_67
|
||||
dire_hero_67
|
||||
radiant_hero_68
|
||||
dire_hero_68
|
||||
radiant_hero_69
|
||||
dire_hero_69
|
||||
radiant_hero_70
|
||||
dire_hero_70
|
||||
radiant_hero_71
|
||||
dire_hero_71
|
||||
radiant_hero_72
|
||||
dire_hero_72
|
||||
radiant_hero_73
|
||||
dire_hero_73
|
||||
radiant_hero_74
|
||||
dire_hero_74
|
||||
radiant_hero_75
|
||||
dire_hero_75
|
||||
radiant_hero_77
|
||||
dire_hero_77
|
||||
radiant_hero_78
|
||||
dire_hero_78
|
||||
radiant_hero_79
|
||||
dire_hero_79
|
||||
radiant_hero_80
|
||||
dire_hero_80
|
||||
radiant_hero_82
|
||||
dire_hero_82
|
||||
radiant_hero_83
|
||||
dire_hero_83
|
||||
radiant_hero_85
|
||||
dire_hero_85
|
||||
radiant_hero_86
|
||||
dire_hero_86
|
||||
radiant_hero_87
|
||||
dire_hero_87
|
||||
radiant_hero_88
|
||||
dire_hero_88
|
||||
radiant_hero_89
|
||||
dire_hero_89
|
||||
radiant_hero_90
|
||||
dire_hero_90
|
||||
radiant_hero_91
|
||||
dire_hero_91
|
||||
radiant_hero_93
|
||||
dire_hero_93
|
||||
radiant_hero_94
|
||||
dire_hero_94
|
||||
radiant_hero_95
|
||||
dire_hero_95
|
||||
radiant_hero_96
|
||||
dire_hero_96
|
||||
radiant_hero_97
|
||||
dire_hero_97
|
||||
radiant_hero_98
|
||||
dire_hero_98
|
||||
radiant_hero_99
|
||||
dire_hero_99
|
||||
radiant_hero_100
|
||||
dire_hero_100
|
||||
radiant_hero_101
|
||||
dire_hero_101
|
||||
radiant_hero_102
|
||||
dire_hero_102
|
||||
radiant_hero_103
|
||||
dire_hero_103
|
||||
radiant_hero_104
|
||||
dire_hero_104
|
||||
radiant_hero_105
|
||||
dire_hero_105
|
||||
radiant_hero_106
|
||||
dire_hero_106
|
||||
radiant_hero_108
|
||||
dire_hero_108
|
||||
radiant_hero_109
|
||||
dire_hero_109
|
||||
radiant_hero_110
|
||||
dire_hero_110
|
||||
radiant_hero_112
|
||||
dire_hero_112
|
||||
radiant_hero_114
|
||||
dire_hero_114
|
||||
radiant_hero_119
|
||||
dire_hero_119
|
||||
radiant_hero_120
|
||||
dire_hero_120
|
||||
radiant_hero_121
|
||||
dire_hero_121
|
||||
radiant_hero_123
|
||||
dire_hero_123
|
||||
radiant_hero_126
|
||||
dire_hero_126
|
||||
radiant_hero_128
|
||||
dire_hero_128
|
||||
radiant_hero_129
|
||||
dire_hero_129
|
||||
radiant_hero_131
|
||||
dire_hero_131
|
||||
radiant_hero_135
|
||||
dire_hero_135
|
||||
radiant_hero_136
|
||||
dire_hero_136
|
||||
radiant_hero_137
|
||||
dire_hero_137
|
||||
radiant_hero_138
|
||||
dire_hero_138
|
||||
radiant_hero_145
|
||||
dire_hero_145
|
||||
|
411
artifacts/feature_order_db.csv
Normal file
411
artifacts/feature_order_db.csv
Normal file
@@ -0,0 +1,411 @@
|
||||
feature
|
||||
dire_h100_p2
|
||||
dire_h100_p3
|
||||
dire_h100_p5
|
||||
dire_h101_p2
|
||||
dire_h101_p3
|
||||
dire_h101_p5
|
||||
dire_h102_p3
|
||||
dire_h102_p5
|
||||
dire_h103_p2
|
||||
dire_h103_p3
|
||||
dire_h103_p5
|
||||
dire_h104_p5
|
||||
dire_h105_p3
|
||||
dire_h105_p5
|
||||
dire_h106_p2
|
||||
dire_h108_p5
|
||||
dire_h109_p3
|
||||
dire_h10_p2
|
||||
dire_h10_p3
|
||||
dire_h110_p2
|
||||
dire_h110_p3
|
||||
dire_h112_p3
|
||||
dire_h114_p2
|
||||
dire_h114_p3
|
||||
dire_h114_p5
|
||||
dire_h119_p3
|
||||
dire_h119_p5
|
||||
dire_h11_p2
|
||||
dire_h11_p3
|
||||
dire_h120_p2
|
||||
dire_h120_p5
|
||||
dire_h121_p2
|
||||
dire_h121_p5
|
||||
dire_h123_p2
|
||||
dire_h123_p3
|
||||
dire_h123_p5
|
||||
dire_h126_p2
|
||||
dire_h126_p3
|
||||
dire_h126_p5
|
||||
dire_h128_p2
|
||||
dire_h128_p3
|
||||
dire_h128_p5
|
||||
dire_h129_p2
|
||||
dire_h129_p5
|
||||
dire_h131_p2
|
||||
dire_h131_p3
|
||||
dire_h131_p5
|
||||
dire_h135_p5
|
||||
dire_h136_p3
|
||||
dire_h136_p5
|
||||
dire_h137_p2
|
||||
dire_h137_p5
|
||||
dire_h138_p2
|
||||
dire_h138_p3
|
||||
dire_h138_p5
|
||||
dire_h13_p2
|
||||
dire_h13_p5
|
||||
dire_h145_p2
|
||||
dire_h145_p3
|
||||
dire_h14_p2
|
||||
dire_h14_p3
|
||||
dire_h14_p5
|
||||
dire_h16_p2
|
||||
dire_h16_p5
|
||||
dire_h17_p2
|
||||
dire_h17_p3
|
||||
dire_h18_p3
|
||||
dire_h18_p5
|
||||
dire_h19_p2
|
||||
dire_h19_p3
|
||||
dire_h19_p5
|
||||
dire_h1_p3
|
||||
dire_h21_p2
|
||||
dire_h21_p3
|
||||
dire_h21_p5
|
||||
dire_h23_p2
|
||||
dire_h23_p5
|
||||
dire_h26_p3
|
||||
dire_h26_p5
|
||||
dire_h27_p3
|
||||
dire_h27_p5
|
||||
dire_h28_p2
|
||||
dire_h28_p5
|
||||
dire_h29_p3
|
||||
dire_h29_p5
|
||||
dire_h2_p5
|
||||
dire_h32_p2
|
||||
dire_h33_p2
|
||||
dire_h33_p5
|
||||
dire_h34_p2
|
||||
dire_h35_p2
|
||||
dire_h36_p2
|
||||
dire_h37_p2
|
||||
dire_h37_p3
|
||||
dire_h37_p5
|
||||
dire_h38_p2
|
||||
dire_h38_p3
|
||||
dire_h38_p5
|
||||
dire_h39_p2
|
||||
dire_h39_p3
|
||||
dire_h3_p2
|
||||
dire_h3_p3
|
||||
dire_h3_p5
|
||||
dire_h40_p2
|
||||
dire_h40_p5
|
||||
dire_h41_p3
|
||||
dire_h41_p5
|
||||
dire_h43_p2
|
||||
dire_h45_p2
|
||||
dire_h45_p3
|
||||
dire_h45_p5
|
||||
dire_h46_p2
|
||||
dire_h46_p3
|
||||
dire_h47_p2
|
||||
dire_h47_p5
|
||||
dire_h48_p3
|
||||
dire_h49_p2
|
||||
dire_h49_p3
|
||||
dire_h49_p5
|
||||
dire_h50_p2
|
||||
dire_h50_p3
|
||||
dire_h51_p2
|
||||
dire_h51_p3
|
||||
dire_h51_p5
|
||||
dire_h52_p2
|
||||
dire_h53_p2
|
||||
dire_h53_p3
|
||||
dire_h53_p5
|
||||
dire_h54_p3
|
||||
dire_h55_p5
|
||||
dire_h56_p3
|
||||
dire_h58_p2
|
||||
dire_h58_p3
|
||||
dire_h58_p5
|
||||
dire_h59_p2
|
||||
dire_h59_p3
|
||||
dire_h60_p5
|
||||
dire_h61_p3
|
||||
dire_h62_p2
|
||||
dire_h62_p3
|
||||
dire_h62_p5
|
||||
dire_h63_p3
|
||||
dire_h64_p2
|
||||
dire_h64_p3
|
||||
dire_h64_p5
|
||||
dire_h65_p2
|
||||
dire_h65_p3
|
||||
dire_h65_p5
|
||||
dire_h66_p3
|
||||
dire_h66_p5
|
||||
dire_h68_p2
|
||||
dire_h68_p3
|
||||
dire_h69_p2
|
||||
dire_h69_p3
|
||||
dire_h69_p5
|
||||
dire_h6_p3
|
||||
dire_h70_p3
|
||||
dire_h70_p5
|
||||
dire_h71_p2
|
||||
dire_h71_p5
|
||||
dire_h72_p3
|
||||
dire_h72_p5
|
||||
dire_h73_p3
|
||||
dire_h73_p5
|
||||
dire_h74_p2
|
||||
dire_h75_p3
|
||||
dire_h77_p2
|
||||
dire_h77_p5
|
||||
dire_h78_p5
|
||||
dire_h79_p2
|
||||
dire_h79_p3
|
||||
dire_h79_p5
|
||||
dire_h7_p2
|
||||
dire_h7_p5
|
||||
dire_h80_p3
|
||||
dire_h82_p2
|
||||
dire_h82_p3
|
||||
dire_h85_p2
|
||||
dire_h85_p3
|
||||
dire_h85_p5
|
||||
dire_h86_p3
|
||||
dire_h86_p5
|
||||
dire_h87_p3
|
||||
dire_h87_p5
|
||||
dire_h88_p2
|
||||
dire_h88_p5
|
||||
dire_h89_p2
|
||||
dire_h89_p3
|
||||
dire_h89_p5
|
||||
dire_h8_p3
|
||||
dire_h90_p3
|
||||
dire_h91_p3
|
||||
dire_h93_p5
|
||||
dire_h94_p3
|
||||
dire_h95_p3
|
||||
dire_h95_p5
|
||||
dire_h96_p2
|
||||
dire_h96_p5
|
||||
dire_h97_p5
|
||||
dire_h98_p2
|
||||
dire_h98_p3
|
||||
dire_h98_p5
|
||||
dire_h99_p3
|
||||
dire_h99_p5
|
||||
dire_h9_p3
|
||||
radiant_h100_p1
|
||||
radiant_h100_p2
|
||||
radiant_h100_p4
|
||||
radiant_h101_p1
|
||||
radiant_h101_p2
|
||||
radiant_h101_p4
|
||||
radiant_h102_p1
|
||||
radiant_h102_p4
|
||||
radiant_h103_p1
|
||||
radiant_h103_p4
|
||||
radiant_h104_p4
|
||||
radiant_h105_p1
|
||||
radiant_h105_p4
|
||||
radiant_h106_p2
|
||||
radiant_h108_p4
|
||||
radiant_h109_p1
|
||||
radiant_h10_p1
|
||||
radiant_h110_p1
|
||||
radiant_h110_p4
|
||||
radiant_h114_p1
|
||||
radiant_h114_p2
|
||||
radiant_h114_p4
|
||||
radiant_h119_p1
|
||||
radiant_h119_p4
|
||||
radiant_h11_p1
|
||||
radiant_h11_p2
|
||||
radiant_h120_p2
|
||||
radiant_h120_p4
|
||||
radiant_h121_p1
|
||||
radiant_h121_p4
|
||||
radiant_h123_p1
|
||||
radiant_h123_p2
|
||||
radiant_h123_p4
|
||||
radiant_h126_p1
|
||||
radiant_h126_p2
|
||||
radiant_h126_p4
|
||||
radiant_h128_p1
|
||||
radiant_h128_p2
|
||||
radiant_h128_p4
|
||||
radiant_h129_p1
|
||||
radiant_h129_p2
|
||||
radiant_h129_p4
|
||||
radiant_h131_p1
|
||||
radiant_h131_p2
|
||||
radiant_h131_p4
|
||||
radiant_h135_p4
|
||||
radiant_h136_p1
|
||||
radiant_h136_p4
|
||||
radiant_h137_p2
|
||||
radiant_h137_p4
|
||||
radiant_h138_p1
|
||||
radiant_h138_p2
|
||||
radiant_h138_p4
|
||||
radiant_h13_p2
|
||||
radiant_h13_p4
|
||||
radiant_h145_p1
|
||||
radiant_h145_p4
|
||||
radiant_h14_p1
|
||||
radiant_h14_p2
|
||||
radiant_h14_p4
|
||||
radiant_h15_p4
|
||||
radiant_h16_p2
|
||||
radiant_h16_p4
|
||||
radiant_h17_p1
|
||||
radiant_h17_p2
|
||||
radiant_h18_p1
|
||||
radiant_h19_p2
|
||||
radiant_h19_p4
|
||||
radiant_h1_p1
|
||||
radiant_h21_p1
|
||||
radiant_h21_p2
|
||||
radiant_h21_p4
|
||||
radiant_h22_p2
|
||||
radiant_h23_p4
|
||||
radiant_h25_p2
|
||||
radiant_h26_p4
|
||||
radiant_h27_p1
|
||||
radiant_h28_p2
|
||||
radiant_h28_p4
|
||||
radiant_h29_p4
|
||||
radiant_h2_p1
|
||||
radiant_h2_p4
|
||||
radiant_h32_p1
|
||||
radiant_h32_p4
|
||||
radiant_h33_p2
|
||||
radiant_h33_p4
|
||||
radiant_h35_p2
|
||||
radiant_h36_p1
|
||||
radiant_h36_p2
|
||||
radiant_h37_p1
|
||||
radiant_h37_p2
|
||||
radiant_h38_p2
|
||||
radiant_h38_p4
|
||||
radiant_h39_p1
|
||||
radiant_h39_p2
|
||||
radiant_h39_p4
|
||||
radiant_h3_p1
|
||||
radiant_h3_p2
|
||||
radiant_h3_p4
|
||||
radiant_h40_p1
|
||||
radiant_h40_p2
|
||||
radiant_h41_p1
|
||||
radiant_h45_p1
|
||||
radiant_h45_p4
|
||||
radiant_h46_p1
|
||||
radiant_h47_p2
|
||||
radiant_h47_p4
|
||||
radiant_h48_p1
|
||||
radiant_h49_p1
|
||||
radiant_h49_p2
|
||||
radiant_h49_p4
|
||||
radiant_h50_p1
|
||||
radiant_h50_p4
|
||||
radiant_h51_p1
|
||||
radiant_h51_p2
|
||||
radiant_h51_p4
|
||||
radiant_h52_p2
|
||||
radiant_h52_p4
|
||||
radiant_h53_p1
|
||||
radiant_h53_p2
|
||||
radiant_h54_p1
|
||||
radiant_h55_p4
|
||||
radiant_h57_p1
|
||||
radiant_h58_p1
|
||||
radiant_h58_p2
|
||||
radiant_h58_p4
|
||||
radiant_h59_p1
|
||||
radiant_h59_p2
|
||||
radiant_h5_p1
|
||||
radiant_h60_p1
|
||||
radiant_h60_p4
|
||||
radiant_h61_p1
|
||||
radiant_h61_p2
|
||||
radiant_h61_p4
|
||||
radiant_h62_p1
|
||||
radiant_h62_p2
|
||||
radiant_h62_p4
|
||||
radiant_h63_p1
|
||||
radiant_h64_p1
|
||||
radiant_h64_p2
|
||||
radiant_h64_p4
|
||||
radiant_h65_p1
|
||||
radiant_h65_p2
|
||||
radiant_h65_p4
|
||||
radiant_h66_p1
|
||||
radiant_h66_p2
|
||||
radiant_h66_p4
|
||||
radiant_h66_p5
|
||||
radiant_h67_p1
|
||||
radiant_h68_p1
|
||||
radiant_h68_p4
|
||||
radiant_h69_p1
|
||||
radiant_h69_p4
|
||||
radiant_h6_p1
|
||||
radiant_h70_p1
|
||||
radiant_h70_p4
|
||||
radiant_h71_p1
|
||||
radiant_h71_p2
|
||||
radiant_h71_p4
|
||||
radiant_h72_p1
|
||||
radiant_h72_p4
|
||||
radiant_h73_p1
|
||||
radiant_h73_p2
|
||||
radiant_h73_p4
|
||||
radiant_h74_p2
|
||||
radiant_h75_p1
|
||||
radiant_h75_p4
|
||||
radiant_h77_p4
|
||||
radiant_h78_p4
|
||||
radiant_h79_p1
|
||||
radiant_h79_p2
|
||||
radiant_h79_p4
|
||||
radiant_h7_p2
|
||||
radiant_h7_p4
|
||||
radiant_h80_p1
|
||||
radiant_h80_p2
|
||||
radiant_h82_p1
|
||||
radiant_h83_p1
|
||||
radiant_h85_p1
|
||||
radiant_h85_p4
|
||||
radiant_h86_p4
|
||||
radiant_h87_p1
|
||||
radiant_h87_p2
|
||||
radiant_h87_p4
|
||||
radiant_h88_p1
|
||||
radiant_h88_p2
|
||||
radiant_h88_p4
|
||||
radiant_h89_p1
|
||||
radiant_h89_p4
|
||||
radiant_h8_p1
|
||||
radiant_h90_p1
|
||||
radiant_h90_p2
|
||||
radiant_h90_p4
|
||||
radiant_h94_p1
|
||||
radiant_h95_p1
|
||||
radiant_h96_p2
|
||||
radiant_h96_p4
|
||||
radiant_h97_p4
|
||||
radiant_h98_p1
|
||||
radiant_h98_p2
|
||||
radiant_h98_p4
|
||||
radiant_h99_p1
|
||||
radiant_h99_p4
|
||||
radiant_h9_p1
|
||||
radiant_h9_p2
|
||||
|
4509
artifacts/feature_order_with_players.csv
Normal file
4509
artifacts/feature_order_with_players.csv
Normal file
File diff suppressed because it is too large
Load Diff
BIN
artifacts/model_bag_of_heroes.cbm
Normal file
BIN
artifacts/model_bag_of_heroes.cbm
Normal file
Binary file not shown.
BIN
artifacts/model_from_db_pro_v3.cbm
Normal file
BIN
artifacts/model_from_db_pro_v3.cbm
Normal file
Binary file not shown.
BIN
artifacts/model_stacking.pkl
Normal file
BIN
artifacts/model_stacking.pkl
Normal file
Binary file not shown.
BIN
artifacts/model_with_players.cbm
Normal file
BIN
artifacts/model_with_players.cbm
Normal file
Binary file not shown.
BIN
data/dataset_from_db.parquet
Normal file
BIN
data/dataset_from_db.parquet
Normal file
Binary file not shown.
BIN
data/dataset_with_players.parquet
Normal file
BIN
data/dataset_with_players.parquet
Normal file
Binary file not shown.
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: korobka_postgres
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: korobka_db
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
94
educationML/build_dataset_pro.py
Normal file
94
educationML/build_dataset_pro.py
Normal file
@@ -0,0 +1,94 @@
|
||||
import pandas as pd
|
||||
import psycopg2
|
||||
from psycopg2.extras import RealDictCursor
|
||||
|
||||
def get_db_connection():
|
||||
return psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="korobka_db",
|
||||
user="postgres",
|
||||
password="postgres"
|
||||
)
|
||||
|
||||
print("Загрузка данных из БД...")
|
||||
|
||||
conn = get_db_connection()
|
||||
|
||||
# Загружаем матчи
|
||||
matches_df = pd.read_sql_query("""
|
||||
SELECT id as match_id, radiant_team_id, dire_team_id, radiant_win
|
||||
FROM matches
|
||||
WHERE "source" = 'pro'
|
||||
ORDER BY id
|
||||
""", conn)
|
||||
|
||||
print(f"Загружено {len(matches_df)} матчей")
|
||||
|
||||
# Загружаем детали героев
|
||||
details_df = pd.read_sql_query("""
|
||||
SELECT match_id, hero_id, team, players_id, pos
|
||||
FROM details_match
|
||||
WHERE "source" = 'pro'
|
||||
ORDER BY match_id
|
||||
""", conn)
|
||||
|
||||
print(f"Загружено {len(details_df)} записей героев")
|
||||
|
||||
conn.close()
|
||||
|
||||
# Формируем слоты героев для каждого матча
|
||||
def slots_from_picks(group):
|
||||
# --- Radiant (team = 0) ---
|
||||
r_heroes = group[group['team'] == 0]['hero_id'].tolist()[:5]
|
||||
r_players = group[group['team'] == 0]['players_id'].tolist()[:5]
|
||||
r_pos = group[group['team'] == 0]['pos'].tolist()[:5]
|
||||
|
||||
# --- Dire (team = 1) ---
|
||||
d_heroes = group[group['team'] == 1]['hero_id'].tolist()[:5]
|
||||
d_players = group[group['team'] == 1]['players_id'].tolist()[:5]
|
||||
d_pos = group[group['team'] == 1]['pos'].tolist()[:5]
|
||||
|
||||
row = {}
|
||||
# --- Добавляем 5 слотов для каждой стороны ---
|
||||
for i in range(5):
|
||||
# Герои Radiant / Dire
|
||||
row[f"r_h{i+1}"] = r_heroes[i] if i < len(r_heroes) else -1
|
||||
row[f"d_h{i+1}"] = d_heroes[i] if i < len(d_heroes) else -1
|
||||
|
||||
# Позиции героев
|
||||
row[f"rp_h{i+1}"] = r_pos[i] if i < len(r_pos) else -1
|
||||
row[f"dp_h{i+1}"] = d_pos[i] if i < len(d_pos) else -1
|
||||
|
||||
# Игроки Radiant / Dire
|
||||
row[f"r_p{i+1}"] = r_players[i] if i < len(r_players) else -1
|
||||
row[f"d_p{i+1}"] = d_players[i] if i < len(d_players) else -1
|
||||
|
||||
# Определяем, кто пикал первым (команда 0 = radiant)
|
||||
fp_team = group.iloc[0]['team'] if len(group) > 0 else 0
|
||||
row["is_first_pick_radiant"] = 1 if fp_team == 0 else 0
|
||||
|
||||
return pd.Series(row)
|
||||
|
||||
slots_df = details_df.groupby("match_id").apply(slots_from_picks).reset_index()
|
||||
|
||||
# Объединяем с информацией о матчах
|
||||
dataset = matches_df.merge(slots_df, on="match_id", how="inner")
|
||||
|
||||
# Добавляем целевую переменную
|
||||
dataset['y'] = dataset['radiant_win'].astype(int)
|
||||
|
||||
# Выбираем нужные колонки в правильном порядке
|
||||
final_df = dataset[['match_id', 'is_first_pick_radiant',
|
||||
'r_h1', 'r_h2', 'r_h3', 'r_h4', 'r_h5',
|
||||
'd_h1', 'd_h2', 'd_h3', 'd_h4', 'd_h5',
|
||||
'r_p1', 'r_p2', 'r_p3', 'r_p4', 'r_p5',
|
||||
'd_p1', 'd_p2', 'd_p3', 'd_p4', 'd_p5',
|
||||
'rp_h1', 'rp_h2', 'rp_h3', 'rp_h4', 'rp_h5',
|
||||
'dp_h1', 'dp_h2', 'dp_h3', 'dp_h4', 'dp_h5',
|
||||
'y']]
|
||||
|
||||
# Сохраняем
|
||||
final_df.to_parquet("data/dataset_from_db.parquet", index=False)
|
||||
print(f"Сохранено {len(final_df)} записей в data/dataset_from_db.parquet")
|
||||
print(f"Radiant wins: {final_df['y'].sum()}, Dire wins: {len(final_df) - final_df['y'].sum()}")
|
||||
139
educationML/build_dataset_with_players.py
Normal file
139
educationML/build_dataset_with_players.py
Normal file
@@ -0,0 +1,139 @@
|
||||
import psycopg2
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
print("Подключение к базе данных...")
|
||||
conn = psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="korobka_db",
|
||||
user="postgres",
|
||||
password="postgres"
|
||||
)
|
||||
|
||||
print("Загрузка матчей с известными игроками...")
|
||||
|
||||
# Получаем все матчи где есть хотя бы один известный игрок
|
||||
query = """
|
||||
SELECT
|
||||
m.id as match_id,
|
||||
m.radiant_win,
|
||||
m.leagueid
|
||||
FROM matches m
|
||||
WHERE EXISTS (
|
||||
SELECT 1
|
||||
FROM details_match dm
|
||||
WHERE dm.match_id = m.id
|
||||
AND dm.players_id IS NOT NULL
|
||||
AND dm.players_id != 0
|
||||
)
|
||||
ORDER BY m.id
|
||||
"""
|
||||
|
||||
matches_df = pd.read_sql(query, conn)
|
||||
print(f"Найдено матчей: {len(matches_df)}")
|
||||
|
||||
# Получаем детали всех этих матчей
|
||||
query_details = """
|
||||
SELECT
|
||||
dm.match_id,
|
||||
dm.hero_id,
|
||||
dm.team,
|
||||
dm.players_id,
|
||||
dm.pos,
|
||||
dm."order"
|
||||
FROM details_match dm
|
||||
WHERE dm.match_id IN (
|
||||
SELECT DISTINCT m.id
|
||||
FROM matches m
|
||||
WHERE EXISTS (
|
||||
SELECT 1
|
||||
FROM details_match dm2
|
||||
WHERE dm2.match_id = m.id
|
||||
AND dm2.players_id IS NOT NULL
|
||||
AND dm2.players_id != 0
|
||||
)
|
||||
)
|
||||
ORDER BY dm.match_id, dm."order"
|
||||
"""
|
||||
|
||||
details_df = pd.read_sql(query_details, conn)
|
||||
conn.close()
|
||||
|
||||
print(f"Загружено {len(details_df)} записей деталей")
|
||||
|
||||
# Преобразуем в wide-format
|
||||
print("\nПреобразование в wide-format...")
|
||||
|
||||
rows = []
|
||||
|
||||
for match_id, group in details_df.groupby('match_id'):
|
||||
match_info = matches_df[matches_df['match_id'] == match_id].iloc[0]
|
||||
|
||||
row = {
|
||||
'match_id': match_id,
|
||||
'y': int(match_info['radiant_win']),
|
||||
'leagueid': int(match_info['leagueid'])
|
||||
}
|
||||
|
||||
# Radiant (team=0) и Dire (team=1)
|
||||
radiant_picks = group[group['team'] == 0].sort_values('order')
|
||||
dire_picks = group[group['team'] == 1].sort_values('order')
|
||||
|
||||
# Заполняем героев и игроков для Radiant (до 5)
|
||||
for i, (idx, pick) in enumerate(radiant_picks.iterrows(), 1):
|
||||
if i > 5:
|
||||
break
|
||||
row[f'r_h{i}'] = int(pick['hero_id'])
|
||||
row[f'r_p{i}'] = int(pick['players_id']) if pd.notna(pick['players_id']) and pick['players_id'] != 0 else -1
|
||||
row[f'rp_h{i}'] = int(pick['pos']) if pd.notna(pick['pos']) else -1
|
||||
|
||||
# Заполняем пропуски для Radiant
|
||||
for i in range(len(radiant_picks) + 1, 6):
|
||||
row[f'r_h{i}'] = -1
|
||||
row[f'r_p{i}'] = -1
|
||||
row[f'rp_h{i}'] = -1
|
||||
|
||||
# Заполняем героев и игроков для Dire (до 5)
|
||||
for i, (idx, pick) in enumerate(dire_picks.iterrows(), 1):
|
||||
if i > 5:
|
||||
break
|
||||
row[f'd_h{i}'] = int(pick['hero_id'])
|
||||
row[f'd_p{i}'] = int(pick['players_id']) if pd.notna(pick['players_id']) and pick['players_id'] != 0 else -1
|
||||
row[f'dp_h{i}'] = int(pick['pos']) if pd.notna(pick['pos']) else -1
|
||||
|
||||
# Заполняем пропуски для Dire
|
||||
for i in range(len(dire_picks) + 1, 6):
|
||||
row[f'd_h{i}'] = -1
|
||||
row[f'd_p{i}'] = -1
|
||||
row[f'dp_h{i}'] = -1
|
||||
|
||||
rows.append(row)
|
||||
|
||||
df = pd.DataFrame(rows)
|
||||
|
||||
print(f"Создано {len(df)} записей в wide-format")
|
||||
print(f"Radiant wins: {df['y'].sum()} ({df['y'].mean()*100:.1f}%)")
|
||||
print(f"Dire wins: {len(df) - df['y'].sum()} ({(1-df['y'].mean())*100:.1f}%)")
|
||||
|
||||
# Статистика по игрокам
|
||||
player_cols = [f'r_p{i}' for i in range(1, 6)] + [f'd_p{i}' for i in range(1, 6)]
|
||||
all_players = []
|
||||
for col in player_cols:
|
||||
all_players.extend(df[col][df[col] > 0].tolist())
|
||||
|
||||
unique_players = len(set(all_players))
|
||||
print(f"\nУникальных игроков в датасете: {unique_players}")
|
||||
print(f"Всего записей игроков (не -1): {len(all_players)}")
|
||||
|
||||
# Статистика по турнирам
|
||||
print(f"\nУникальных турниров (leagueid): {df['leagueid'].nunique()}")
|
||||
|
||||
# Сохранение
|
||||
output_path = "data/dataset_with_players.parquet"
|
||||
df.to_parquet(output_path, index=False)
|
||||
print(f"\n✓ Датасет сохранён: {output_path}")
|
||||
|
||||
# Пример первых записей
|
||||
print("\nПример данных (первые 3 матча):")
|
||||
print(df.head(3).to_string())
|
||||
127
educationML/train_model_bag_of_heroes.py
Normal file
127
educationML/train_model_bag_of_heroes.py
Normal file
@@ -0,0 +1,127 @@
|
||||
import os
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from catboost import CatBoostClassifier, Pool
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.metrics import roc_auc_score
|
||||
|
||||
print("Загрузка датасета...")
|
||||
|
||||
df = pd.read_parquet("data/dataset_from_db.parquet")
|
||||
|
||||
print(f"Всего записей: {len(df)}")
|
||||
print(f"Radiant wins: {df['y'].sum()} ({df['y'].mean()*100:.1f}%)")
|
||||
print(f"Dire wins: {len(df) - df['y'].sum()} ({(1-df['y'].mean())*100:.1f}%)")
|
||||
|
||||
# --- Bag-of-Heroes подход ---
|
||||
# Создаем бинарные признаки для каждого героя в каждой команде
|
||||
|
||||
# Получаем все уникальные ID героев из данных
|
||||
hero_cols_r = [f"r_h{i}" for i in range(1, 6)]
|
||||
hero_cols_d = [f"d_h{i}" for i in range(1, 6)]
|
||||
|
||||
all_hero_ids = set()
|
||||
for col in hero_cols_r + hero_cols_d:
|
||||
all_hero_ids.update(df[col].dropna().unique())
|
||||
|
||||
all_hero_ids = sorted([int(h) for h in all_hero_ids if h >= 0])
|
||||
print(f"\nВсего уникальных героев: {len(all_hero_ids)}")
|
||||
|
||||
# Создаем новый датафрейм с bag-of-heroes признаками
|
||||
X = pd.DataFrame()
|
||||
|
||||
# Добавляем is_first_pick_radiant
|
||||
X["is_first_pick_radiant"] = df["is_first_pick_radiant"].astype(int)
|
||||
|
||||
# Для каждого героя создаем 2 признака: radiant_hero_{id} и dire_hero_{id}
|
||||
for hero_id in all_hero_ids:
|
||||
# Radiant team
|
||||
X[f"radiant_hero_{hero_id}"] = 0
|
||||
for col in hero_cols_r:
|
||||
X.loc[df[col] == hero_id, f"radiant_hero_{hero_id}"] = 1
|
||||
|
||||
# Dire team
|
||||
X[f"dire_hero_{hero_id}"] = 0
|
||||
for col in hero_cols_d:
|
||||
X.loc[df[col] == hero_id, f"dire_hero_{hero_id}"] = 1
|
||||
|
||||
print(f"Количество признаков: {len(X.columns)}")
|
||||
print(f" - is_first_pick_radiant: 1")
|
||||
print(f" - radiant_hero_*: {len(all_hero_ids)}")
|
||||
print(f" - dire_hero_*: {len(all_hero_ids)}")
|
||||
|
||||
# Целевая переменная
|
||||
y = df["y"].astype(int).copy()
|
||||
|
||||
# Разбиение
|
||||
X_train, X_test, y_train, y_test = train_test_split(
|
||||
X, y,
|
||||
test_size=0.2,
|
||||
random_state=42,
|
||||
stratify=y
|
||||
)
|
||||
|
||||
print(f"\nTrain: {len(X_train)} записей")
|
||||
print(f"Test: {len(X_test)} записей")
|
||||
|
||||
# В bag-of-heroes все признаки числовые (0 или 1), категориальных нет
|
||||
train_pool = Pool(X_train, y_train)
|
||||
test_pool = Pool(X_test, y_test)
|
||||
|
||||
# Модель
|
||||
model = CatBoostClassifier(
|
||||
iterations=2500,
|
||||
learning_rate=0.03,
|
||||
depth=7,
|
||||
l2_leaf_reg=2,
|
||||
bootstrap_type="Bayesian",
|
||||
bagging_temperature=1.0,
|
||||
loss_function="Logloss",
|
||||
eval_metric="AUC",
|
||||
random_seed=42,
|
||||
verbose=100,
|
||||
od_type="Iter",
|
||||
od_wait=200
|
||||
)
|
||||
|
||||
print("\nНачало обучения...")
|
||||
model.fit(train_pool, eval_set=test_pool, use_best_model=True)
|
||||
|
||||
# --- Оценка качества ---
|
||||
best_scores = model.get_best_score()
|
||||
train_auc_cb = best_scores.get("learn", {}).get("AUC", np.nan)
|
||||
test_auc_cb = best_scores.get("validation", {}).get("AUC", np.nan)
|
||||
|
||||
y_train_proba = model.predict_proba(train_pool)[:, 1]
|
||||
y_test_proba = model.predict_proba(test_pool)[:, 1]
|
||||
train_auc = roc_auc_score(y_train, y_train_proba)
|
||||
test_auc = roc_auc_score(y_test, y_test_proba)
|
||||
|
||||
print(f"\nCatBoost best AUC (learn/valid): {train_auc_cb:.4f} / {test_auc_cb:.4f}")
|
||||
print(f"Recomputed AUC (train/test): {train_auc:.4f} / {test_auc:.4f}")
|
||||
|
||||
# --- Сохранение ---
|
||||
os.makedirs("artifacts", exist_ok=True)
|
||||
model_path = "artifacts/model_bag_of_heroes.cbm"
|
||||
model.save_model(model_path)
|
||||
print(f"\nМодель сохранена: {model_path}")
|
||||
|
||||
# Порядок фичей
|
||||
feature_cols = list(X.columns)
|
||||
pd.DataFrame(feature_cols, columns=["feature"]).to_csv(
|
||||
"artifacts/feature_order_bag_of_heroes.csv", index=False
|
||||
)
|
||||
print("Порядок фичей сохранен в artifacts/feature_order_bag_of_heroes.csv")
|
||||
|
||||
# Важность признаков (топ-30)
|
||||
importance = model.get_feature_importance(train_pool)
|
||||
importance_df = (
|
||||
pd.DataFrame({"feature": X_train.columns, "importance": importance})
|
||||
.sort_values("importance", ascending=False)
|
||||
.reset_index(drop=True)
|
||||
)
|
||||
|
||||
print("\nВажность признаков (top 30):")
|
||||
print(importance_df.head(30).to_string(index=False))
|
||||
|
||||
importance_df.to_csv("artifacts/feature_importance_bag_of_heroes.csv", index=False)
|
||||
131
educationML/train_model_pro.py
Normal file
131
educationML/train_model_pro.py
Normal file
@@ -0,0 +1,131 @@
|
||||
import os
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from catboost import CatBoostClassifier, Pool
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.metrics import roc_auc_score
|
||||
|
||||
print("Загрузка датасета...")
|
||||
|
||||
df = pd.read_parquet("data/dataset_from_db.parquet")
|
||||
|
||||
print(f"Всего записей (матчей): {len(df)}")
|
||||
print(f"Radiant wins: {df['y'].sum()} ({df['y'].mean()*100:.1f}%)")
|
||||
print(f"Dire wins: {len(df) - df['y'].sum()} ({(1-df['y'].mean())*100:.1f}%)")
|
||||
|
||||
# --- Создаём признаки на уровне матча ---
|
||||
print("\nСоздание признаков...")
|
||||
|
||||
hero_cols_r = [f"r_h{i}" for i in range(1, 6)]
|
||||
hero_cols_d = [f"d_h{i}" for i in range(1, 6)]
|
||||
pos_cols_r = [f"rp_h{i}" for i in range(1, 6)]
|
||||
pos_cols_d = [f"dp_h{i}" for i in range(1, 6)]
|
||||
|
||||
# Создаём признаки: каждый герой на каждой позиции для каждой команды
|
||||
# Формат: radiant_{hero_id}_pos_{position}, dire_{hero_id}_pos_{position}
|
||||
|
||||
rows = []
|
||||
|
||||
for idx, row in df.iterrows():
|
||||
features = {}
|
||||
|
||||
# Radiant heroes с позициями
|
||||
for i in range(5):
|
||||
hero_id = int(row[hero_cols_r[i]])
|
||||
position = int(row[pos_cols_r[i]])
|
||||
|
||||
if hero_id >= 0 and position >= 0:
|
||||
features[f"radiant_h{hero_id}_p{position}"] = 1
|
||||
|
||||
# Dire heroes с позициями
|
||||
for i in range(5):
|
||||
hero_id = int(row[hero_cols_d[i]])
|
||||
position = int(row[pos_cols_d[i]])
|
||||
|
||||
if hero_id >= 0 and position >= 0:
|
||||
features[f"dire_h{hero_id}_p{position}"] = 1
|
||||
|
||||
features['y'] = int(row['y'])
|
||||
rows.append(features)
|
||||
|
||||
df_features = pd.DataFrame(rows).fillna(0)
|
||||
|
||||
print(f"Создано признаков: {len(df_features.columns) - 1}")
|
||||
|
||||
# Целевая
|
||||
y = df_features['y'].astype(int)
|
||||
X = df_features.drop('y', axis=1)
|
||||
|
||||
# Разбиение
|
||||
X_train, X_test, y_train, y_test = train_test_split(
|
||||
X, y,
|
||||
test_size=0.2,
|
||||
random_state=42,
|
||||
stratify=y
|
||||
)
|
||||
|
||||
print(f"\nTrain: {len(X_train)} матчей")
|
||||
print(f"Test: {len(X_test)} матчей")
|
||||
|
||||
# Обучение
|
||||
train_pool = Pool(X_train, y_train)
|
||||
test_pool = Pool(X_test, y_test)
|
||||
|
||||
model = CatBoostClassifier(
|
||||
iterations=1000,
|
||||
learning_rate=0.05,
|
||||
depth=5,
|
||||
l2_leaf_reg=3,
|
||||
min_data_in_leaf=10,
|
||||
bootstrap_type="Bayesian",
|
||||
bagging_temperature=0.5,
|
||||
loss_function="Logloss",
|
||||
eval_metric="AUC",
|
||||
random_seed=42,
|
||||
verbose=50,
|
||||
od_type="Iter",
|
||||
od_wait=100,
|
||||
use_best_model=True
|
||||
)
|
||||
|
||||
print("\nНачало обучения...")
|
||||
model.fit(train_pool, eval_set=test_pool)
|
||||
|
||||
# Оценка
|
||||
best_scores = model.get_best_score()
|
||||
train_auc_cb = best_scores.get("learn", {}).get("AUC", np.nan)
|
||||
test_auc_cb = best_scores.get("validation", {}).get("AUC", np.nan)
|
||||
|
||||
y_train_proba = model.predict_proba(train_pool)[:, 1]
|
||||
y_test_proba = model.predict_proba(test_pool)[:, 1]
|
||||
train_auc = roc_auc_score(y_train, y_train_proba)
|
||||
test_auc = roc_auc_score(y_test, y_test_proba)
|
||||
|
||||
print(f"\nCatBoost best AUC (learn/valid): {train_auc_cb:.4f} / {test_auc_cb:.4f}")
|
||||
print(f"Recomputed AUC (train/test): {train_auc:.4f} / {test_auc:.4f}")
|
||||
|
||||
# Сохранение
|
||||
os.makedirs("artifacts", exist_ok=True)
|
||||
model_path = "artifacts/model_from_db_pro_v3.cbm"
|
||||
model.save_model(model_path)
|
||||
print(f"\nМодель сохранена: {model_path}")
|
||||
|
||||
# Важность (топ-30)
|
||||
importance = model.get_feature_importance(train_pool)
|
||||
importance_df = (
|
||||
pd.DataFrame({"feature": X_train.columns, "importance": importance})
|
||||
.sort_values("importance", ascending=False)
|
||||
.reset_index(drop=True)
|
||||
)
|
||||
|
||||
print("\nВажность признаков (top 30):")
|
||||
print(importance_df.head(30).to_string(index=False))
|
||||
|
||||
importance_df.to_csv("artifacts/feature_importance_db.csv", index=False)
|
||||
|
||||
# Сохраняем список всех возможных признаков для инференса
|
||||
all_features = sorted(X.columns.tolist())
|
||||
pd.DataFrame(all_features, columns=["feature"]).to_csv(
|
||||
"artifacts/feature_order_db.csv", index=False
|
||||
)
|
||||
print(f"Порядок фичей сохранен в artifacts/feature_order_db.csv ({len(all_features)} признаков)")
|
||||
161
educationML/train_model_pro_long_old.py
Normal file
161
educationML/train_model_pro_long_old.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import os
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from catboost import CatBoostClassifier, Pool
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.metrics import roc_auc_score
|
||||
|
||||
print("Загрузка датасета...")
|
||||
|
||||
df = pd.read_parquet("data/dataset_from_db.parquet")
|
||||
|
||||
print(f"Всего записей (матчей): {len(df)}")
|
||||
print(f"Radiant wins: {df['y'].sum()} ({df['y'].mean()*100:.1f}%)")
|
||||
print(f"Dire wins: {len(df) - df['y'].sum()} ({(1-df['y'].mean())*100:.1f}%)")
|
||||
|
||||
# --- Преобразование в long-format ---
|
||||
print("\nПреобразование в long-format...")
|
||||
|
||||
hero_cols_r = [f"r_h{i}" for i in range(1, 6)]
|
||||
hero_cols_d = [f"d_h{i}" for i in range(1, 6)]
|
||||
pos_cols_r = [f"rp_h{i}" for i in range(1, 6)]
|
||||
pos_cols_d = [f"dp_h{i}" for i in range(1, 6)]
|
||||
|
||||
rows = []
|
||||
|
||||
for idx, row in df.iterrows():
|
||||
match_id = idx
|
||||
is_first_pick_radiant = int(row.get("is_first_pick_radiant", 0))
|
||||
radiant_win = int(row["y"])
|
||||
|
||||
# Radiant team (5 героев)
|
||||
for i in range(5):
|
||||
hero_id = int(row[hero_cols_r[i]])
|
||||
position = int(row[pos_cols_r[i]])
|
||||
|
||||
if hero_id >= 0: # Только валидные герои
|
||||
rows.append({
|
||||
"match_id": match_id,
|
||||
"is_first_pick_radiant": is_first_pick_radiant,
|
||||
"team": 0, # Radiant
|
||||
"hero_id": hero_id,
|
||||
"position": position,
|
||||
"radiant_win": radiant_win
|
||||
})
|
||||
|
||||
# Dire team (5 героев)
|
||||
for i in range(5):
|
||||
hero_id = int(row[hero_cols_d[i]])
|
||||
position = int(row[pos_cols_d[i]])
|
||||
|
||||
if hero_id >= 0: # Только валидные герои
|
||||
rows.append({
|
||||
"match_id": match_id,
|
||||
"is_first_pick_radiant": is_first_pick_radiant,
|
||||
"team": 1, # Dire
|
||||
"hero_id": hero_id,
|
||||
"position": position,
|
||||
"radiant_win": radiant_win
|
||||
})
|
||||
|
||||
df_long = pd.DataFrame(rows)
|
||||
|
||||
print(f"\nLong-format датасет создан:")
|
||||
print(f"Всего записей (пиков): {len(df_long)}")
|
||||
print(f"Уникальных матчей: {df_long['match_id'].nunique()}")
|
||||
print(f"Средних пиков на матч: {len(df_long) / df_long['match_id'].nunique():.1f}")
|
||||
|
||||
# Целевая переменная
|
||||
y = df_long["radiant_win"].astype(int)
|
||||
|
||||
# Признаки
|
||||
feature_cols = ["team", "hero_id", "position"]
|
||||
X = df_long[feature_cols].copy()
|
||||
|
||||
# Убедимся в правильных типах
|
||||
X["team"] = X["team"].astype(int)
|
||||
X["hero_id"] = X["hero_id"].astype(int)
|
||||
X["position"] = X["position"].astype(int)
|
||||
|
||||
# Разбиение (важно: разбиваем по match_id, чтобы пики одного матча были в одном сплите)
|
||||
unique_matches = df_long["match_id"].unique()
|
||||
train_matches, test_matches = train_test_split(
|
||||
unique_matches,
|
||||
test_size=0.1,
|
||||
random_state=42
|
||||
)
|
||||
|
||||
train_mask = df_long["match_id"].isin(train_matches)
|
||||
test_mask = df_long["match_id"].isin(test_matches)
|
||||
|
||||
X_train = X[train_mask].reset_index(drop=True)
|
||||
y_train = y[train_mask].reset_index(drop=True)
|
||||
X_test = X[test_mask].reset_index(drop=True)
|
||||
y_test = y[test_mask].reset_index(drop=True)
|
||||
|
||||
print(f"\nTrain: {len(X_train)} пиков ({len(train_matches)} матчей)")
|
||||
print(f"Test: {len(X_test)} пиков ({len(test_matches)} матчей)")
|
||||
|
||||
# Категориальные признаки
|
||||
cat_features = ["team", "hero_id", "position"]
|
||||
train_pool = Pool(X_train, y_train, cat_features=cat_features)
|
||||
test_pool = Pool(X_test, y_test, cat_features=cat_features)
|
||||
|
||||
# Модель с более агрессивной регуляризацией для малого датасета
|
||||
model = CatBoostClassifier(
|
||||
iterations=1000,
|
||||
learning_rate=0.1, # Увеличили learning rate
|
||||
depth=4, # Уменьшили глубину
|
||||
l2_leaf_reg=5, # Увеличили регуляризацию
|
||||
min_data_in_leaf=20, # Добавили минимум данных в листе
|
||||
bootstrap_type="Bayesian",
|
||||
bagging_temperature=0.5, # Уменьшили для меньшего разброса
|
||||
loss_function="Logloss",
|
||||
eval_metric="AUC",
|
||||
random_seed=42,
|
||||
verbose=50,
|
||||
od_type="Iter",
|
||||
od_wait=50, # Уменьшили patience
|
||||
use_best_model=True
|
||||
)
|
||||
|
||||
print("\nНачало обучения...")
|
||||
model.fit(train_pool, eval_set=test_pool, use_best_model=True)
|
||||
|
||||
# --- Оценка качества ---
|
||||
best_scores = model.get_best_score()
|
||||
train_auc_cb = best_scores.get("learn", {}).get("AUC", np.nan)
|
||||
test_auc_cb = best_scores.get("validation", {}).get("AUC", np.nan)
|
||||
|
||||
y_train_proba = model.predict_proba(train_pool)[:, 1]
|
||||
y_test_proba = model.predict_proba(test_pool)[:, 1]
|
||||
train_auc = roc_auc_score(y_train, y_train_proba)
|
||||
test_auc = roc_auc_score(y_test, y_test_proba)
|
||||
|
||||
print(f"\nCatBoost best AUC (learn/valid): {train_auc_cb:.4f} / {test_auc_cb:.4f}")
|
||||
print(f"Recomputed AUC (train/test): {train_auc:.4f} / {test_auc:.4f}")
|
||||
|
||||
# --- Сохранение ---
|
||||
os.makedirs("artifacts", exist_ok=True)
|
||||
model_path = "artifacts/model_from_db_pro_v3.cbm"
|
||||
model.save_model(model_path)
|
||||
print(f"\nМодель сохранена: {model_path}")
|
||||
|
||||
# Порядок фичей
|
||||
pd.DataFrame(feature_cols, columns=["feature"]).to_csv(
|
||||
"artifacts/feature_order_db.csv", index=False
|
||||
)
|
||||
print("Порядок фичей сохранен в artifacts/feature_order_db.csv")
|
||||
|
||||
# Важность признаков
|
||||
importance = model.get_feature_importance(train_pool)
|
||||
importance_df = (
|
||||
pd.DataFrame({"feature": X_train.columns, "importance": importance})
|
||||
.sort_values("importance", ascending=False)
|
||||
.reset_index(drop=True)
|
||||
)
|
||||
|
||||
print("\nВажность признаков:")
|
||||
print(importance_df.to_string(index=False))
|
||||
|
||||
importance_df.to_csv("artifacts/feature_importance_db.csv", index=False)
|
||||
116
educationML/train_model_pro_old.py
Normal file
116
educationML/train_model_pro_old.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import os
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from catboost import CatBoostClassifier, Pool
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.metrics import roc_auc_score
|
||||
|
||||
print("Загрузка датасета...")
|
||||
|
||||
df = pd.read_parquet("data/dataset_from_db.parquet")
|
||||
|
||||
print(f"Всего записей: {len(df)}")
|
||||
print(f"Radiant wins: {df['y'].sum()} ({df['y'].mean()*100:.1f}%)")
|
||||
print(f"Dire wins: {len(df) - df['y'].sum()} ({(1-df['y'].mean())*100:.1f}%)")
|
||||
|
||||
# --- Фичи под новый формат датасета ---
|
||||
hero_cols_r = [f"r_h{i}" for i in range(1, 6)]
|
||||
hero_cols_d = [f"d_h{i}" for i in range(1, 5+1)]
|
||||
# player_cols_r = [f"r_p{i}" for i in range(1, 6)]
|
||||
# player_cols_d = [f"d_p{i}" for i in range(1, 6)]
|
||||
pos_cols_r = [f"rp_h{i}" for i in range(1, 6)]
|
||||
pos_cols_d = [f"dp_h{i}" for i in range(1, 6)]
|
||||
|
||||
feature_cols = (
|
||||
["is_first_pick_radiant"]
|
||||
+ hero_cols_r + hero_cols_d
|
||||
# + player_cols_r + player_cols_d # Убрали игроков - мало данных
|
||||
+ pos_cols_r + pos_cols_d
|
||||
)
|
||||
|
||||
# Целевая
|
||||
target_col = "y"
|
||||
|
||||
# Отделяем признаки/таргет
|
||||
X = df[feature_cols].copy()
|
||||
y = df[target_col].astype(int).copy()
|
||||
|
||||
# На всякий случай убедимся, что бинарный признак int
|
||||
X["is_first_pick_radiant"] = X["is_first_pick_radiant"].astype(int)
|
||||
|
||||
# Разбиение
|
||||
X_train, X_test, y_train, y_test = train_test_split(
|
||||
X, y,
|
||||
test_size=0.1,
|
||||
random_state=42,
|
||||
stratify=y
|
||||
)
|
||||
|
||||
print(f"\nTrain: {len(X_train)} записей")
|
||||
print(f"Test: {len(X_test)} записей")
|
||||
|
||||
# Категориальные признаки: герои и позиции (их ID — это категории)
|
||||
cat_features = hero_cols_r + hero_cols_d + pos_cols_r + pos_cols_d
|
||||
# CatBoost принимает либо индексы, либо имена колонок. Передаем имена.
|
||||
train_pool = Pool(X_train, y_train, cat_features=cat_features)
|
||||
test_pool = Pool(X_test, y_test, cat_features=cat_features)
|
||||
|
||||
# Модель
|
||||
model = CatBoostClassifier(
|
||||
iterations=2500,
|
||||
learning_rate=0.03,
|
||||
depth=7,
|
||||
l2_leaf_reg=2,
|
||||
bootstrap_type="Bayesian",
|
||||
bagging_temperature=1.0, # <- вместо subsample
|
||||
loss_function="Logloss",
|
||||
eval_metric="AUC",
|
||||
random_seed=42,
|
||||
verbose=100,
|
||||
od_type="Iter",
|
||||
od_wait=200
|
||||
)
|
||||
|
||||
print("\nНачало обучения...")
|
||||
model.fit(train_pool, eval_set=test_pool, use_best_model=True)
|
||||
|
||||
# --- Оценка качества ---
|
||||
# Лучшие метрики по мнению CatBoost
|
||||
best_scores = model.get_best_score()
|
||||
train_auc_cb = best_scores.get("learn", {}).get("AUC", np.nan)
|
||||
test_auc_cb = best_scores.get("validation", {}).get("AUC", np.nan)
|
||||
|
||||
# Перепроверим AUC напрямую
|
||||
y_train_proba = model.predict_proba(train_pool)[:, 1]
|
||||
y_test_proba = model.predict_proba(test_pool)[:, 1]
|
||||
train_auc = roc_auc_score(y_train, y_train_proba)
|
||||
test_auc = roc_auc_score(y_test, y_test_proba)
|
||||
|
||||
print(f"\nCatBoost best AUC (learn/valid): {train_auc_cb:.4f} / {test_auc_cb:.4f}")
|
||||
print(f"Recomputed AUC (train/test): {train_auc:.4f} / {test_auc:.4f}")
|
||||
|
||||
# --- Сохранение ---
|
||||
os.makedirs("artifacts", exist_ok=True)
|
||||
model_path = "artifacts/model_from_db_pro_v3.cbm"
|
||||
model.save_model(model_path)
|
||||
print(f"\nМодель сохранена: {model_path}")
|
||||
|
||||
# Порядок фичей
|
||||
pd.DataFrame(feature_cols, columns=["feature"]).to_csv(
|
||||
"artifacts/feature_order_db.csv", index=False
|
||||
)
|
||||
print("Порядок фичей сохранен в artifacts/feature_order_db.csv")
|
||||
|
||||
# Важность признаков
|
||||
importance = model.get_feature_importance(train_pool)
|
||||
importance_df = (
|
||||
pd.DataFrame({"feature": X_train.columns, "importance": importance})
|
||||
.sort_values("importance", ascending=False)
|
||||
.reset_index(drop=True)
|
||||
)
|
||||
|
||||
print("\nВажность признаков (top 25):")
|
||||
print(importance_df.head(25).to_string(index=False))
|
||||
|
||||
# При желании — сохранить важности целиком
|
||||
importance_df.to_csv("artifacts/feature_importance_db.csv", index=False)
|
||||
176
educationML/train_model_stacking.py
Normal file
176
educationML/train_model_stacking.py
Normal file
@@ -0,0 +1,176 @@
|
||||
import os
|
||||
import sys
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from catboost import CatBoostClassifier, Pool
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.metrics import roc_auc_score
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
import pickle
|
||||
|
||||
# Добавляем корневую директорию проекта в путь
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
|
||||
print("Загрузка датасета...")
|
||||
df = pd.read_parquet("data/dataset_from_db.parquet")
|
||||
|
||||
print(f"Всего записей: {len(df)}")
|
||||
print(f"Radiant wins: {df['y'].sum()} ({df['y'].mean()*100:.1f}%)")
|
||||
print(f"Dire wins: {len(df) - df['y'].sum()} ({(1-df['y'].mean())*100:.1f}%)")
|
||||
|
||||
# Целевая переменная
|
||||
y = df["y"].astype(int).copy()
|
||||
|
||||
# Разбиение на train/test
|
||||
_, X_test_indices, _, y_test = train_test_split(
|
||||
df.index, y,
|
||||
test_size=0.2,
|
||||
random_state=42,
|
||||
stratify=y
|
||||
)
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("Загрузка базовых моделей...")
|
||||
print("="*60)
|
||||
|
||||
# === Модель 1: Heroes + Positions ===
|
||||
from routes.predict import build_long_format_input, modelPro
|
||||
|
||||
# === Модель 2: Bag of Heroes ===
|
||||
from routes.predict_bag_of_heroes import build_bag_of_heroes_features, modelBagOfHeroes
|
||||
|
||||
# === Модель 3: With Players ===
|
||||
from routes.predict_with_players import build_player_features, modelWithPlayers
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("Генерация предсказаний базовых моделей...")
|
||||
print("="*60)
|
||||
|
||||
# Подготовим данные для всех моделей
|
||||
hero_cols_r = [f"r_h{i}" for i in range(1, 6)]
|
||||
hero_cols_d = [f"d_h{i}" for i in range(1, 6)]
|
||||
player_cols_r = [f"r_p{i}" for i in range(1, 6)]
|
||||
player_cols_d = [f"d_p{i}" for i in range(1, 6)]
|
||||
pos_cols_r = [f"rp_h{i}" for i in range(1, 6)]
|
||||
pos_cols_d = [f"dp_h{i}" for i in range(1, 6)]
|
||||
|
||||
predictions_list = []
|
||||
|
||||
for idx in df.index:
|
||||
row_data = df.loc[idx]
|
||||
|
||||
# Формируем payload для текущей записи
|
||||
payload = {
|
||||
"is_first_pick_radiant": int(row_data.get("is_first_pick_radiant", 0)),
|
||||
}
|
||||
|
||||
# Герои
|
||||
for col in hero_cols_r + hero_cols_d:
|
||||
payload[col] = int(row_data.get(col, -1))
|
||||
|
||||
# Игроки
|
||||
for col in player_cols_r + player_cols_d:
|
||||
payload[col] = int(row_data.get(col, -1))
|
||||
|
||||
# Позиции
|
||||
for col in pos_cols_r + pos_cols_d:
|
||||
payload[col] = int(row_data.get(col, -1))
|
||||
|
||||
# === Предсказание модели 1: Heroes + Positions ===
|
||||
X_with_pos = build_long_format_input(payload)
|
||||
pred1 = float(modelPro.predict_proba(X_with_pos)[0, 1])
|
||||
|
||||
# === Предсказание модели 2: Bag of Heroes ===
|
||||
X_bag = build_bag_of_heroes_features(payload)
|
||||
pred2 = float(modelBagOfHeroes.predict_proba(X_bag)[0, 1])
|
||||
|
||||
# === Предсказание модели 3: With Players ===
|
||||
X_players = build_player_features(payload)
|
||||
pred3 = float(modelWithPlayers.predict_proba(X_players)[0, 1])
|
||||
|
||||
predictions_list.append({
|
||||
"pred_with_positions": pred1,
|
||||
"pred_bag_of_heroes": pred2,
|
||||
"pred_with_players": pred3
|
||||
})
|
||||
|
||||
if (idx + 1) % 100 == 0:
|
||||
print(f"Обработано {idx + 1}/{len(df)} записей...")
|
||||
|
||||
# Создаём DataFrame с предсказаниями
|
||||
X_meta = pd.DataFrame(predictions_list)
|
||||
|
||||
print(f"\nСоздано {len(X_meta)} мета-признаков")
|
||||
print(f"Колонки: {list(X_meta.columns)}")
|
||||
|
||||
# Разбиение на train/test по тем же индексам
|
||||
X_meta_train = X_meta.loc[~X_meta.index.isin(X_test_indices)]
|
||||
X_meta_test = X_meta.loc[X_meta.index.isin(X_test_indices)]
|
||||
y_meta_train = y.loc[~y.index.isin(X_test_indices)]
|
||||
y_meta_test = y.loc[y.index.isin(X_test_indices)]
|
||||
|
||||
print(f"\nMeta Train: {len(X_meta_train)} записей")
|
||||
print(f"Meta Test: {len(X_meta_test)} записей")
|
||||
|
||||
# Обучение мета-модели
|
||||
print("\n" + "="*60)
|
||||
print("Обучение мета-модели (Логистическая регрессия)...")
|
||||
print("="*60)
|
||||
|
||||
# Используем логистическую регрессию вместо CatBoost для избежания переобучения
|
||||
meta_model = LogisticRegression(
|
||||
random_state=42,
|
||||
max_iter=1000,
|
||||
C=1.0 # Регуляризация
|
||||
)
|
||||
|
||||
meta_model.fit(X_meta_train, y_meta_train)
|
||||
|
||||
# Оценка качества
|
||||
y_train_proba = meta_model.predict_proba(X_meta_train)[:, 1]
|
||||
y_test_proba = meta_model.predict_proba(X_meta_test)[:, 1]
|
||||
train_auc = roc_auc_score(y_meta_train, y_train_proba)
|
||||
test_auc = roc_auc_score(y_meta_test, y_test_proba)
|
||||
|
||||
print(f"\nLogistic Regression AUC (train/test): {train_auc:.4f} / {test_auc:.4f}")
|
||||
|
||||
# Сохранение мета-модели
|
||||
os.makedirs("artifacts", exist_ok=True)
|
||||
model_path = "artifacts/model_stacking.pkl"
|
||||
with open(model_path, 'wb') as f:
|
||||
pickle.dump(meta_model, f)
|
||||
print(f"\nМета-модель сохранена: {model_path}")
|
||||
|
||||
# Важность признаков (коэффициенты логистической регрессии)
|
||||
coefficients = meta_model.coef_[0]
|
||||
intercept = meta_model.intercept_[0]
|
||||
|
||||
importance_df = pd.DataFrame({
|
||||
"feature": X_meta_train.columns,
|
||||
"coefficient": coefficients
|
||||
}).sort_values("coefficient", ascending=False).reset_index(drop=True)
|
||||
|
||||
print("\nКоэффициенты логистической регрессии:")
|
||||
print(f"Intercept: {intercept:.4f}")
|
||||
print(importance_df.to_string(index=False))
|
||||
|
||||
# Сохраняем в старом формате для совместимости
|
||||
importance_df_compat = pd.DataFrame({
|
||||
"feature": X_meta_train.columns,
|
||||
"importance": np.abs(coefficients) # Абсолютные значения коэффициентов
|
||||
})
|
||||
importance_df_compat.to_csv("artifacts/feature_importance_stacking.csv", index=False)
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("Сравнение моделей на тестовой выборке:")
|
||||
print("="*60)
|
||||
|
||||
# AUC базовых моделей
|
||||
auc1 = roc_auc_score(y_meta_test, X_meta_test["pred_with_positions"])
|
||||
auc2 = roc_auc_score(y_meta_test, X_meta_test["pred_bag_of_heroes"])
|
||||
auc3 = roc_auc_score(y_meta_test, X_meta_test["pred_with_players"])
|
||||
|
||||
print(f"Модель 1 (Heroes + Positions): AUC = {auc1:.4f}")
|
||||
print(f"Модель 2 (Bag of Heroes): AUC = {auc2:.4f}")
|
||||
print(f"Модель 3 (With Players): AUC = {auc3:.4f}")
|
||||
print(f"Мета-модель (Stacking): AUC = {test_auc:.4f}")
|
||||
156
educationML/train_model_with_players.py
Normal file
156
educationML/train_model_with_players.py
Normal file
@@ -0,0 +1,156 @@
|
||||
import os
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from catboost import CatBoostClassifier, Pool
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.metrics import roc_auc_score
|
||||
|
||||
print("Загрузка датасета...")
|
||||
|
||||
df = pd.read_parquet("data/dataset_with_players.parquet")
|
||||
|
||||
print(f"Всего записей (матчей): {len(df)}")
|
||||
print(f"Radiant wins: {df['y'].sum()} ({df['y'].mean()*100:.1f}%)")
|
||||
print(f"Dire wins: {len(df) - df['y'].sum()} ({(1-df['y'].mean())*100:.1f}%)")
|
||||
|
||||
# --- Создаём признаки на уровне матча ---
|
||||
print("\nСоздание признаков...")
|
||||
|
||||
hero_cols_r = [f"r_h{i}" for i in range(1, 6)]
|
||||
hero_cols_d = [f"d_h{i}" for i in range(1, 6)]
|
||||
player_cols_r = [f"r_p{i}" for i in range(1, 6)]
|
||||
player_cols_d = [f"d_p{i}" for i in range(1, 6)]
|
||||
pos_cols_r = [f"rp_h{i}" for i in range(1, 6)]
|
||||
pos_cols_d = [f"dp_h{i}" for i in range(1, 6)]
|
||||
|
||||
# Создаём признаки: player_hero_pos для каждой команды
|
||||
# Формат: radiant_p{player_id}_h{hero_id}_pos{position}, dire_p{player_id}_h{hero_id}_pos{position}
|
||||
|
||||
rows = []
|
||||
|
||||
for idx, row in df.iterrows():
|
||||
features = {}
|
||||
|
||||
# Radiant heroes с игроками и позициями
|
||||
for i in range(5):
|
||||
hero_id = int(row[hero_cols_r[i]])
|
||||
player_id = int(row[player_cols_r[i]])
|
||||
position = int(row[pos_cols_r[i]])
|
||||
|
||||
# Признак: игрок + герой + позиция
|
||||
if player_id > 0 and hero_id >= 0 and position >= 0:
|
||||
features[f"radiant_p{player_id}_h{hero_id}_pos{position}"] = 1
|
||||
|
||||
# Признак: только игрок + герой (если позиция неизвестна)
|
||||
if player_id > 0 and hero_id >= 0:
|
||||
features[f"radiant_p{player_id}_h{hero_id}"] = 1
|
||||
|
||||
# Признак: только игрок + позиция
|
||||
if player_id > 0 and position >= 0:
|
||||
features[f"radiant_p{player_id}_pos{position}"] = 1
|
||||
|
||||
# Dire heroes с игроками и позициями
|
||||
for i in range(5):
|
||||
hero_id = int(row[hero_cols_d[i]])
|
||||
player_id = int(row[player_cols_d[i]])
|
||||
position = int(row[pos_cols_d[i]])
|
||||
|
||||
# Признак: игрок + герой + позиция
|
||||
if player_id > 0 and hero_id >= 0 and position >= 0:
|
||||
features[f"dire_p{player_id}_h{hero_id}_pos{position}"] = 1
|
||||
|
||||
# Признак: только игрок + герой (если позиция неизвестна)
|
||||
if player_id > 0 and hero_id >= 0:
|
||||
features[f"dire_p{player_id}_h{hero_id}"] = 1
|
||||
|
||||
# Признак: только игрок + позиция
|
||||
if player_id > 0 and position >= 0:
|
||||
features[f"dire_p{player_id}_pos{position}"] = 1
|
||||
|
||||
features['y'] = int(row['y'])
|
||||
rows.append(features)
|
||||
|
||||
if (idx + 1) % 100 == 0:
|
||||
print(f"Обработано {idx + 1}/{len(df)} матчей...")
|
||||
|
||||
df_features = pd.DataFrame(rows).fillna(0)
|
||||
|
||||
print(f"\nСоздано признаков: {len(df_features.columns) - 1}")
|
||||
|
||||
# Целевая
|
||||
y = df_features['y'].astype(int)
|
||||
X = df_features.drop('y', axis=1)
|
||||
|
||||
# Разбиение
|
||||
X_train, X_test, y_train, y_test = train_test_split(
|
||||
X, y,
|
||||
test_size=0.2,
|
||||
random_state=42,
|
||||
stratify=y
|
||||
)
|
||||
|
||||
print(f"\nTrain: {len(X_train)} матчей")
|
||||
print(f"Test: {len(X_test)} матчей")
|
||||
|
||||
# Обучение
|
||||
train_pool = Pool(X_train, y_train)
|
||||
test_pool = Pool(X_test, y_test)
|
||||
|
||||
model = CatBoostClassifier(
|
||||
iterations=1000,
|
||||
learning_rate=0.05,
|
||||
depth=5,
|
||||
l2_leaf_reg=3,
|
||||
min_data_in_leaf=5,
|
||||
bootstrap_type="Bayesian",
|
||||
bagging_temperature=0.5,
|
||||
loss_function="Logloss",
|
||||
eval_metric="AUC",
|
||||
random_seed=42,
|
||||
verbose=50,
|
||||
od_type="Iter",
|
||||
od_wait=100,
|
||||
use_best_model=True
|
||||
)
|
||||
|
||||
print("\nНачало обучения...")
|
||||
model.fit(train_pool, eval_set=test_pool)
|
||||
|
||||
# Оценка
|
||||
best_scores = model.get_best_score()
|
||||
train_auc_cb = best_scores.get("learn", {}).get("AUC", np.nan)
|
||||
test_auc_cb = best_scores.get("validation", {}).get("AUC", np.nan)
|
||||
|
||||
y_train_proba = model.predict_proba(train_pool)[:, 1]
|
||||
y_test_proba = model.predict_proba(test_pool)[:, 1]
|
||||
train_auc = roc_auc_score(y_train, y_train_proba)
|
||||
test_auc = roc_auc_score(y_test, y_test_proba)
|
||||
|
||||
print(f"\nCatBoost best AUC (learn/valid): {train_auc_cb:.4f} / {test_auc_cb:.4f}")
|
||||
print(f"Recomputed AUC (train/test): {train_auc:.4f} / {test_auc:.4f}")
|
||||
|
||||
# Сохранение
|
||||
os.makedirs("artifacts", exist_ok=True)
|
||||
model_path = "artifacts/model_with_players.cbm"
|
||||
model.save_model(model_path)
|
||||
print(f"\nМодель сохранена: {model_path}")
|
||||
|
||||
# Важность (топ-30)
|
||||
importance = model.get_feature_importance(train_pool)
|
||||
importance_df = (
|
||||
pd.DataFrame({"feature": X_train.columns, "importance": importance})
|
||||
.sort_values("importance", ascending=False)
|
||||
.reset_index(drop=True)
|
||||
)
|
||||
|
||||
print("\nВажность признаков (top 30):")
|
||||
print(importance_df.head(30).to_string(index=False))
|
||||
|
||||
importance_df.to_csv("artifacts/feature_importance_with_players.csv", index=False)
|
||||
|
||||
# Сохраняем список всех возможных признаков для инференса
|
||||
all_features = sorted(X.columns.tolist())
|
||||
pd.DataFrame(all_features, columns=["feature"]).to_csv(
|
||||
"artifacts/feature_order_with_players.csv", index=False
|
||||
)
|
||||
print(f"\nПорядок фичей сохранен в artifacts/feature_order_with_players.csv ({len(all_features)} признаков)")
|
||||
0
routes/__init__.py
Normal file
0
routes/__init__.py
Normal file
24
routes/heroes.py
Normal file
24
routes/heroes.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from fastapi import APIRouter
|
||||
import psycopg2
|
||||
from psycopg2.extras import RealDictCursor
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def get_db_connection():
|
||||
return psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="korobka_db",
|
||||
user="postgres",
|
||||
password="postgres"
|
||||
)
|
||||
|
||||
@router.get("/heroes")
|
||||
def get_heroes():
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor(cursor_factory=RealDictCursor)
|
||||
cursor.execute("SELECT id, name FROM hero ORDER BY id")
|
||||
heroes = cursor.fetchall()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return heroes
|
||||
62
routes/match.py
Normal file
62
routes/match.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import List
|
||||
import psycopg2
|
||||
from psycopg2.extras import RealDictCursor
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def get_db_connection():
|
||||
return psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="korobka_db",
|
||||
user="postgres",
|
||||
password="postgres"
|
||||
)
|
||||
|
||||
class HeroDetail(BaseModel):
|
||||
hero_id: int
|
||||
team: int
|
||||
order: int
|
||||
|
||||
class MatchData(BaseModel):
|
||||
id: int
|
||||
start_time: int
|
||||
leagueid: int
|
||||
radiant_team_id: int
|
||||
dire_team_id: int
|
||||
radiant_win: bool
|
||||
heroes: List[HeroDetail]
|
||||
|
||||
@router.post("/match/pro/add")
|
||||
def add_pro_match(match: MatchData):
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
# Добавляем матч в pro_matches
|
||||
cursor.execute("""
|
||||
INSERT INTO pro_matches (id, start_time, leagueid, radiant_team_id, dire_team_id, radiant_win)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
ON CONFLICT (id) DO NOTHING
|
||||
""", (match.id, match.start_time, match.leagueid, match.radiant_team_id, match.dire_team_id, match.radiant_win))
|
||||
|
||||
# Добавляем детали героев в pro_details_match
|
||||
for hero in match.heroes:
|
||||
cursor.execute("""
|
||||
INSERT INTO pro_details_match (match_id, hero_id, team, "order")
|
||||
VALUES (%s, %s, %s, %s)
|
||||
""", (match.id, hero.hero_id, hero.team, hero.order))
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return {"status": "success", "message": f"Match {match.id} added successfully"}
|
||||
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
24
routes/players.py
Normal file
24
routes/players.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from fastapi import APIRouter
|
||||
import psycopg2
|
||||
from psycopg2.extras import RealDictCursor
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def get_db_connection():
|
||||
return psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="korobka_db",
|
||||
user="postgres",
|
||||
password="postgres"
|
||||
)
|
||||
|
||||
@router.get("/pro-players")
|
||||
def get_pro_players():
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor(cursor_factory=RealDictCursor)
|
||||
cursor.execute("SELECT id, name, team_id FROM pro_players ORDER BY id")
|
||||
players = cursor.fetchall()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return players
|
||||
199
routes/predict.py
Normal file
199
routes/predict.py
Normal file
@@ -0,0 +1,199 @@
|
||||
from fastapi import APIRouter, Request
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional, Dict, Any
|
||||
from catboost import CatBoostClassifier
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from routes.predict_bag_of_heroes import predict_bag_of_heroes
|
||||
from routes.predict_with_players import predict_with_players
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
# =========================
|
||||
# Загрузка модели
|
||||
# =========================
|
||||
modelPro = CatBoostClassifier()
|
||||
modelPro.load_model("artifacts/model_from_db_pro_v3.cbm")
|
||||
|
||||
# =========================
|
||||
# Загрузка порядка фич
|
||||
# =========================
|
||||
def load_feature_order(path: str) -> list[str]:
|
||||
fo = pd.read_csv(path)
|
||||
first_col = fo.columns[0]
|
||||
return fo[first_col].tolist()
|
||||
|
||||
FEATURE_ORDER_PRO: list[str] = load_feature_order("artifacts/feature_order_db.csv")
|
||||
|
||||
# =========================
|
||||
# Дефолты для недостающих фич
|
||||
# =========================
|
||||
DEFAULTS: Dict[str, Any] = {
|
||||
"is_first_pick_radiant": 0,
|
||||
# Radiant heroes
|
||||
"r_h1": -1, "r_h2": -1, "r_h3": -1, "r_h4": -1, "r_h5": -1,
|
||||
# Dire heroes
|
||||
"d_h1": -1, "d_h2": -1, "d_h3": -1, "d_h4": -1, "d_h5": -1,
|
||||
# # Radiant players
|
||||
"r_p1": -1, "r_p2": -1, "r_p3": -1, "r_p4": -1, "r_p5": -1,
|
||||
# # Dire players
|
||||
"d_p1": -1, "d_p2": -1, "d_p3": -1, "d_p4": -1, "d_p5": -1,
|
||||
# Radiant positions
|
||||
"rp_h1": -1, "rp_h2": -1, "rp_h3": -1, "rp_h4": -1, "rp_h5": -1,
|
||||
# Dire positions
|
||||
"dp_h1": -1, "dp_h2": -1, "dp_h3": -1, "dp_h4": -1, "dp_h5": -1,
|
||||
}
|
||||
|
||||
# =========================
|
||||
# Входная схема
|
||||
# =========================
|
||||
class DraftPayload(BaseModel):
|
||||
# флаг первого пика (0 — Dire first pick/неизвестно, 1 — Radiant first pick)
|
||||
is_first_pick_radiant: Optional[int] = Field(default=DEFAULTS["is_first_pick_radiant"])
|
||||
|
||||
# герои (IDs)
|
||||
r_h1: Optional[int] = Field(default=DEFAULTS["r_h1"])
|
||||
r_h2: Optional[int] = Field(default=DEFAULTS["r_h2"])
|
||||
r_h3: Optional[int] = Field(default=DEFAULTS["r_h3"])
|
||||
r_h4: Optional[int] = Field(default=DEFAULTS["r_h4"])
|
||||
r_h5: Optional[int] = Field(default=DEFAULTS["r_h5"])
|
||||
|
||||
d_h1: Optional[int] = Field(default=DEFAULTS["d_h1"])
|
||||
d_h2: Optional[int] = Field(default=DEFAULTS["d_h2"])
|
||||
d_h3: Optional[int] = Field(default=DEFAULTS["d_h3"])
|
||||
d_h4: Optional[int] = Field(default=DEFAULTS["d_h4"])
|
||||
d_h5: Optional[int] = Field(default=DEFAULTS["d_h5"])
|
||||
|
||||
# игроки (IDs)
|
||||
r_p1: Optional[int] = Field(default=DEFAULTS["r_p1"])
|
||||
r_p2: Optional[int] = Field(default=DEFAULTS["r_p2"])
|
||||
r_p3: Optional[int] = Field(default=DEFAULTS["r_p3"])
|
||||
r_p4: Optional[int] = Field(default=DEFAULTS["r_p4"])
|
||||
r_p5: Optional[int] = Field(default=DEFAULTS["r_p5"])
|
||||
|
||||
d_p1: Optional[int] = Field(default=DEFAULTS["d_p1"])
|
||||
d_p2: Optional[int] = Field(default=DEFAULTS["d_p2"])
|
||||
d_p3: Optional[int] = Field(default=DEFAULTS["d_p3"])
|
||||
d_p4: Optional[int] = Field(default=DEFAULTS["d_p4"])
|
||||
d_p5: Optional[int] = Field(default=DEFAULTS["d_p5"])
|
||||
|
||||
# позиции героев (1-5)
|
||||
rp_h1: Optional[int] = Field(default=DEFAULTS["rp_h1"])
|
||||
rp_h2: Optional[int] = Field(default=DEFAULTS["rp_h2"])
|
||||
rp_h3: Optional[int] = Field(default=DEFAULTS["rp_h3"])
|
||||
rp_h4: Optional[int] = Field(default=DEFAULTS["rp_h4"])
|
||||
rp_h5: Optional[int] = Field(default=DEFAULTS["rp_h5"])
|
||||
|
||||
dp_h1: Optional[int] = Field(default=DEFAULTS["dp_h1"])
|
||||
dp_h2: Optional[int] = Field(default=DEFAULTS["dp_h2"])
|
||||
dp_h3: Optional[int] = Field(default=DEFAULTS["dp_h3"])
|
||||
dp_h4: Optional[int] = Field(default=DEFAULTS["dp_h4"])
|
||||
dp_h5: Optional[int] = Field(default=DEFAULTS["dp_h5"])
|
||||
|
||||
# =========================
|
||||
# Хелперы
|
||||
# =========================
|
||||
def build_long_format_input(payload: dict) -> pd.DataFrame:
|
||||
"""
|
||||
Конвертирует payload в hero+position combination features для модели.
|
||||
|
||||
Создаёт бинарные признаки вида radiant_h{hero_id}_p{position} и dire_h{hero_id}_p{position}
|
||||
"""
|
||||
features = {}
|
||||
|
||||
# Инициализируем все признаки нулями
|
||||
for feat in FEATURE_ORDER_PRO:
|
||||
features[feat] = 0
|
||||
|
||||
# Radiant heroes с позициями
|
||||
for i in range(1, 6):
|
||||
hero_id = int(payload.get(f"r_h{i}", -1))
|
||||
position = int(payload.get(f"rp_h{i}", -1))
|
||||
|
||||
if hero_id >= 0 and position >= 0:
|
||||
feature_name = f"radiant_h{hero_id}_p{position}"
|
||||
if feature_name in features:
|
||||
features[feature_name] = 1
|
||||
|
||||
# Dire heroes с позициями
|
||||
for i in range(1, 6):
|
||||
hero_id = int(payload.get(f"d_h{i}", -1))
|
||||
position = int(payload.get(f"dp_h{i}", -1))
|
||||
|
||||
if hero_id >= 0 and position >= 0:
|
||||
feature_name = f"dire_h{hero_id}_p{position}"
|
||||
if feature_name in features:
|
||||
features[feature_name] = 1
|
||||
|
||||
# Создаём DataFrame с одной строкой в правильном порядке
|
||||
df = pd.DataFrame([features], columns=FEATURE_ORDER_PRO)
|
||||
|
||||
return df
|
||||
|
||||
def proba_percent(p: float) -> float:
|
||||
"""Перевод вероятности в проценты (0..100) с отсечкой."""
|
||||
return round(float(np.clip(p * 100.0, 0.0, 100.0)))
|
||||
|
||||
# =========================
|
||||
# Роут
|
||||
# =========================
|
||||
@router.post("/draft/predict")
|
||||
async def predict(request: Request):
|
||||
body = await request.json()
|
||||
|
||||
# Конвертируем все значения героев, игроков и позиций в int
|
||||
for key in body:
|
||||
if key.startswith(("r_h", "d_h", "is_first_pick_radiant")):
|
||||
if body[key] is not None and body[key] != "":
|
||||
try:
|
||||
body[key] = int(body[key])
|
||||
except (ValueError, TypeError):
|
||||
body[key] = -1
|
||||
else:
|
||||
body[key] = -1
|
||||
elif key.startswith(("rp_h", "dp_h")):
|
||||
if body[key] == 0:
|
||||
body[key] = -1
|
||||
else:
|
||||
body[key] = -1
|
||||
|
||||
# Hero+position combination предсказание
|
||||
X_pro = build_long_format_input(body)
|
||||
|
||||
# Получаем предсказание для матча (одна строка)
|
||||
radiant_pro = float(modelPro.predict_proba(X_pro)[0, 1])
|
||||
|
||||
rp = proba_percent(radiant_pro)
|
||||
rd = 100.0 - rp
|
||||
|
||||
# Предсказание bag-of-heroes модели
|
||||
bag_prediction = predict_bag_of_heroes(body)
|
||||
|
||||
# Предсказание модели с игроками
|
||||
players_prediction = predict_with_players(body)
|
||||
|
||||
# Предсказание стекинг модели (ленивый импорт для избежания циклической зависимости)
|
||||
try:
|
||||
from routes.predict_stacking import predict_stacking
|
||||
stacking_prediction = predict_stacking(body)
|
||||
except Exception:
|
||||
stacking_prediction = {"radiant_win": 50, "dire_win": 50}
|
||||
|
||||
return {
|
||||
"pro-with-pos": {
|
||||
"radiant_win": rp,
|
||||
"dire_win": rd
|
||||
},
|
||||
"pro": {
|
||||
"radiant_win": bag_prediction["radiant_win"],
|
||||
"dire_win": bag_prediction["dire_win"]
|
||||
},
|
||||
"with-players": {
|
||||
"radiant_win": players_prediction["radiant_win"],
|
||||
"dire_win": players_prediction["dire_win"]
|
||||
},
|
||||
"stacking": {
|
||||
"radiant_win": stacking_prediction["radiant_win"],
|
||||
"dire_win": stacking_prediction["dire_win"]
|
||||
}
|
||||
}
|
||||
85
routes/predict_bag_of_heroes.py
Normal file
85
routes/predict_bag_of_heroes.py
Normal file
@@ -0,0 +1,85 @@
|
||||
from catboost import CatBoostClassifier
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from typing import Dict, Any
|
||||
|
||||
# Загрузка модели
|
||||
modelBagOfHeroes = CatBoostClassifier()
|
||||
modelBagOfHeroes.load_model("artifacts/model_bag_of_heroes.cbm")
|
||||
|
||||
# Загрузка порядка фич
|
||||
def load_feature_order(path: str) -> list[str]:
|
||||
fo = pd.read_csv(path)
|
||||
first_col = fo.columns[0]
|
||||
return fo[first_col].tolist()
|
||||
|
||||
FEATURE_ORDER_BAG: list[str] = load_feature_order("artifacts/feature_order_bag_of_heroes.csv")
|
||||
|
||||
def build_bag_of_heroes_features(payload: Dict[str, Any]) -> pd.DataFrame:
|
||||
"""
|
||||
Конвертирует payload в bag-of-heroes формат.
|
||||
|
||||
payload содержит:
|
||||
- is_first_pick_radiant
|
||||
- r_h1, r_h2, r_h3, r_h4, r_h5
|
||||
- d_h1, d_h2, d_h3, d_h4, d_h5
|
||||
|
||||
Возвращает DataFrame с колонками:
|
||||
- is_first_pick_radiant
|
||||
- radiant_hero_{1-145}
|
||||
- dire_hero_{1-145}
|
||||
"""
|
||||
# Получаем героев из payload
|
||||
radiant_heroes = []
|
||||
dire_heroes = []
|
||||
|
||||
for i in range(1, 6):
|
||||
r_hero = payload.get(f"r_h{i}", -1)
|
||||
d_hero = payload.get(f"d_h{i}", -1)
|
||||
|
||||
if r_hero and r_hero != -1:
|
||||
radiant_heroes.append(int(r_hero))
|
||||
if d_hero and d_hero != -1:
|
||||
dire_heroes.append(int(d_hero))
|
||||
|
||||
# Создаем словарь признаков
|
||||
features = {feat: 0 for feat in FEATURE_ORDER_BAG}
|
||||
|
||||
# Устанавливаем is_first_pick_radiant
|
||||
features["is_first_pick_radiant"] = int(payload.get("is_first_pick_radiant", 0))
|
||||
|
||||
# Устанавливаем бинарные признаки для героев Radiant
|
||||
for hero_id in radiant_heroes:
|
||||
feat_name = f"radiant_hero_{hero_id}"
|
||||
if feat_name in features:
|
||||
features[feat_name] = 1
|
||||
|
||||
# Устанавливаем бинарные признаки для героев Dire
|
||||
for hero_id in dire_heroes:
|
||||
feat_name = f"dire_hero_{hero_id}"
|
||||
if feat_name in features:
|
||||
features[feat_name] = 1
|
||||
|
||||
# Создаем DataFrame с правильным порядком колонок
|
||||
return pd.DataFrame([features], columns=FEATURE_ORDER_BAG)
|
||||
|
||||
def predict_bag_of_heroes(payload: Dict[str, Any]) -> Dict[str, float]:
|
||||
"""
|
||||
Делает предсказание с использованием bag-of-heroes модели.
|
||||
|
||||
Возвращает:
|
||||
{
|
||||
"radiant_win": вероятность победы Radiant (0-100),
|
||||
"dire_win": вероятность победы Dire (0-100)
|
||||
}
|
||||
"""
|
||||
X = build_bag_of_heroes_features(payload)
|
||||
proba = modelBagOfHeroes.predict_proba(X)[0, 1]
|
||||
|
||||
radiant_win = round(float(np.clip(proba * 100.0, 0.0, 100.0)))
|
||||
dire_win = 100.0 - radiant_win
|
||||
|
||||
return {
|
||||
"radiant_win": radiant_win,
|
||||
"dire_win": dire_win
|
||||
}
|
||||
53
routes/predict_stacking.py
Normal file
53
routes/predict_stacking.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import pickle
|
||||
from typing import Dict, Any
|
||||
from routes.predict import build_long_format_input, modelPro
|
||||
from routes.predict_bag_of_heroes import build_bag_of_heroes_features, modelBagOfHeroes
|
||||
from routes.predict_with_players import build_player_features, modelWithPlayers
|
||||
|
||||
# Загрузка мета-модели (Logistic Regression)
|
||||
with open("artifacts/model_stacking.pkl", 'rb') as f:
|
||||
modelStacking = pickle.load(f)
|
||||
|
||||
def predict_stacking(payload: Dict[str, Any]) -> Dict[str, float]:
|
||||
"""
|
||||
Делает предсказание с использованием стекинг-модели.
|
||||
|
||||
Сначала получает предсказания от всех базовых моделей,
|
||||
затем использует их как признаки для мета-модели.
|
||||
|
||||
Возвращает:
|
||||
{
|
||||
"radiant_win": вероятность победы Radiant (0-100),
|
||||
"dire_win": вероятность победы Dire (0-100)
|
||||
}
|
||||
"""
|
||||
# === Предсказание модели 1: Heroes + Positions ===
|
||||
X_with_pos = build_long_format_input(payload)
|
||||
pred1 = float(modelPro.predict_proba(X_with_pos)[0, 1])
|
||||
|
||||
# === Предсказание модели 2: Bag of Heroes ===
|
||||
X_bag = build_bag_of_heroes_features(payload)
|
||||
pred2 = float(modelBagOfHeroes.predict_proba(X_bag)[0, 1])
|
||||
|
||||
# === Предсказание модели 3: With Players ===
|
||||
X_players = build_player_features(payload)
|
||||
pred3 = float(modelWithPlayers.predict_proba(X_players)[0, 1])
|
||||
|
||||
# === Мета-модель ===
|
||||
X_meta = pd.DataFrame([{
|
||||
"pred_with_positions": pred1,
|
||||
"pred_bag_of_heroes": pred2,
|
||||
"pred_with_players": pred3
|
||||
}])
|
||||
|
||||
proba = modelStacking.predict_proba(X_meta)[0, 1]
|
||||
|
||||
radiant_win = round(float(np.clip(proba * 100.0, 0.0, 100.0)))
|
||||
dire_win = 100.0 - radiant_win
|
||||
|
||||
return {
|
||||
"radiant_win": radiant_win,
|
||||
"dire_win": dire_win
|
||||
}
|
||||
123
routes/predict_with_players.py
Normal file
123
routes/predict_with_players.py
Normal file
@@ -0,0 +1,123 @@
|
||||
from catboost import CatBoostClassifier
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from typing import Dict, Any
|
||||
|
||||
# Загрузка модели с игроками
|
||||
modelWithPlayers = CatBoostClassifier()
|
||||
modelWithPlayers.load_model("artifacts/model_with_players.cbm")
|
||||
|
||||
# Загрузка порядка фич
|
||||
def load_feature_order(path: str) -> list:
|
||||
fo = pd.read_csv(path)
|
||||
first_col = fo.columns[0]
|
||||
return fo[first_col].tolist()
|
||||
|
||||
FEATURE_ORDER_WITH_PLAYERS = load_feature_order("artifacts/feature_order_with_players.csv")
|
||||
|
||||
def build_player_features(payload: Dict[str, Any]) -> pd.DataFrame:
|
||||
"""
|
||||
Создаёт бинарные признаки для модели с игроками.
|
||||
|
||||
Признаки:
|
||||
- radiant_p{player_id}_h{hero_id}_pos{position}
|
||||
- radiant_p{player_id}_h{hero_id}
|
||||
- radiant_p{player_id}_pos{position}
|
||||
(аналогично для dire)
|
||||
"""
|
||||
features = {}
|
||||
|
||||
# Инициализируем все признаки нулями
|
||||
for feat in FEATURE_ORDER_WITH_PLAYERS:
|
||||
features[feat] = 0
|
||||
|
||||
# Radiant: игроки + герои + позиции
|
||||
for i in range(1, 6):
|
||||
hero_id = int(payload.get(f"r_h{i}", -1))
|
||||
player_id = int(payload.get(f"r_p{i}", -1))
|
||||
position = int(payload.get(f"rp_h{i}", -1))
|
||||
|
||||
# Признак: игрок + герой + позиция
|
||||
if player_id > 0 and hero_id >= 0 and position >= 0:
|
||||
feature_name = f"radiant_p{player_id}_h{hero_id}_pos{position}"
|
||||
if feature_name in features:
|
||||
features[feature_name] = 1
|
||||
|
||||
# Признак: только игрок + герой
|
||||
if player_id > 0 and hero_id >= 0:
|
||||
feature_name = f"radiant_p{player_id}_h{hero_id}"
|
||||
if feature_name in features:
|
||||
features[feature_name] = 1
|
||||
|
||||
# Признак: только игрок + позиция
|
||||
if player_id > 0 and position >= 0:
|
||||
feature_name = f"radiant_p{player_id}_pos{position}"
|
||||
if feature_name in features:
|
||||
features[feature_name] = 1
|
||||
|
||||
# Dire: игроки + герои + позиции
|
||||
for i in range(1, 6):
|
||||
hero_id = int(payload.get(f"d_h{i}", -1))
|
||||
player_id = int(payload.get(f"d_p{i}", -1))
|
||||
position = int(payload.get(f"dp_h{i}", -1))
|
||||
|
||||
# Признак: игрок + герой + позиция
|
||||
if player_id > 0 and hero_id >= 0 and position >= 0:
|
||||
feature_name = f"dire_p{player_id}_h{hero_id}_pos{position}"
|
||||
if feature_name in features:
|
||||
features[feature_name] = 1
|
||||
|
||||
# Признак: только игрок + герой
|
||||
if player_id > 0 and hero_id >= 0:
|
||||
feature_name = f"dire_p{player_id}_h{hero_id}"
|
||||
if feature_name in features:
|
||||
features[feature_name] = 1
|
||||
|
||||
# Признак: только игрок + позиция
|
||||
if player_id > 0 and position >= 0:
|
||||
feature_name = f"dire_p{player_id}_pos{position}"
|
||||
if feature_name in features:
|
||||
features[feature_name] = 1
|
||||
|
||||
# Создаём DataFrame с одной строкой в правильном порядке
|
||||
df = pd.DataFrame([features], columns=FEATURE_ORDER_WITH_PLAYERS)
|
||||
|
||||
return df
|
||||
|
||||
def predict_with_players(payload: Dict[str, Any]) -> Dict[str, float]:
|
||||
"""
|
||||
Делает предсказание с использованием модели с игроками.
|
||||
|
||||
Возвращает:
|
||||
{
|
||||
"radiant_win": вероятность победы Radiant (0-100),
|
||||
"dire_win": вероятность победы Dire (0-100)
|
||||
}
|
||||
"""
|
||||
# Проверяем, есть ли хотя бы один игрок в payload
|
||||
has_players = False
|
||||
for i in range(1, 6):
|
||||
if payload.get(f"r_p{i}", -1) > 0 or payload.get(f"d_p{i}", -1) > 0:
|
||||
has_players = True
|
||||
break
|
||||
|
||||
# Если нет игроков, возвращаем 50/50
|
||||
if not has_players:
|
||||
return {
|
||||
"radiant_win": 50,
|
||||
"dire_win": 50
|
||||
}
|
||||
|
||||
# Создаём признаки
|
||||
X = build_player_features(payload)
|
||||
|
||||
# Предсказание
|
||||
proba = modelWithPlayers.predict_proba(X)[0, 1]
|
||||
|
||||
radiant_win = round(float(np.clip(proba * 100.0, 0.0, 100.0)))
|
||||
dire_win = 100 - radiant_win
|
||||
|
||||
return {
|
||||
"radiant_win": radiant_win,
|
||||
"dire_win": dire_win
|
||||
}
|
||||
24
routes/teams.py
Normal file
24
routes/teams.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from fastapi import APIRouter
|
||||
import psycopg2
|
||||
from psycopg2.extras import RealDictCursor
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def get_db_connection():
|
||||
return psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="korobka_db",
|
||||
user="postgres",
|
||||
password="postgres"
|
||||
)
|
||||
|
||||
@router.get("/teams")
|
||||
def get_teams():
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor(cursor_factory=RealDictCursor)
|
||||
cursor.execute("SELECT id, name FROM teams ORDER BY id")
|
||||
teams = cursor.fetchall()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return teams
|
||||
236
run.sh
Executable file
236
run.sh
Executable file
@@ -0,0 +1,236 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ===========================
|
||||
# Конфиг (меняйте по желанию)
|
||||
# ===========================
|
||||
PY=python3
|
||||
VENV=".venv"
|
||||
|
||||
# Порт REST-сервиса:
|
||||
PORT="${PORT:-8000}"
|
||||
|
||||
# Принудить IPv4 (полезно при проблемном IPv6 у провайдера):
|
||||
FORCE_IPV4="${FORCE_IPV4:-1}"
|
||||
|
||||
# API-ключи (необязательно, но улучшает стабильность/квоты):
|
||||
# export OPENDOTA_API_KEY=...
|
||||
# export STRATZ_TOKEN=...
|
||||
OPENDOTA_API_KEY="${OPENDOTA_API_KEY:-}"
|
||||
STRATZ_TOKEN="${STRATZ_TOKEN:-}"
|
||||
|
||||
# Использовать STRATZ вместо OpenDota
|
||||
# только для шага 1 (список матчей): USE_STRATZ_LIST=1
|
||||
# только для шага 2 (детали/драфт): USE_STRATZ_DETAILS=1
|
||||
USE_STRATZ_LIST="${USE_STRATZ_LIST:-0}"
|
||||
USE_STRATZ_DETAILS="${USE_STRATZ_DETAILS:-0}"
|
||||
|
||||
# Задержка после каждых 100 запросов (смягчить 429):
|
||||
SLEEP_PER_100="${SLEEP_PER_100:-1.0}"
|
||||
|
||||
# ===========================
|
||||
# Окружение и зависимости
|
||||
# ===========================
|
||||
if [ ! -d "$VENV" ]; then
|
||||
$PY -m venv "$VENV"
|
||||
fi
|
||||
# shellcheck disable=SC1091
|
||||
source "$VENV/bin/activate"
|
||||
|
||||
pip install -U pip
|
||||
pip install pandas pyarrow requests httpx "urllib3>=2.2" certifi catboost scikit-learn fastapi uvicorn
|
||||
|
||||
mkdir -p data artifacts
|
||||
|
||||
# ===========================
|
||||
# Хелперы
|
||||
# ===========================
|
||||
export FORCE_IPV4
|
||||
export OPENDOTA_API_KEY
|
||||
export STRATZ_TOKEN
|
||||
export PAGES
|
||||
export SLEEP_PER_100
|
||||
|
||||
# ===========================
|
||||
# [1/7] Список pub-матчей
|
||||
# ===========================
|
||||
# [1b] Паблики (high-rank)
|
||||
$PY educationML/fetch_public_matches.py
|
||||
# [2b] Детали пабликов (герои из players)
|
||||
$PY educationML/fetch_public_details.py
|
||||
|
||||
# ===========================
|
||||
# [2/7] Список pro-матчей
|
||||
# ===========================
|
||||
echo "[1/6] Fetch pro matches via OpenDota (pages=$PAGES)"
|
||||
$PY educationML/fetch_pro_matches_opendota.py
|
||||
|
||||
# =========================================
|
||||
# [2/6] Детали матча + драфт (устойчивый)
|
||||
# =========================================
|
||||
if [ "$USE_STRATZ_DETAILS" = "1" ]; then
|
||||
echo "[2/6] Fetch match details + draft via STRATZ"
|
||||
$PY - <<'PYCODE'
|
||||
|
||||
PYCODE
|
||||
|
||||
else
|
||||
echo "[2/6] Fetch match details + draft via OpenDota (robust)"
|
||||
$PY - <<'PYCODE'
|
||||
import os, time, socket, sys, pandas as pd, requests, httpx
|
||||
from urllib3.util.retry import Retry
|
||||
from requests.adapters import HTTPAdapter
|
||||
|
||||
# IPv4-only (если FORCE_IPV4=1)
|
||||
if os.getenv("FORCE_IPV4","1") == "1":
|
||||
_orig = socket.getaddrinfo
|
||||
def _v4(host, port, family=0, type=0, proto=0, flags=0):
|
||||
return _orig(host, port, socket.AF_INET, type, proto, flags)
|
||||
socket.getaddrinfo = _v4
|
||||
|
||||
API_KEY = os.getenv("OPENDOTA_API_KEY")
|
||||
SLEEP_PER_100 = float(os.getenv("SLEEP_PER_100","1.0"))
|
||||
BASE = "https://api.opendota.com/api/matches/{mid}"
|
||||
headers = {"User-Agent":"korobkaGames/1.0","Accept":"application/json","Connection":"close"}
|
||||
|
||||
# список match_id
|
||||
pro = pd.read_parquet("data/pro_matches.parquet")
|
||||
match_ids = pro['match_id'].drop_duplicates().tolist()
|
||||
|
||||
# requests с Retry
|
||||
sess = requests.Session()
|
||||
retries = Retry(total=6, connect=6, read=6, backoff_factor=0.7,
|
||||
status_forcelist=[429,500,502,503,504],
|
||||
allowed_methods=frozenset(["GET"]))
|
||||
sess.mount("https://", HTTPAdapter(max_retries=retries))
|
||||
|
||||
def fetch_one(mid: int):
|
||||
url = BASE.format(mid=mid)
|
||||
if API_KEY:
|
||||
url += f"?api_key={API_KEY}"
|
||||
try:
|
||||
r = sess.get(url, headers=headers, timeout=(5,40))
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
except requests.exceptions.SSLError:
|
||||
# fallback: httpx http2 off
|
||||
with httpx.Client(http2=False, timeout=40, headers=headers) as client:
|
||||
resp = client.get(url)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
match_rows, draft_rows, failed = [], [], []
|
||||
for i, mid in enumerate(match_ids, 1):
|
||||
try:
|
||||
m = fetch_one(int(mid))
|
||||
match_rows.append({
|
||||
"match_id": int(mid),
|
||||
"date": pd.to_datetime(m.get("start_time",0), unit="s"),
|
||||
"patch": str(m.get("patch")),
|
||||
"radiant_win": bool(m.get("radiant_win")),
|
||||
"duration_sec": m.get("duration"),
|
||||
"league_id": (m.get("league") or {}).get("id"),
|
||||
"series_type": m.get("series_type"),
|
||||
})
|
||||
for pb in (m.get("picks_bans") or []):
|
||||
draft_rows.append({
|
||||
"match_id": int(mid),
|
||||
"is_pick": pb.get("is_pick", False),
|
||||
"team": pb.get("team"),
|
||||
"hero_id": pb.get("hero_id"),
|
||||
"order": pb.get("order")
|
||||
})
|
||||
except Exception:
|
||||
failed.append(int(mid))
|
||||
if i % 100 == 0:
|
||||
time.sleep(SLEEP_PER_100)
|
||||
|
||||
pd.DataFrame(match_rows).to_parquet("data/matches.parquet", index=False)
|
||||
pd.DataFrame(draft_rows).to_parquet("data/draft.parquet", index=False)
|
||||
pd.Series(failed, name="failed_match_id").to_csv("data/matches_failed.csv", index=False)
|
||||
print(f"Saved via OpenDota: matches={len(match_rows)} draft_rows={len(draft_rows)} failed={len(failed)}")
|
||||
if not match_rows:
|
||||
raise SystemExit("OpenDota details: ничего не скачано")
|
||||
PYCODE
|
||||
fi
|
||||
|
||||
# ===========================
|
||||
# [3/6] Простой Elo baseline
|
||||
# ===========================
|
||||
echo "[3/6] Build Elo"
|
||||
$PY - <<'PYCODE'
|
||||
import pandas as pd
|
||||
matches = pd.read_parquet("data/matches.parquet").sort_values("date")
|
||||
pro = pd.read_parquet("data/pro_matches.parquet")[['match_id','radiant_name','dire_name']]
|
||||
df = matches.merge(pro, on='match_id', how='left')
|
||||
|
||||
K = 24
|
||||
elo = {}
|
||||
def get_elo(t): return elo.get(t, 1500)
|
||||
def expect(a,b): return 1.0/(1.0+10**((b-a)/400))
|
||||
|
||||
rows=[]
|
||||
for _, r in df.iterrows():
|
||||
A, B = r['radiant_name'], r['dire_name']
|
||||
ra, rb = get_elo(A), get_elo(B)
|
||||
ea, eb = expect(ra,rb), expect(rb,ra)
|
||||
y = 1.0 if r['radiant_win'] else 0.0
|
||||
rows.append({
|
||||
'match_id': r['match_id'],
|
||||
'date': r['date'],
|
||||
'elo_radiant': ra, 'elo_dire': rb,
|
||||
'elo_diff_90': ra - rb # упрощённо без окон
|
||||
})
|
||||
elo[A] = ra + K*(y-ea)
|
||||
elo[B] = rb + K*((1-y)-eb)
|
||||
|
||||
pd.DataFrame(rows).to_parquet("data/elo.parquet", index=False)
|
||||
print("Saved data/elo.parquet")
|
||||
PYCODE
|
||||
|
||||
# [4] вместо старого build_dataset_draft.py
|
||||
$PY educationML/build_dataset_mixed.py
|
||||
|
||||
# ===========================
|
||||
# [5/6] Обучение модели
|
||||
# ===========================
|
||||
echo "[5/6] Train CatBoost"
|
||||
$PY - <<'PYCODE'
|
||||
import pandas as pd
|
||||
from catboost import CatBoostClassifier
|
||||
from sklearn.model_selection import TimeSeriesSplit
|
||||
from sklearn.metrics import log_loss, brier_score_loss
|
||||
|
||||
df = pd.read_parquet("data/dataset_mixed.parquet").sort_values("date")
|
||||
cat_cols = ['patch','source','r_h1','r_h2','r_h3','r_h4','r_h5','d_h1','d_h2','d_h3','d_h4','d_h5']
|
||||
X = df.drop(columns=['y','date','match_id']) if 'match_id' in df.columns else df.drop(columns=['y','date'])
|
||||
y = df['y']
|
||||
cat_idx = [X.columns.get_loc(c) for c in cat_cols]
|
||||
|
||||
tscv = TimeSeriesSplit(n_splits=5)
|
||||
ll, br = [], []
|
||||
for tr, te in tscv.split(X):
|
||||
model = CatBoostClassifier(
|
||||
depth=8, iterations=1200, learning_rate=0.03,
|
||||
loss_function='Logloss', eval_metric='Logloss', verbose=False
|
||||
)
|
||||
model.fit(X.iloc[tr], y.iloc[tr], cat_features=cat_idx)
|
||||
p = model.predict_proba(X.iloc[te])[:,1]
|
||||
ll.append(log_loss(y.iloc[te], p))
|
||||
br.append(brier_score_loss(y.iloc[te], p))
|
||||
print("CV LogLoss=", sum(ll)/len(ll), " Brier=", sum(br)/len(br))
|
||||
|
||||
final = CatBoostClassifier(depth=8, iterations=1500, learning_rate=0.03,
|
||||
loss_function='Logloss', verbose=False)
|
||||
final.fit(X, y, cat_features=cat_idx)
|
||||
final.save_model("artifacts/model_draft.cbm")
|
||||
pd.Series(X.columns).to_csv("artifacts/feature_order.csv", index=False)
|
||||
print("Saved artifacts/model_draft.cbm and artifacts/feature_order.csv")
|
||||
PYCODE
|
||||
|
||||
# ===========================
|
||||
# [6/6] REST-сервис предсказаний
|
||||
# ===========================
|
||||
echo "[6/6] Start API → http://127.0.0.1:$PORT"
|
||||
|
||||
exec uvicorn serve:app --host 0.0.0.0 --port "$PORT"
|
||||
31
serve.py
Normal file
31
serve.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from routes.predict import router as predict_router
|
||||
|
||||
from routes.heroes import router as heroes_router
|
||||
from routes.match import router as match_router
|
||||
from routes.teams import router as teams_router
|
||||
from routes.players import router as players_router
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# CORS настройки
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
app.include_router(predict_router)
|
||||
|
||||
app.include_router(heroes_router)
|
||||
app.include_router(match_router)
|
||||
app.include_router(teams_router)
|
||||
app.include_router(players_router)
|
||||
|
||||
@app.get("/features")
|
||||
def features():
|
||||
# Чтобы легко проверить, что ждёт модель
|
||||
return {"feature_order": feature_order, "defaults": DEFAULTS}
|
||||
106
start/parse_pro_details_match.py
Normal file
106
start/parse_pro_details_match.py
Normal file
@@ -0,0 +1,106 @@
|
||||
import requests
|
||||
import psycopg2
|
||||
import time
|
||||
from psycopg2.extras import RealDictCursor, execute_values
|
||||
|
||||
# Подключение к базе данных
|
||||
conn = psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="korobka_db",
|
||||
user="postgres",
|
||||
password="postgres"
|
||||
)
|
||||
cursor = conn.cursor(cursor_factory=RealDictCursor)
|
||||
|
||||
# Функция для определения позиции по lane и lane_role
|
||||
def get_position(lane, lane_role):
|
||||
"""
|
||||
lane 2, lane_role 2 -> pos 2 (Mid Core)
|
||||
lane 1, lane_role 1 -> pos 1 (Safe Lane Carry)
|
||||
lane 1, lane_role 3 -> pos 5 (Safe Lane Support)
|
||||
lane 3, lane_role 1 -> pos 3 (Offlane Core)
|
||||
lane 3, lane_role 3 -> pos 4 (Offlane Support)
|
||||
"""
|
||||
if lane == 2 and lane_role == 2:
|
||||
return 2
|
||||
elif lane == 1 and lane_role == 1:
|
||||
return 1
|
||||
elif lane == 1 and lane_role == 3:
|
||||
return 5
|
||||
elif lane == 3 and lane_role == 1:
|
||||
return 3
|
||||
elif lane == 3 and lane_role == 3:
|
||||
return 4
|
||||
else:
|
||||
return -1 # Неизвестная комбинация
|
||||
|
||||
# Получение ID матчей из БД
|
||||
cursor.execute("""
|
||||
select m.id
|
||||
from matches m
|
||||
left join details_match dm on dm.match_id = m.id
|
||||
where m."source" = 'pro' and dm.match_id is null
|
||||
""")
|
||||
matches = cursor.fetchall()
|
||||
match_ids = [match['id'] for match in matches]
|
||||
|
||||
print(f"Получено {len(match_ids)} ID матчей из БД")
|
||||
|
||||
# Запрос деталей для каждого матча
|
||||
for idx, match_id in enumerate(match_ids, 1):
|
||||
url = f"https://api.opendota.com/api/matches/{match_id}"
|
||||
|
||||
try:
|
||||
response = requests.get(url, timeout=30)
|
||||
|
||||
if response.status_code == 200:
|
||||
match_data = response.json()
|
||||
picks_bans = match_data.get('picks_bans', [])
|
||||
players = match_data.get('players', [])
|
||||
|
||||
print(f"[{idx}/{len(match_ids)}] Match {match_id}: {len(picks_bans)} picks/bans, {len(players)} players")
|
||||
|
||||
# Создаем словари из players
|
||||
hero_to_account = {player.get('hero_id'): player.get('account_id') for player in players if player.get('hero_id')}
|
||||
hero_to_pos = {player.get('hero_id'): get_position(player.get('lane'), player.get('lane_role')) for player in players if player.get('hero_id')}
|
||||
|
||||
# Сохранение picks_bans в БД (только пики) с позициями
|
||||
data = [
|
||||
(
|
||||
match_id,
|
||||
pick_ban.get('hero_id'),
|
||||
pick_ban.get('team'),
|
||||
pick_ban.get('order'),
|
||||
hero_to_account.get(pick_ban.get('hero_id')), # players_id
|
||||
hero_to_pos.get(pick_ban.get('hero_id'), -1), # pos
|
||||
'pro' # source
|
||||
)
|
||||
for pick_ban in picks_bans
|
||||
if pick_ban.get('is_pick')
|
||||
]
|
||||
|
||||
print(f"Вставка {len(data)} записей для матча {match_id}")
|
||||
|
||||
execute_values(
|
||||
cursor,
|
||||
"""INSERT INTO details_match (match_id, hero_id, team, "order", players_id, pos, source)
|
||||
VALUES %s""",
|
||||
data
|
||||
)
|
||||
conn.commit()
|
||||
time.sleep(1) # пауза между запросами
|
||||
|
||||
else:
|
||||
print(f"[{idx}/{len(match_ids)}] Ошибка для матча {match_id}: {response.status_code}")
|
||||
if response.status_code == 429:
|
||||
print("Превышен лимит запросов, ждем 10 секунд...")
|
||||
time.sleep(10)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[{idx}/{len(match_ids)}] Исключение для матча {match_id}: {e}")
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
print("Завершено сохранение деталей матчей")
|
||||
79
start/parse_pro_matches.py
Normal file
79
start/parse_pro_matches.py
Normal file
@@ -0,0 +1,79 @@
|
||||
import requests
|
||||
import psycopg2
|
||||
from psycopg2.extras import execute_values
|
||||
|
||||
PAGE = 10
|
||||
url = "https://api.opendota.com/api/proMatches"
|
||||
all_matches = []
|
||||
less_than_match_id = None
|
||||
|
||||
# Разрешенные лиги
|
||||
ALLOWED_LEAGUES = [17420] # Замените на нужные ID лиг
|
||||
|
||||
for page in range(PAGE):
|
||||
params = {}
|
||||
if less_than_match_id:
|
||||
params['less_than_match_id'] = less_than_match_id
|
||||
|
||||
response = requests.get(url, params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
matches = response.json()
|
||||
all_matches.extend(matches)
|
||||
print(f"Страница {page + 1}: получено {len(matches)} матчей")
|
||||
|
||||
if matches:
|
||||
less_than_match_id = matches[-1]['match_id']
|
||||
else:
|
||||
print(f"Ошибка на странице {page + 1}: {response.status_code}")
|
||||
break
|
||||
|
||||
print(f"\nВсего получено {len(all_matches)} матчей")
|
||||
|
||||
# Подключение к базе данных
|
||||
conn = psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="korobka_db",
|
||||
user="postgres",
|
||||
password="postgres"
|
||||
)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Подготовка данных для вставки (фильтр по leagueid)
|
||||
data = [
|
||||
(
|
||||
match['match_id'],
|
||||
match.get('start_time'),
|
||||
match.get('leagueid'),
|
||||
match.get('radiant_team_id'),
|
||||
match.get('dire_team_id'),
|
||||
match.get('radiant_win'),
|
||||
'pro' # ← добавили source
|
||||
)
|
||||
for match in all_matches
|
||||
if match.get('leagueid') in ALLOWED_LEAGUES
|
||||
]
|
||||
|
||||
print(f"Отфильтровано {len(data)} матчей из {len(all_matches)} по разрешенным лигам")
|
||||
|
||||
# Вставка данных в таблицу
|
||||
execute_values(
|
||||
cursor,
|
||||
"""INSERT INTO matches (id, start_time, leagueid, radiant_team_id, dire_team_id, radiant_win, source)
|
||||
VALUES %s
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
start_time = EXCLUDED.start_time,
|
||||
leagueid = EXCLUDED.leagueid,
|
||||
radiant_team_id = EXCLUDED.radiant_team_id,
|
||||
dire_team_id = EXCLUDED.dire_team_id,
|
||||
radiant_win = EXCLUDED.radiant_win,
|
||||
source = EXCLUDED.source""",
|
||||
data
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
print(f"Успешно сохранено {len(data)} матчей в БД")
|
||||
234
test_models_accuracy.py
Normal file
234
test_models_accuracy.py
Normal file
@@ -0,0 +1,234 @@
|
||||
import sys
|
||||
sys.path.insert(0, '.')
|
||||
|
||||
import psycopg2
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from routes.predict import build_long_format_input, modelPro
|
||||
from routes.predict_bag_of_heroes import build_bag_of_heroes_features, modelBagOfHeroes
|
||||
from routes.predict_with_players import build_player_features, modelWithPlayers
|
||||
from routes.predict_stacking import predict_stacking
|
||||
|
||||
# Подключение к БД
|
||||
conn = psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="korobka_db",
|
||||
user="postgres",
|
||||
password="postgres"
|
||||
)
|
||||
|
||||
# Получаем случайные матчи с известными игроками
|
||||
query = """
|
||||
SELECT
|
||||
m.id as match_id,
|
||||
m.radiant_win,
|
||||
m.leagueid
|
||||
FROM matches m
|
||||
WHERE EXISTS (
|
||||
SELECT 1
|
||||
FROM details_match dm
|
||||
WHERE dm.match_id = m.id
|
||||
AND dm.players_id IS NOT NULL
|
||||
AND dm.players_id != 0
|
||||
)
|
||||
ORDER BY RANDOM()
|
||||
LIMIT 100
|
||||
"""
|
||||
|
||||
matches_df = pd.read_sql(query, conn)
|
||||
print(f"Загружено {len(matches_df)} случайных матчей")
|
||||
|
||||
# Получаем детали этих матчей
|
||||
match_ids = matches_df['match_id'].tolist()
|
||||
placeholders = ','.join(['%s'] * len(match_ids))
|
||||
|
||||
query_details = f"""
|
||||
SELECT
|
||||
dm.match_id,
|
||||
dm.hero_id,
|
||||
dm.team,
|
||||
dm.players_id,
|
||||
dm.pos,
|
||||
dm."order"
|
||||
FROM details_match dm
|
||||
WHERE dm.match_id IN ({placeholders})
|
||||
ORDER BY dm.match_id, dm."order"
|
||||
"""
|
||||
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(query_details, match_ids)
|
||||
details_rows = cursor.fetchall()
|
||||
conn.close()
|
||||
|
||||
# Преобразуем детали в словарь по match_id
|
||||
details_by_match = {}
|
||||
for row in details_rows:
|
||||
match_id = row[0]
|
||||
if match_id not in details_by_match:
|
||||
details_by_match[match_id] = []
|
||||
details_by_match[match_id].append({
|
||||
'hero_id': row[1],
|
||||
'team': row[2],
|
||||
'players_id': row[3],
|
||||
'pos': row[4],
|
||||
'order': row[5]
|
||||
})
|
||||
|
||||
print(f"Загружено деталей для {len(details_by_match)} матчей\n")
|
||||
|
||||
# Счётчики правильных предсказаний
|
||||
correct = {
|
||||
'model1': 0,
|
||||
'model2': 0,
|
||||
'model3': 0,
|
||||
'stacking': 0
|
||||
}
|
||||
|
||||
# Списки для хранения всех предсказаний (для расчёта AUC)
|
||||
predictions = {
|
||||
'model1': [],
|
||||
'model2': [],
|
||||
'model3': [],
|
||||
'stacking': []
|
||||
}
|
||||
actuals = []
|
||||
|
||||
print("Тестирование моделей...")
|
||||
print("="*80)
|
||||
|
||||
# Проверяем каждый матч
|
||||
for idx, match_row in matches_df.iterrows():
|
||||
match_id = match_row['match_id']
|
||||
radiant_win = match_row['radiant_win']
|
||||
|
||||
if match_id not in details_by_match:
|
||||
continue
|
||||
|
||||
details = details_by_match[match_id]
|
||||
|
||||
# Формируем payload
|
||||
payload = {}
|
||||
|
||||
# Разделяем на Radiant и Dire
|
||||
radiant_picks = sorted([d for d in details if d['team'] == 0], key=lambda x: x['order'])
|
||||
dire_picks = sorted([d for d in details if d['team'] == 1], key=lambda x: x['order'])
|
||||
|
||||
# Заполняем Radiant
|
||||
for i in range(5):
|
||||
if i < len(radiant_picks):
|
||||
payload[f'r_h{i+1}'] = radiant_picks[i]['hero_id']
|
||||
payload[f'r_p{i+1}'] = radiant_picks[i]['players_id'] if radiant_picks[i]['players_id'] else -1
|
||||
payload[f'rp_h{i+1}'] = radiant_picks[i]['pos'] if radiant_picks[i]['pos'] else -1
|
||||
else:
|
||||
payload[f'r_h{i+1}'] = -1
|
||||
payload[f'r_p{i+1}'] = -1
|
||||
payload[f'rp_h{i+1}'] = -1
|
||||
|
||||
# Заполняем Dire
|
||||
for i in range(5):
|
||||
if i < len(dire_picks):
|
||||
payload[f'd_h{i+1}'] = dire_picks[i]['hero_id']
|
||||
payload[f'd_p{i+1}'] = dire_picks[i]['players_id'] if dire_picks[i]['players_id'] else -1
|
||||
payload[f'dp_h{i+1}'] = dire_picks[i]['pos'] if dire_picks[i]['pos'] else -1
|
||||
else:
|
||||
payload[f'd_h{i+1}'] = -1
|
||||
payload[f'd_p{i+1}'] = -1
|
||||
payload[f'dp_h{i+1}'] = -1
|
||||
|
||||
# Предсказания
|
||||
try:
|
||||
# Модель 1: Heroes + Positions
|
||||
X1 = build_long_format_input(payload)
|
||||
pred1_proba = float(modelPro.predict_proba(X1)[0, 1])
|
||||
pred1 = pred1_proba >= 0.5
|
||||
|
||||
# Модель 2: Bag of Heroes
|
||||
X2 = build_bag_of_heroes_features(payload)
|
||||
pred2_proba = float(modelBagOfHeroes.predict_proba(X2)[0, 1])
|
||||
pred2 = pred2_proba >= 0.5
|
||||
|
||||
# Модель 3: With Players
|
||||
X3 = build_player_features(payload)
|
||||
pred3_proba = float(modelWithPlayers.predict_proba(X3)[0, 1])
|
||||
pred3 = pred3_proba >= 0.5
|
||||
|
||||
# Стекинг
|
||||
stack_result = predict_stacking(payload)
|
||||
pred_stack_proba = stack_result['radiant_win'] / 100.0
|
||||
pred_stack = pred_stack_proba >= 0.5
|
||||
|
||||
# Сохраняем предсказания
|
||||
predictions['model1'].append(pred1_proba)
|
||||
predictions['model2'].append(pred2_proba)
|
||||
predictions['model3'].append(pred3_proba)
|
||||
predictions['stacking'].append(pred_stack_proba)
|
||||
actuals.append(int(radiant_win))
|
||||
|
||||
# Подсчитываем правильные предсказания
|
||||
if pred1 == radiant_win:
|
||||
correct['model1'] += 1
|
||||
if pred2 == radiant_win:
|
||||
correct['model2'] += 1
|
||||
if pred3 == radiant_win:
|
||||
correct['model3'] += 1
|
||||
if pred_stack == radiant_win:
|
||||
correct['stacking'] += 1
|
||||
|
||||
# Показываем первые 10 матчей
|
||||
if idx < 10:
|
||||
actual_str = "Radiant" if radiant_win else "Dire"
|
||||
print(f"\nМатч #{idx+1} (ID: {match_id}):")
|
||||
print(f" Реальный результат: {actual_str} win")
|
||||
print(f" Модель 1: {pred1_proba*100:.1f}% Radiant ({'✓' if pred1 == radiant_win else '✗'})")
|
||||
print(f" Модель 2: {pred2_proba*100:.1f}% Radiant ({'✓' if pred2 == radiant_win else '✗'})")
|
||||
print(f" Модель 3: {pred3_proba*100:.1f}% Radiant ({'✓' if pred3 == radiant_win else '✗'})")
|
||||
print(f" Стекинг: {pred_stack_proba*100:.1f}% Radiant ({'✓' if pred_stack == radiant_win else '✗'})")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ошибка при обработке матча {match_id}: {e}")
|
||||
continue
|
||||
|
||||
# Итоговая статистика
|
||||
total = len(actuals)
|
||||
|
||||
print("\n" + "="*80)
|
||||
print("ИТОГОВАЯ СТАТИСТИКА")
|
||||
print("="*80)
|
||||
print(f"Всего проверено матчей: {total}\n")
|
||||
|
||||
print("Точность (Accuracy):")
|
||||
print(f" Модель 1 (Heroes + Positions): {correct['model1']}/{total} = {correct['model1']/total*100:.2f}%")
|
||||
print(f" Модель 2 (Bag of Heroes): {correct['model2']}/{total} = {correct['model2']/total*100:.2f}%")
|
||||
print(f" Модель 3 (With Players): {correct['model3']}/{total} = {correct['model3']/total*100:.2f}%")
|
||||
print(f" Мета-модель (Stacking): {correct['stacking']}/{total} = {correct['stacking']/total*100:.2f}%")
|
||||
|
||||
# Расчёт AUC
|
||||
from sklearn.metrics import roc_auc_score
|
||||
|
||||
print("\nAUC (Area Under ROC Curve):")
|
||||
try:
|
||||
auc1 = roc_auc_score(actuals, predictions['model1'])
|
||||
print(f" Модель 1 (Heroes + Positions): {auc1:.4f}")
|
||||
except:
|
||||
print(f" Модель 1 (Heroes + Positions): N/A")
|
||||
|
||||
try:
|
||||
auc2 = roc_auc_score(actuals, predictions['model2'])
|
||||
print(f" Модель 2 (Bag of Heroes): {auc2:.4f}")
|
||||
except:
|
||||
print(f" Модель 2 (Bag of Heroes): N/A")
|
||||
|
||||
try:
|
||||
auc3 = roc_auc_score(actuals, predictions['model3'])
|
||||
print(f" Модель 3 (With Players): {auc3:.4f}")
|
||||
except:
|
||||
print(f" Модель 3 (With Players): N/A")
|
||||
|
||||
try:
|
||||
auc_stack = roc_auc_score(actuals, predictions['stacking'])
|
||||
print(f" Мета-модель (Stacking): {auc_stack:.4f}")
|
||||
except:
|
||||
print(f" Мета-модель (Stacking): N/A")
|
||||
|
||||
print("\n" + "="*80)
|
||||
73
update_models.sh
Executable file
73
update_models.sh
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Скрипт для обновления базы данных и переобучения моделей
|
||||
|
||||
set -e # Остановка при ошибке
|
||||
|
||||
echo "======================================"
|
||||
echo "Начало обновления моделей"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# Активация виртуального окружения
|
||||
source .venv/bin/activate
|
||||
|
||||
# 1. Парсинг про матчей
|
||||
echo "======================================"
|
||||
echo "1. Парсинг про матчей..."
|
||||
echo "======================================"
|
||||
python start/parse_pro_matches.py
|
||||
echo ""
|
||||
|
||||
# 2. Парсинг деталей про матчей
|
||||
echo "======================================"
|
||||
echo "2. Парсинг деталей про матчей..."
|
||||
echo "======================================"
|
||||
python start/parse_pro_details_match.py
|
||||
echo ""
|
||||
|
||||
# 3. Построение датасета
|
||||
echo "======================================"
|
||||
echo "3. Построение датасета из БД..."
|
||||
echo "======================================"
|
||||
python educationML/build_dataset_pro.py
|
||||
echo ""
|
||||
|
||||
# 4. Обучение модели Long-Format (Heroes + Positions)
|
||||
echo "======================================"
|
||||
echo "4. Обучение модели Long-Format..."
|
||||
echo "======================================"
|
||||
python educationML/train_model_pro.py
|
||||
echo ""
|
||||
|
||||
# 5. Обучение модели Bag of Heroes
|
||||
echo "======================================"
|
||||
echo "5. Обучение модели Bag of Heroes..."
|
||||
echo "======================================"
|
||||
python educationML/train_model_bag_of_heroes.py
|
||||
echo ""
|
||||
|
||||
# 6. Построение датасета с игроками
|
||||
echo "======================================"
|
||||
echo "6. Построение датасета с игроками..."
|
||||
echo "======================================"
|
||||
python educationML/build_dataset_with_players.py
|
||||
echo ""
|
||||
|
||||
# 7. Обучение модели With Players
|
||||
echo "======================================"
|
||||
echo "7. Обучение модели With Players..."
|
||||
echo "======================================"
|
||||
python educationML/train_model_with_players.py
|
||||
echo ""
|
||||
|
||||
# 8. Обучение мета-модели (Stacking)
|
||||
echo "======================================"
|
||||
echo "8. Обучение мета-модели (Stacking)..."
|
||||
echo "======================================"
|
||||
python educationML/train_model_stacking.py
|
||||
echo ""
|
||||
|
||||
echo "======================================"
|
||||
echo "✅ Все модели успешно обновлены!"
|
||||
echo "======================================"
|
||||
9
лиги.txt
Normal file
9
лиги.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
18038 - FISSURE PLAYGROUND 2 - Closed Qualifiers - EEU
|
||||
//18667 - FISSURE PLAYGROUND 2 - Closed Qualifiers - China
|
||||
//18668 - FISSURE PLAYGROUND 2 - Closed Qualifiers - Americas
|
||||
//18700 - FISSURE PLAYGROUND 2 - Closed Qualifiers - Americas (SA)
|
||||
//18702 - RES Unchained - A Blast Dota Slam IV Qualifier EU
|
||||
//18704 - RES Unchained - A Blast Dota Slam IV Qualifier SEA
|
||||
//18706 - BLAST Slam IV: China Closed Qualifier
|
||||
18863 - FISSURE PLAYGROUND 2
|
||||
18920 - PGL Wallachia 2025 Season 6"
|
||||
Reference in New Issue
Block a user