CoolFace
Apppublic

53Devon/Dota_2_Machine_Learning

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
prediction.py552 linesDownload Raw Back to root
1# import library
2import streamlit as st
3import pickle
4import json
5import pandas as pd
6import numpy as np
7
8with open("preprocessor.pkl", "rb") as file:
9    preprocessor = pickle.load(file)
10
11with open("model.pkl", "rb") as file:
12    model = pickle.load(file)
13
14with open("heroes.txt", "r") as file:
15    heroes = json.load(file)
16
17with open("team.txt", "r") as file:
18    team = json.load(file)
19
20
21def cosine_sim(vect1, vect2):
22    norm_1 = np.linalg.norm(vect1)
23    norm_2 = np.linalg.norm(vect2)
24
25    cos_sim = (vect1 @ vect2) / (norm_1 * norm_2)
26    return cos_sim
27
28
29def recsys(df, index_data_inf, top_N):
30    index_rec = []
31    cossim = pd.Series(
32        [cosine_sim(df.loc[index_data_inf], x) for x in df.values], index=df.index
33    ).drop(index=index_data_inf)
34    for data_idx in cossim.sort_values(ascending=False)[:top_N].index:
35        index_rec.append(data_idx)
36    return index_rec
37
38
39def run():
40    st.title("Halaman Prediksi & Rekomendasi")
41    st.image("prediction_pic.jpg")
42
43    st.markdown(
44        '<div style="text-align: justify;; text-indent: 40px;">Halaman ini bertujuan untuk memprediksi kemenangan tim berdasarkan informasi komposisi, detail tim dan lain-lain. Diharapkan dari prediksi ini pihak manajemen dan pelatih dapat membuat strategi dan <i>threshold</i> batas agar potensi kemenangan tim semakin besar.<br><br>',
45        unsafe_allow_html=True,
46    )
47
48    tab_1, tab_2 = st.tabs(
49        [
50            "Prediksi Kemenangan Tim Lawan",
51            "Rekomendasi Lineup Terhadap Musuh",
52        ]
53    )
54    with tab_1:
55        with st.form("Form Result Prediction 1"):
56            st.subheader("Prediksi Kemenangan Tim Musuh")
57
58            st.markdown(
59                "Model prediksi yang digunakan adalah Support Vector Machine (SVM) untuk menghasilkan prediksi akan kemenangan dari tim lawan berdasarkan pada _feature_ yang telah diolah."
60            )
61            input_tournament = st.text_input(
62                "Tournament Name",
63                help="Field ini memungkinkan pengguna untuk memasukkan nama turnamen yang diinginkan.",
64            )
65
66            input_team = st.selectbox(
67                "Nama Tim Lawan",
68                sorted(team),
69                help="Field ini memungkinkan pengguna untuk mengisi nama tim yang akan diprediksi.",
70            )
71
72            input_side = st.selectbox(
73                "Sisi tim Lawan",
74                ("dire", "radiant"),
75                index=0,
76                help="Field ini memungkinkan pengguna untuk mengisi bagian sisi yang dipilih oleh pengguna berupa dire atau radiant.",
77            )
78
79            input_score = st.slider("Target Skor Akhir Lawan", min_value=0, value=0)
80
81            input_duration = st.slider(
82                "Durasi dari Pertandingan (Menit)", min_value=0, value=0
83            )
84
85            input_hero = st.multiselect(
86                "Komposisi Karakter dalam Tim (hero lineup)",
87                heroes,
88                help="Field ini berisi nama karakter yang dipilih oleh tim dimulai dari nama karakter pertama sampai terakhir dipilih.",
89                max_selections=5,
90            )
91
92            name_changes = {
93                "Anti-Mage": "antimage",
94                "Centaur Warrunner": "centaur",
95                "Clockwerk": "rattletrap",
96                "Doom": "doom_bringer",
97                "Io": "wisp",
98                "Lifestealer": "life_stealer",
99                "Magnus": "magnataur",
100                "Nature's Prohpet": "furion",
101                "Necrophos": "necrolyte",
102                "Outworld Devourer": "obsidian_destroyer",
103                "Queen of Pain": "queenofpain",
104                "Shadow Fiend": "nevermore",
105                "Treant Protector": "treant",
106                "Underlord": "abyssal_underlord",
107                "Vengeful Spirit": "vengefulspirit",
108                "Windranger": "windrunner",
109                "Wraith King": "skeleton_king",
110                "Zeus": "zuus",
111            }
112            
113            org_heroes = {name_changes.get(hero, hero) for hero in heroes}
114            hero_images = {
115                hero: f"https://cdn.akamai.steamstatic.com/apps/dota2/images/dota_react/heroes/{hero.lower().replace(' ', '_')}.png"
116                for hero in org_heroes
117            }
118
119            hero_con = [name_changes.get(hero,hero) for hero in input_hero]
120            
121            col1, col2, col3, col4, col5 = st.columns(5)
122
123            col1.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Pertama</div>', unsafe_allow_html=True)
124            col2.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Kedua</div>', unsafe_allow_html=True)
125            col3.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Ketiga</div>', unsafe_allow_html=True)
126            col4.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Keempat</div>', unsafe_allow_html=True)
127            col5.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Kelima</div>', unsafe_allow_html=True)
128
129            cols = st.columns(5)
130            for i in range(5):
131                col = cols[i]
132                if i < len(input_hero):
133                    pic = col.image(hero_images[hero_con[i]], width=120)
134                else:
135                    pic = col.image('block.png', width=120)
136            
137            st.markdown("---")
138
139            col1, col2, coldiv = st.columns((3, 3, 3))
140            how_to = col2.popover("Cara Kerja Model Prediksi")
141            submitted = col1.form_submit_button("Prediksi Hasil Pertandingan")
142
143            if submitted:
144                if len(input_hero) < 5:
145                    st.subheader("Kekurangan Komposisi Karakter")
146                else:
147                    data_inf = {
148                        "TOURNAMENT": input_tournament,
149                        "TEAM": input_team,
150                        "SIDE": input_side,
151                        "HERO_1": input_hero[4],
152                        "HERO_2": input_hero[3],
153                        "HERO_3": input_hero[2],
154                        "HERO_4": input_hero[1],
155                        "HERO_5": input_hero[0],
156                        "SCORE": input_score,
157                    }
158
159                    data_inf = pd.DataFrame([data_inf])
160
161                    data_final = preprocessor.transform(data_inf)
162
163                    pred = model.predict(data_final)
164                    if pred == 1:
165                        st.markdown(
166                            f'<h4>Ketika pertandingan berakhir dengan skor lawan sebesar {input_score} dan komposisi tertera, {input_team} diprediksi <span style="color: green;">Menang</span></h4>',
167                            unsafe_allow_html=True,
168                        )
169                    else:
170                        st.markdown(
171                            f'<h4>Ketika pertandingan berakhir dengan skor lawan sebesar {input_score} dan komposisi tertera, {input_team} diprediksi <span style="color: red;">Kalah</span></h4>',
172                            unsafe_allow_html=True,
173                        )
174
175                    df = pd.read_csv("P1M2_Devon.csv")
176                    df_bar_1 = (
177                        df[["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]]
178                        .stack()
179                        .value_counts()
180                        .reset_index()
181                    )
182                    df_bar_1.columns = ["HERO", "Global Hero Pick"]
183                    df_bar_1["WIN COUNT"] = 0
184                    for index, row in df_bar_1.iterrows():
185                        hero = row["HERO"]
186                        win_count = 0
187                        for col in ["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]:
188                            win_count += (
189                                df[df["RESULT"] == "WIN"][col]
190                                .value_counts()
191                                .get(hero, 0)
192                            )
193                        df_bar_1.at[index, "WIN COUNT"] = win_count
194                    df_bar_1["Global Winrate (%)"] = round(
195                        (df_bar_1["WIN COUNT"] / df_bar_1["Global Hero Pick"] * 100), 2
196                    )
197
198                    df_stat = df_bar_1[
199                        (df_bar_1["HERO"] == input_hero[0])
200                        | (df_bar_1["HERO"] == input_hero[1])
201                        | (df_bar_1["HERO"] == input_hero[2])
202                        | (df_bar_1["HERO"] == input_hero[3])
203                        | (df_bar_1["HERO"] == input_hero[4])
204                    ].sort_values(by="HERO")
205
206                    all_heroes = df[df["TEAM"] == input_team][
207                        ["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]
208                    ]
209                    for hero in heroes:
210                        all_heroes[hero] = all_heroes.apply(
211                            lambda row: int(hero in row.values), axis=1
212                        )
213                    df_stat["Team Hero Pick"] = None
214                    df_stat["Team Hero Winrate (%)"] = None
215                    for hero in df_stat["HERO"]:
216                        pick_count = all_heroes.apply(
217                            lambda row: hero in row.values, axis=1
218                        ).sum()
219                        win_count_team = all_heroes[
220                            all_heroes.apply(
221                                lambda row: hero in row.values
222                                and df.loc[row.name, "RESULT"] == "WIN",
223                                axis=1,
224                            )
225                        ].shape[0]
226                        df_stat.loc[df_stat["HERO"] == hero, "Team Hero Pick"] = (
227                            pick_count
228                        )
229                        df_stat.loc[
230                            df_stat["HERO"] == hero, "Team Hero Winrate (%)"
231                        ] = (
232                            round(win_count_team / pick_count * 100, 2)
233                            if pick_count > 0
234                            else 0
235                        )
236
237                    df_stat.index = np.arange(1, len(df_stat) + 1)
238                    df_stat.rename(columns={"HERO": "Nama Karakter"}, inplace=True)
239                            
240                    st.markdown(
241                        "<h5>Informasi statistik komposisi karakter tim lawan:</h5>",
242                        unsafe_allow_html=True,
243                    )
244                    st.dataframe(df_stat.drop(columns=["WIN COUNT"]))
245
246            if len(input_hero) == 5:
247                with how_to:
248                    st.markdown("##### Langkah-langkah:")
249                    st.markdown("1. Mengubah format data input menjadi dataframe")
250                    data_inf = {
251                        "TOURNAMENT": input_tournament,
252                        "TEAM": input_team,
253                        "SIDE": input_side,
254                        "HERO_1": input_hero[4],
255                        "HERO_2": input_hero[3],
256                        "HERO_3": input_hero[2],
257                        "HERO_4": input_hero[1],
258                        "HERO_5": input_hero[0],
259                        "SCORE": input_score,
260                        "DURATION": input_duration,
261                    }
262
263                    st.dataframe(data_inf)
264
265                    st.markdown(
266                        "2. Melakukan preprocessing data kolom yang dianggap berpengaruh secara statistik menggunakan pipeline yang telah diolah yakni scaling pada data numerikal dan encoding pada data kategorikal"
267                    )
268                    st.markdown(
269                        "3. Pengabunggan hasil pengolahan menjadi sebuah dataframe hasil preprocessing"
270                    )
271                    st.markdown(
272                        "4. Melakukan model prediksi berdasarkan hasil model yang telah dibuat menggunakan pelatihan dataset."
273                    )
274                    st.markdown("5. Menampilkan hasil prediksi")
275
276    with tab_2:
277        with st.form("Form Result Prediction"):
278            st.subheader("Rekomendasi Karakter kepada Tim Aliansi")
279            st.markdown(
280                "Proses rekomendasi ini menggunakan data historis kemenangan lawan tim musuh yang menang dengan memanfaatkan _cosine similarity_ sebagai indeks kemiripan komposisi aliansi agar dapat meningkatkan kemungkinan menang dalam pertandingan."
281            )
282
283            input_team = st.selectbox(
284                "Nama Tim Lawan",
285                sorted(team),
286                help="Field ini memungkinkan pengguna untuk mengisi nama tim lawan.",
287            )
288
289            input_hero = st.multiselect(
290                "Komposisi Karakter dalam Tim Aliansi (hero lineup)",
291                heroes,
292                help="Field ini berisi nama karakter yang dipilih oleh tim dimulai dari nama karakter pertama sampai terakhir dipilih.",
293                max_selections=4,
294            )
295
296            name_changes = {
297                "Anti-Mage": "antimage",
298                "Centaur Warrunner": "centaur",
299                "Clockwerk": "rattletrap",
300                "Doom": "doom_bringer",
301                "Io": "wisp",
302                "Lifestealer": "life_stealer",
303                "Magnus": "magnataur",
304                "Nature's Prohpet": "furion",
305                "Necrophos": "necrolyte",
306                "Outworld Devourer": "obsidian_destroyer",
307                "Queen of Pain": "queenofpain",
308                "Shadow Fiend": "nevermore",
309                "Treant Protector": "treant",
310                "Underlord": "abyssal_underlord",
311                "Vengeful Spirit": "vengefulspirit",
312                "Windranger": "windrunner",
313                "Wraith King": "skeleton_king",
314                "Zeus": "zuus",
315            }
316            
317            org_heroes = {name_changes.get(hero, hero) for hero in heroes}
318            hero_images = {
319                hero: f"https://cdn.akamai.steamstatic.com/apps/dota2/images/dota_react/heroes/{hero.lower().replace(' ', '_')}.png"
320                for hero in org_heroes
321            }
322
323            hero_con = [name_changes.get(hero,hero) for hero in input_hero]
324            
325            col1, col2, col3, col4, col5 = st.columns(5)
326
327            col1.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Pertama</div>', unsafe_allow_html=True)
328            col2.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Kedua</div>', unsafe_allow_html=True)
329            col3.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Ketiga</div>', unsafe_allow_html=True)
330            col4.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Keempat</div>', unsafe_allow_html=True)
331            col5.markdown('<div style="text-align: center;margin-bottom: 10px">Karakter Kelima</div>', unsafe_allow_html=True)
332
333            cols = st.columns(5)
334            for i in range(5):
335                col = cols[i]
336                if i < len(input_hero):
337                    pic = col.image(hero_images[hero_con[i]], width=120)
338                else:
339                    pic = col.image('block.png', width=120)
340            
341            st.write('')
342            
343            col1, col2, coldiv = st.columns((9.5, 14, 9.3))
344            how_to = col2.popover("Cara Kerja Model Rekomendaasi")
345            submitted2 = col1.form_submit_button("Membuat Rekomendasi")
346            detail_rekomendasi_dataframe = coldiv.popover('Detail Rekomendasi')
347            
348            with how_to:
349                st.markdown("##### Langkah-langkah:")
350                st.markdown('1. Melakukan Filter data terkait dengan semua lawan dari tim musuh yang berakhir dalam kondisi menang. ')
351                st.markdown('2. Melakukan input komposisi karakter ke dalam dataframe.')
352                st.markdown('3. Melakukan perhitungan cosine similarity terhadap data input.')
353                st.markdown('4. Mengumpulkan keseluruhan karakter pada 5 data paling mirip.')
354                st.markdown('5. Melakukan pengurutan data berdasarkan jumlah pertemuan karakter pada 5 data tersebut dan persortir berdasarkan global winrate')
355                st.markdown('5. Menampilkan hasil rekomendasi.')
356            
357            if submitted2:
358                if len(input_hero) == 0:
359                    st.markdown(
360                        "<h4>Dibutuhkan minimal 1 pemilihan karakter untuk melihat data historis, rekomendasi berdasarkan statistik sebagai berikut:</h4>",
361                        unsafe_allow_html=True,
362                    )
363                    df = pd.read_csv("P1M2_Devon.csv")
364                    df = df[
365                        (df["MATCH_ID"].isin(df[df["TEAM"] == input_team]["MATCH_ID"]))
366                    ]
367                    df = df[(df["TEAM"] != input_team)]
368
369                    df_bar_1 = (
370                        df[["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]]
371                        .stack()
372                        .value_counts()
373                        .reset_index()
374                    )
375                    df_bar_1.columns = ["Nama Karakter", "Hero Pick"]
376                    df_bar_1["Win Count"] = 0
377                    for index, row in df_bar_1.iterrows():
378                        hero = row["Nama Karakter"]
379                        win_count = 0
380                        for col in ["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]:
381                            win_count += (
382                                df[df["RESULT"] == "WIN"][col]
383                                .value_counts()
384                                .get(hero, 0)
385                            )
386                        df_bar_1.at[index, "Win Count"] = win_count
387                    df_bar_1["Winrate (%)"] = round(
388                        df_bar_1["Win Count"] / df_bar_1["Hero Pick"] * 100, 2
389                    )
390                    df_bar_1.sort_values(
391                        by="Winrate (%)", ascending=False, inplace=True
392                    )
393                    df_bar_1.reset_index(drop=True)
394                    df_bar_1.index = np.arange(1, len(df_bar_1) + 1)
395                    st.dataframe(df_bar_1)
396                else:
397                    df = pd.read_csv("P1M2_Devon.csv")
398                    df_bar_1 = (
399                        df[["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]]
400                        .stack()
401                        .value_counts()
402                        .reset_index()
403                    )
404                    df_bar_1.columns = ["HERO", "Global Hero Pick"]
405                    df_bar_1["WIN COUNT"] = 0
406                    for index, row in df_bar_1.iterrows():
407                        hero = row["HERO"]
408                        win_count = 0
409                        for col in ["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]:
410                            win_count += (
411                                df[df["RESULT"] == "WIN"][col]
412                                .value_counts()
413                                .get(hero, 0)
414                            )
415                        df_bar_1.at[index, "WIN COUNT"] = win_count
416                    df_bar_1["Global Winrate (%)"] = round(
417                        df_bar_1["WIN COUNT"] / df_bar_1["Global Hero Pick"] * 100, 2
418                    )
419
420                    all_heroes = df[
421                        (df["MATCH_ID"].isin(df[df["TEAM"] == input_team]["MATCH_ID"]))
422                        & (df["RESULT"] == "WIN")
423                    ]
424                    all_heroes = all_heroes[(df["TEAM"] != input_team)][
425                        ["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]
426                    ]
427                    for hero in heroes:
428                        all_heroes[hero] = all_heroes.apply(
429                            lambda row: int(hero in row.values), axis=1
430                        )
431                    all_heroes.drop(
432                        columns=["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"],
433                        inplace=True,
434                    )
435                    match len(input_hero):
436                        case 4:
437                            data_inf = {
438                                "HERO_2": input_hero[3],
439                                "HERO_3": input_hero[2],
440                                "HERO_4": input_hero[1],
441                                "HERO_5": input_hero[0],
442                            }
443                            data_inf = pd.DataFrame([data_inf])
444                            for hero in heroes:
445                                data_inf[hero] = data_inf.apply(
446                                    lambda row: int(hero in row.values), axis=1
447                                )
448                            data_inf.drop(
449                                columns=["HERO_2", "HERO_3", "HERO_4", "HERO_5"],
450                                inplace=True,
451                            )
452
453                        case 3:
454                            data_inf = {
455                                "HERO_3": input_hero[2],
456                                "HERO_4": input_hero[1],
457                                "HERO_5": input_hero[0],
458                            }
459                            data_inf = pd.DataFrame([data_inf])
460                            for hero in heroes:
461                                data_inf[hero] = data_inf.apply(
462                                    lambda row: int(hero in row.values), axis=1
463                                )
464                            data_inf.drop(
465                                columns=["HERO_3", "HERO_4", "HERO_5"], inplace=True
466                            )
467
468                        case 2:
469                            data_inf = {
470                                "HERO_4": input_hero[1],
471                                "HERO_5": input_hero[0],
472                            }
473                            data_inf = pd.DataFrame([data_inf])
474                            for hero in heroes:
475                                data_inf[hero] = data_inf.apply(
476                                    lambda row: int(hero in row.values), axis=1
477                                )
478                            data_inf.drop(columns=["HERO_4", "HERO_5"], inplace=True)
479
480                        case 1:
481                            data_inf = {
482                                "HERO_5": input_hero[0],
483                            }
484                            data_inf = pd.DataFrame([data_inf])
485                            for hero in heroes:
486                                data_inf[hero] = data_inf.apply(
487                                    lambda row: int(hero in row.values), axis=1
488                                )
489                            data_inf.drop(columns=["HERO_5"], inplace=True)
490
491                    data_inf.index = pd.RangeIndex(
492                        start=99999, stop=99999 + len(data_inf)
493                    )
494                    df_combine = pd.concat([all_heroes, data_inf], axis=0)
495                    result = recsys(df_combine, 99999, 5)
496                    filtered_df = df.loc[df.index.isin(result)]
497                    filtered_df_stack = (
498                        filtered_df[["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]]
499                        .stack()
500                        .value_counts()
501                        .reset_index()
502                    )
503                    filtered_df_stack = pd.DataFrame(filtered_df_stack)
504                    for hero in filtered_df_stack["index"]:
505                        if any(hero == hero_list for hero_list in input_hero):
506                            filtered_df_stack = filtered_df_stack[
507                                filtered_df_stack["index"] != hero
508                            ]
509                    filtered_df_stack.rename(
510                        columns={"index": "HERO", "count": "Encounter"}, inplace=True
511                    )
512
513                    filtered_df_stack["Global Winrate (%)"] = None
514                    for hero in filtered_df_stack["HERO"]:
515                        filtered_df_stack.loc[
516                            filtered_df_stack["HERO"] == hero, "Global Winrate (%)"
517                        ] = df_bar_1.loc[
518                            df_bar_1["HERO"] == hero, "Global Winrate (%)"
519                        ].values[0]
520
521                    filtered_df_stack.sort_values(
522                        by=["Encounter", "Global Winrate (%)"],
523                        ascending=False,
524                        inplace=True,
525                    )
526                    filtered_df_stack.index = np.arange(1, len(filtered_df_stack) + 1)
527                    filtered_df_stack.rename(
528                        columns={"HERO": "Nama Karakter"}, inplace=True
529                    )
530                    
531                    col1, col2 = st.columns((6,3))
532                    col1.markdown(
533                        "<h4>Rekomendasi Pemilihan Karakter:</h4>",
534                        unsafe_allow_html=True,
535                    )
536                    col1.markdown(f'  1. {filtered_df_stack["Nama Karakter"].iloc[0]}')
537                    col1.markdown(f'  2. {filtered_df_stack["Nama Karakter"].iloc[1]}')
538                    col1.markdown(f'  3. {filtered_df_stack["Nama Karakter"].iloc[2]}')
539                    
540                    st.markdown('<br>', unsafe_allow_html=True)
541                    
542                    with detail_rekomendasi_dataframe:
543                        st.markdown(
544                            '<h4>Detail Informasi Statistik</h4>', unsafe_allow_html=True
545                        )
546                        st.dataframe(filtered_df_stack)
547
548            
549
550if __name__ == "__main__":
551    run()
552