Spaces:
Runtime error
Runtime error
import pandas as pd | |
import datetime | |
import os | |
import base64 | |
from catboost import CatBoostClassifier, Pool | |
import streamlit as st | |
st.set_page_config( | |
page_title="Hockey Match Prediction", | |
page_icon="🏒", | |
layout="wide" | |
) | |
# Функция загрузки данных | |
def load_data(): | |
df = pd.read_csv("rink_master_47816_wteams.csv") | |
df['gameDate'] = pd.to_datetime(df['gameDate']) | |
# Извлечение года и месяца, и создание нового столбца Season | |
df["Year"] = df["gameDate"].dt.year | |
df["Month"] = df["gameDate"].dt.month | |
df["Season"] = df["Year"].astype(str) + "-" + (df["Year"] + 1).astype(str) | |
# Создание SeasonWeight и NormalizedWeight | |
seasons = df["Season"].unique() | |
season_weights = {season: i + 1 for i, season in enumerate(sorted(seasons))} | |
max_season_weight = max(season_weights.values()) | |
min_season_weight = min(season_weights.values()) | |
df["SeasonWeight"] = df["Season"].map(season_weights) | |
df["NormalizedWeight"] = (df["SeasonWeight"] - min_season_weight) / ( | |
max_season_weight - min_season_weight | |
) | |
df["Weights"] = df.groupby("Season")["NormalizedWeight"].transform("mean") | |
return df | |
data = load_data() | |
# Определение результата | |
def determine_result(row): | |
if ( | |
row["Win"] != 0 | |
or row["regulationWins"] != 0 | |
or row["regulationAndOtWins"] != 0 | |
or row["shootoutWins"] != 0 | |
): | |
return 1 # Победа | |
elif row["Loss"] != 0 or row["OTLoss"] != 0: | |
return 0 # Поражение | |
else: | |
return -1 # Неопределено | |
data["Result"] = data.apply(determine_result, axis=1) | |
# Маппинг команд на числовые значения | |
fullname_to_code = { | |
"New Jersey Devils": 1, "New York Islanders": 2, "New York Rangers": 3, | |
"Philadelphia Flyers": 4, "Pittsburgh Penguins": 5, "Boston Bruins": 6, | |
"Buffalo Sabres": 7, "Montréal Canadiens": 8, "Ottawa Senators": 9, | |
"Toronto Maple Leafs": 10, "Carolina Hurricanes": 11, "Florida Panthers": 12, | |
"Tampa Bay Lightning": 13, "Washington Capitals": 14, "Chicago Blackhawks": 15, | |
"Detroit Red Wings": 16, "Nashville Predators": 17, "St. Louis Blues": 18, | |
"Calgary Flames": 19, "Colorado Avalanche": 20, "Edmonton Oilers": 21, | |
"Vancouver Canucks": 22, "Anaheim Ducks": 23, "Dallas Stars": 24, | |
"Los Angeles Kings": 25, "San Jose Sharks": 26, "Columbus Blue Jackets": 27, | |
"Minnesota Wild": 28, "Winnipeg Jets": 29, "Arizona Coyotes": 30, | |
"Vegas Golden Knights": 31, "Seattle Kraken": 32, | |
} | |
data["Team"] = data["Team"].map(fullname_to_code) | |
data["Opponent"] = data["Opponent"].map(fullname_to_code) | |
# Разделение данных на обучающую и тестовую выборки | |
train = data[data["gameDate"] < "2023-10-10"] | |
test = data[data["gameDate"] >= "2023-10-10"] | |
# Определение колонок, которые будут удалены | |
features_to_drop = [ | |
"Result", "gameDate", "gameID", "gamesPlayed", "Win", "Loss", "Tie", | |
"OTLoss", "points", "pointPct", "regulationWins", "regulationAndOtWins", | |
"shootoutWins", "goalsFor", "goalsAgainst", "goalsForPerGame", | |
"goalsAgainstPerGame", "powerPlayPct", "penaltyKillPct", "powerPlayNetPct", | |
"penaltyKillNetPct", "shotsForPerGame", "shotsAgainstPerGame", | |
"faceoffWinPct", "Year", "Month", "Season", "NonRegulationTime", | |
"SeasonWeight", "NormalizedWeight" | |
] | |
code_to_fullname = {v: k for k, v in fullname_to_code.items()} # Создание обратного маппинга | |
# Убедитесь, что колонки для удаления существуют в данных | |
features_to_drop = [col for col in features_to_drop if col in train.columns] | |
# Обновление признаков, включая Weight | |
X_train = train.drop(columns=features_to_drop) | |
y_train = train["Result"] | |
X_test = test.drop(columns=features_to_drop) | |
y_test = test["Result"] | |
# Функция для загрузки модели CatBoost | |
def load_catboost_model(file_path): | |
try: | |
model = CatBoostClassifier() | |
model.load_model(file_path) | |
# st.write(f"Тип загруженной модели: {type(model)}") # Для отладки | |
return model | |
except Exception as e: | |
st.write(f"Ошибка при загрузке модели CatBoost: {e}") | |
return None | |
model_path = "catboost_model.cb" | |
model = load_catboost_model(model_path) | |
# # Проверка признаков | |
# model_feature_names = model.feature_names_ | |
# st.write("Признаки модели:", model_feature_names) | |
# st.write("Признаки в данных для обучения:", X_train.columns.tolist()) | |
# Маппинг для homeRoad | |
home_road_mapping = { | |
1: "На выезде", | |
0: "Дома" | |
} | |
win_mapping = { | |
1: "Победа", | |
0: "Не победа: Поражение или Ничья" | |
} | |
# Функция для предсказания исхода | |
def predict_winner(row, model): | |
# print(f"Тип модели в predict_winner: {type(model)}") # Для отладки | |
try: | |
# Подготовка входных данных | |
features = pd.DataFrame([row], columns=X_train.columns).fillna(0) | |
# Создание объекта Pool для CatBoost | |
pool = Pool(data=features, feature_names=X_train.columns.tolist()) | |
# Сделайте предсказание | |
prediction = model.predict(pool) | |
prediction_proba = model.predict_proba(pool) | |
# st.write(f"Предсказание: {prediction}, вероятность: {prediction_proba}") # Для отладки | |
# Верните результат и вероятность | |
result = 'Победа с вероятностью' if prediction[0] == 1 else 'Не победа: Поражение или Ничья с вероятностью' | |
probability = prediction_proba[0][1] if prediction[0] == 1 else prediction_proba[0][0] | |
return result, probability | |
except Exception as e: | |
print(f"Ошибка при предсказании: {e}") | |
return "Ошибка" | |
st.markdown( | |
""" | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Anton:wght@400;700&display=swap'); | |
.title { | |
font-size: 48px; | |
font-weight: 700; | |
color: #0A74DA; /* Темно-голубой цвет */ | |
font-family: 'Anton', sans-serif; /* шрифт Anton */ | |
text-transform: uppercase; /* все буквы заглавные */ | |
text-shadow: 2px 2px 4px #000000; /* тень текста */ | |
margin-bottom: 20px; | |
text-align: center; /* Центрирование текста */ | |
} | |
.title-container { | |
background: rgba(255, 255, 255, 1.0); /* Белый фон */ | |
padding: 10px; | |
border-radius: 10px; | |
margin-bottom: 20px; | |
display: inline-block; | |
width: 100%; /* Занимает всю ширину, чтобы текст был по центру */ | |
} | |
.stApp { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
min-height: 100vh; | |
flex-direction: column; | |
} | |
.stMarkdown, .stTable, .stDataFrame, .stForm, .stTextInput, .stDateInput, .stSelectbox { | |
background: rgba(255, 255, 255, 1.0); /* Белый фон */ | |
border-radius: 10px; | |
padding: 10px; | |
margin-bottom: 20px; | |
display: inline-block; /* Чтобы контейнеры не растягивались */ | |
max-width: fit-content; /* Максимальная ширина по содержимому */ | |
} | |
</style> | |
""", | |
unsafe_allow_html=True | |
) | |
st.markdown('<div class="title-container"><h1 class="title">Предсказание исходов хоккейных матчей NHL 🏒🥅🏆</h1></div>', unsafe_allow_html=True) | |
# Добавление навигации по страницам | |
st.sidebar.markdown("## Навигация") | |
page = st.sidebar.selectbox("Выберите страницу", ["Основная", "Графики"]) | |
if page == "Основная": | |
st.sidebar.title("Поиск по фильтрам") | |
selected_date = st.sidebar.date_input("Выберите дату", value=datetime.date(2023, 10, 8), key="date_input") | |
selected_team = st.sidebar.selectbox("Выберите команду", options=["Все"] + list(fullname_to_code.keys()), key="team_select") | |
selected_opponent = st.sidebar.selectbox("Выберите оппонента", options=["Все"] + list(fullname_to_code.keys()), key="opponent_select") | |
selected_home_road = st.sidebar.selectbox("Где играет команда?", options=["Все", "Дома", "На выезде"], key="home_road_select") | |
# Фильтрация данных по выбранным критериям | |
filtered_data = data[data['gameDate'] == pd.to_datetime(selected_date)] | |
if selected_team != "Все": | |
filtered_data = filtered_data[filtered_data['Team'] == fullname_to_code[selected_team]] | |
if selected_opponent != "Все": | |
filtered_data = filtered_data[filtered_data['Opponent'] == fullname_to_code[selected_opponent]] | |
if selected_home_road != "Все": | |
filtered_data = filtered_data[filtered_data['homeRoad'] == (1 if selected_home_road == "Да" else 0)] | |
if not filtered_data.empty: | |
st.write(f"Игры на {selected_date}:") | |
col1, col2, col3, col4, col5 = st.columns(5) | |
col1.write("Команда") | |
col2.write("Оппонент") | |
col3.write("Где играет команда?") | |
col4.write("Актуальный исход матча") | |
col5.write("Предсказание") | |
for index, row in filtered_data.iterrows(): | |
col1, col2, col3, col4, col5 = st.columns(5) | |
col1.write(code_to_fullname[row['Team']]) | |
col2.write(code_to_fullname[row['Opponent']]) | |
col3.write(home_road_mapping.get(row['homeRoad'], 'Неизвестно')) | |
col4.write(win_mapping.get(row['Win'], 'Нет')) | |
if col5.button('Предсказание', key=index): | |
row_dict = row.to_dict() | |
prediction, probability = predict_winner(row_dict, model) | |
st.write(f"Предсказание для игры {code_to_fullname[row['Team']]} vs {code_to_fullname[row['Opponent']]}: {prediction} {probability:.2f}") | |
else: | |
st.write("Нет игр на выбранную дату.") | |
# Установка фонового изображения | |
background_image_path = "7.jpeg" | |
if os.path.exists(background_image_path): | |
with open(background_image_path, "rb") as image_file: | |
encoded_image = base64.b64encode(image_file.read()).decode() | |
st.markdown( | |
f""" | |
<style> | |
.stApp {{ | |
background-image: url("data:image/jpeg;base64,{encoded_image}"); | |
background-size: cover; | |
background-repeat: no-repeat; | |
background-position: center center; | |
}} | |
.stSidebar {{ | |
background: rgba(255, 255, 255, 0.8); | |
}} | |
.stButton {{ | |
background-color: #0A74DA; | |
color: white; | |
}} | |
</style> | |
""", | |
unsafe_allow_html=True | |
) | |
else: | |
st.error(f"Изображение не найдено по пути: {background_image_path}") | |
elif page == "Графики": | |
st.title("Графики и Анализ") | |
# Импортирование библиотек для графиков | |
import matplotlib.pyplot as plt | |
import seaborn as sns | |
# Отображение локального изображения | |
image_path = "graphs/1.png" # Укажите путь к вашему изображению | |
st.image(image_path, use_column_width=True) | |
# Отображение второго локального изображения | |
image_path2 = "graphs/2.png" # Укажите путь ко второму изображению | |
st.image(image_path2, use_column_width=True) | |
image_path3 = "graphs/3.png" # Укажите путь ко второму изображению | |
st.image(image_path3, use_column_width=True) | |
st.write("Процент побед в домашних играх: 54.55%") | |
st.write("Процент побед в выездных играх: 45.45%") | |
st.write("Домашняя арена увеличивает вероятность победы на: 9.10%") | |
image_path4 = "graphs/4.png" # Укажите путь ко второму изображению | |
st.image(image_path4, use_column_width=True) | |
image_path5 = "graphs/5.png" # Укажите путь ко второму изображению | |
st.image(image_path5, use_column_width=True) | |