import streamlit as st import pandas as pd import numpy as np import datetime from datetime import timedelta import pandas as pd import numpy as np # from datetime import datetime import matplotlib.pyplot as plt from statsmodels.tsa.seasonal import seasonal_decompose from statsmodels import api as sm from statsmodels.graphics import tsaplots from statsmodels.tsa.statespace.sarimax import SARIMAX pd.options.display.float_format = '{:.2f}'.format st.write('Калькулятор для Дениса') # import streamlit as st st.sidebar.title('Выбор параметров для расчета влияния фичи') with st.sidebar: count_features = st.selectbox( "Введите количество фичей, влияние которых желаете оценить", options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], key=f"4") list_with_data_by_features = [None for i in range(count_features)] for i in range(count_features): list_obout_features = [None for i in range(7)] st.subheader(f'Введите данные по фиче #{i+1}') count_view = st.number_input( "Введите охват аудитории - сколько пользователей увидят Вашу фичу/виджет/баннер", min_value=0, # Минимальное значение step=1, # Шаг единицы format='%d', # Формат для целых чисел # max_value=(df1['ЗП в вакансии'].max() - 50000) # ("IT", "Продажи"), value = 1, key = f"2{i}" ) # if count_view: list_obout_features[0] = count_view ctr = st.number_input( "Конверсия в клик", value = 0.03, key = f"22{i}" ) list_obout_features[1] = ctr # dict_with_data[f"i"]['ctr'] = ctr ctr_connect = st.number_input( "Конверсия в подключение услуги", value = 0.05, key = f"26{i}" ) list_obout_features[2] = ctr_connect money = st.selectbox( "Хотите ли Вы указать значение среднего чека или при расчете брать прогнозируемое значений", options=["Выставлю сам", "Использовать прогноз"], key = f"266{i}", index=None, ) # dict_with_data[f"i"]['money'] = None if money == 'Выставлю сам': money_self = st.number_input( "Введите значение среднего чека", value = 1, key = f"267{i}" ) # dict_with_data[f"i"]['money'] = money_self list_obout_features[3] = money_self list_obout_features[6] = money duration = st.selectbox( "Введите количество месяцев, на протяжении которых желаете оценивать влияние фичи", options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], key = f"2677{i}") # dict_with_data[f"i"]['duration'] = duration list_obout_features[4] = duration # min_value=0, # Минимальное значение # step=1, # Шаг единицы # format='%d', # Формат для целых чисел # # max_value=(df1['ЗП в вакансии'].max() - 50000) # # ("IT", "Продажи") date_start = st.date_input("Выберите дату старта акции:", datetime.date(2024, 10, 1), key = f"26i7{i}") list_obout_features[5] = date_start st.write("Вы выбрали дату:", date_start) list_with_data_by_features[i] = list_obout_features # Заголовок приложения st.title("Расчет прогнозных значений моделью SARIMA, с добавлением параментов фичи") st.write("Файл должен содержать 3 колонки: Дата, Оборот, Средний чек") st.write("Если Вы не подгружаете свои данные - расчет производится по дефолтным данным") # Используем file_uploader для загрузки файла uploaded_file = st.file_uploader("Выберите файл Excel", type=["xlsx"]) count_month = st.number_input( "Введите количество месяцев прогноза", min_value=0, # Минимальное значение step=1, # Шаг единицы format='%d', # Формат для целых чисел # max_value=(df1['ЗП в вакансии'].max() - 50000) # ("IT", "Продажи") value=12 ) # Проверяем, был ли загружен файл if uploaded_file is not None: # Читаем файл Excel в DataFrame df = pd.read_excel(uploaded_file) # Отображаем загруженные данные st.write("Загруженные данные:") st.dataframe(df) @st.cache_data def load_file(path): data = pd.read_excel(path) return data @st.cache_data def fit_model(data_list, count_month): seasonal_order = (1, 1, 1, 12) # Настройте параметры сезонности (P, D, Q, s) model = SARIMAX(data_list.dropna(), seasonal_order=seasonal_order) model_fit = model.fit() forecast = model_fit.forecast(steps=count_month) return forecast data = load_file('Файл для построения прогноза.xlsx') data = data.rename(columns={'Оборот по всем копилкам за месяц': 'Оборот', 'Изменение ср чека': 'Средний чек'}) st.dataframe(data, width=1100, height=250) data['Дата'] = pd.to_datetime(data['Дата'], format="%d.%m.%Y") # изменяем тип данных на дату data.set_index('Дата', inplace=True) data = data.rename(columns={'Оборот по всем копилкам за месяц': 'Оборот', 'Изменение ср чека': 'Средний чек'}) # if count_month: # seasonal_order = (1, 1, 1, 12) # Настройте параметры сезонности (P, D, Q, s) # model = SARIMAX(data['Оборот'].dropna(), seasonal_order=seasonal_order) # model_fit = model.fit() # forecast_new = model_fit.forecast(steps=count_month) forecast_new = fit_model(data['Оборот'], count_month) fig, ax = plt.subplots(figsize=(10, 5)) # plt.figure(figsize=(10, 5)) # plt.plot(train['Оборот по всем копилкам за месяц'], label='Train') ax.plot(data['Оборот'], label='Исторические данные', color='orange') ax.plot(forecast_new.index, forecast_new, label='Прогноз', color='green', linestyle='--') ax.set_title('Прогнозирование общего оборота АН с помощью SARIMA') ax.legend() ax.grid() # ax.show() st.pyplot(fig) forecast_chek = fit_model(data['Средний чек'], count_month) # Визуализируем результаты fig, ax = plt.subplots(figsize=(10, 5)) # plt.plot(train['Оборот по всем копилкам за месяц'], label='Train') ax.plot(data['Средний чек'], label='Исторические данные', color='orange') ax.plot(forecast_chek.index, forecast_chek, label='Прогноз', color='green', linestyle='--') ax.set_title('Прогнозирование с помощью SARIMA среднего чека') ax.legend() ax.grid() st.pyplot(fig) st.subheader('Прогнозные значения без влияния фичи с понижающим коэффициентом 0,05') df_no_feature = pd.DataFrame() df_no_feature['Дата'] = forecast_new.index df_no_feature['Оборот поогноз'] = [i*0.95 for i in list(forecast_new)] df_no_feature['Средний чек'] = [i*0.95 for i in list(forecast_chek)] st.dataframe(df_no_feature) st.subheader('Прогнозные значения без влияния фичи без понижения коэффициентов') df_no_feature = pd.DataFrame() df_no_feature['Дата'] = forecast_new.index df_no_feature['Оборот поогноз'] = [i for i in list(forecast_new)] df_no_feature['Средний чек'] = [i for i in list(forecast_chek)] st.dataframe(df_no_feature) list_retention = [0.48, 0.58, 0.52, 0.47, 0.44, 0.42, 0.4, 0.38, 0.37, 0.35, 0.34, 0.33, 0.32, 0.31, 0.30, 0.29, 0.28, 0.27, 0.26, 0.25, 0.24] st.subheader('Визуализация влияния фичи') month_start = date_start # summ_from_feature = 0 # random_colors = ['red', 'blue', 'lightgreen', 'gold', 'slategreay', 'indigo', 'coral', 'plum', 'blue', 'tomato'] # new_summ_with_features = ['red'] if money == 'Выставлю сам': forecast_chek = [money_self for i in range(len(forecast_new))] # for i in range(count_features): # структура list_with_data_by_features: count_view, ctr, ctr_connect, money_self, duration, date_start, sum list_with_colour = ['red', 'blue', 'lightgreen', 'gold', 'plum', 'indigo', 'coral', 'plum', 'blue', 'tomato'] r = 1 oborot = df_no_feature['Оборот поогноз'] for j in list_with_data_by_features: # st.write(j) if j[6] == 'Выставлю сам': forecast_chek = [j[3] for l in range(len(forecast_new))] new_summ_with_features = [] list_retention = list_retention[:duration+1] + [0 for g in range(25)] summ_from_feature = 0 for i in range(len(forecast_new)): # st.write(i) summ_from_feature = 0 # print(f"Сумма прогноза без добавления фичи в период {forecast_new.index[i].date()} -", forecast_new[i]) if (forecast_new.index[i].date() >= j[5]) & ( forecast_new.index[i].date() <= j[5] + timedelta(days=j[4]*30)): # st.write((forecast_new.index[i].date() >= j[5]) & ( # forecast_new.index[i].date() <= j[5] + timedelta(days=180))) # oborot = df_no_feature['Оборот'] summ_from_feature = j[0] * j[1] * j[2] * forecast_chek[i] * list_retention[i] # print("Доп сумма от фичи:", summ_from_feature) # st.write(summ_from_feature) new_summ_with_features.append(summ_from_feature + oborot[i]) # st.write(new_summ_with_features) # i += 1 else: new_summ_with_features.append(oborot[i]) # st.write('new_summ_with_features', type(new_summ_with_features)) # st.write('new_summ_with_features', type(new_summ_with_features)) # st.write(forecast_new) # forecast_new df_no_feature[f'Прогноз с учетом фичи # {r}'] = list(new_summ_with_features) r+=1 oborot = new_summ_with_features # Визуализируем результаты fig, ax = plt.subplots(figsize=(10, 5)) # plt.plot(train['Оборот по всем копилкам за месяц'], label='Train') ax.plot(data['Оборот'], label='Исторические данные', color='orange') ax.plot(forecast_new.index, df_no_feature['Оборот поогноз'], label='Прогноз', color='green', linestyle='--') for k in range(len(list_with_data_by_features)): ax.plot(forecast_new.index, df_no_feature[f'Прогноз с учетом фичи # {k+1}'], label=f'Прогноз с добавлением фичи # {k+1}', color=list_with_colour[k], linestyle='--') ax.set_title('Прогнозирование с помощью SARIMA') ax.legend() ax.grid() st.pyplot(fig) st.subheader('Данные с учетом влияния фичи') # df_no_feature['Прогноз с учетом фичи'] = list(new_summ_with_features) st.dataframe(df_no_feature) st.subheader('Среднемесячные показатели за 2025 год') mask = df_no_feature['Дата'].dt.year == 2025 df_no_feature_2 = df_no_feature[mask] df_no_feature_2.drop(columns={'Дата'}, inplace=True) averages = df_no_feature_2.mean() # averages.columns = ['Средние показатели'] # Вывод результата в одной строке st.dataframe(averages) st.write("Блок тестирования") st.write(list_with_data_by_features)