fruitpicker01 commited on
Commit
01414bf
·
verified ·
1 Parent(s): 9800633

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -35
app.py CHANGED
@@ -15,7 +15,7 @@ def read_and_process_data(url, user_name):
15
  Возвращает:
16
  1) unique_count: количество уникальных SMS (по gender, generation, industry, opf)
17
  2) df_daily: дата, пользователь, дневное кол-во уникальных SMS (НЕ накопленное),
18
- но уже после удаления дубликатов по 4 столбцам.
19
  """
20
  df = pd.read_csv(url, na_values=["Не выбрано"])
21
  cols = ["gender", "generation", "industry", "opf", "timestamp"]
@@ -57,12 +57,17 @@ def process_data():
57
 
58
  # Генерируем HTML-прогресс-бары
59
  def get_progress_bar(label, abs_val, pct):
 
 
 
 
 
60
  return f"""
61
  <div style='margin-bottom: 1em;'>
62
  <div><strong>{label}</strong></div>
63
  <div style='width: 100%; background-color: #ddd; text-align: left;'>
64
  <div style='width: {pct}%; background-color: #4CAF50; padding: 5px 0;'>
65
- &nbsp;{abs_val} SMS ({pct}%)
66
  </div>
67
  </div>
68
  </div>
@@ -81,13 +86,10 @@ def process_data():
81
  daily_all = daily_all.dropna(subset=["date"])
82
 
83
  # Считаем кумулятивное количество SMS отдельно для каждого пользователя
84
- # Для этого сначала отсортируем по user + date
85
  daily_all = daily_all.sort_values(by=["user", "date"])
86
- # Группируем по user, считаем cumsum
87
  daily_all["cumulative"] = daily_all.groupby("user")["count"].cumsum()
88
 
89
- # Чтобы отразить "Всего", добавим user="Всего",
90
- # суммируя по каждой дате. Потом возьмём кумулятивную сумму этой суммы
91
  total_by_date = daily_all.groupby("date")["count"].sum().reset_index(name="count")
92
  total_by_date = total_by_date.sort_values(by="date")
93
  total_by_date["cumulative"] = total_by_date["count"].cumsum()
@@ -96,72 +98,72 @@ def process_data():
96
  # Объединим с daily_all
97
  daily_all_final = pd.concat([daily_all, total_by_date], ignore_index=True)
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  # Строим накопительный (кумулятивный) график (линии)
100
- # Используем Plotly, делая line chart
101
  fig = px.line(
102
  daily_all_final,
103
  x="date",
104
  y="cumulative",
105
  color="user",
106
- title="Количество SMS",
107
  labels={
108
  "date": "Дата",
109
  "cumulative": "Накопительное количество SMS",
110
  "user": "Пользователь"
111
- }
 
 
112
  )
113
 
114
- # Прогноз с помощью Prophet (будем прогнозировать "Всего" до 28.02.2025)
115
- # Берём total_by_date (уже есть 'date', 'cumulative')
116
  forecast_fig = None
117
  if len(total_by_date) > 1:
118
- # Prophet требует колонки ds, y
119
  df_prophet = total_by_date[["date", "cumulative"]].copy()
120
  df_prophet.columns = ["ds", "y"]
121
  df_prophet["ds"] = pd.to_datetime(df_prophet["ds"])
122
 
123
- # Создаём и обучаем модель
124
  model = Prophet()
125
  model.fit(df_prophet)
126
 
127
- # Создаём DataFrame для будущего (до 28.02.2025)
128
- future = model.make_future_dataframe(periods=0) # сначала без будущего
129
  last_date = df_prophet["ds"].max()
130
- # Посчитаем, сколько дней до 28.02.2025
131
  end_date = pd.to_datetime("2025-02-28")
132
  additional_days = (end_date - last_date).days
133
  if additional_days > 0:
134
  future = model.make_future_dataframe(periods=additional_days)
135
 
136
- # Прогноз
137
  forecast = model.predict(future)
138
 
139
- # Построим график: отобразим исторические данные + прогноз
140
- # Можно с plotly, чтобы добавить пунктир.
141
- # Для наглядности создадим merge таблицу:
142
- # ds, y (история), yhat (прогноз) и т.д.
143
  df_plot = pd.merge(
144
  forecast[["ds", "yhat"]],
145
  df_prophet[["ds", "y"]],
146
  on="ds",
147
  how="left"
148
  )
 
 
149
 
150
- # Чтобы отобразить пунктиром прогноз, разделим:
151
- # - где y есть (история)
152
- # - где y нет (будущее)
153
- df_history = df_plot.dropna(subset=["y"])
154
- df_future = df_plot[df_plot["y"].isna()]
155
-
156
  forecast_fig = px.line(
157
  df_history,
158
  x="ds",
159
  y="y",
160
  title="Прогноз до конца февраля 2025 (всего)",
161
- labels={
162
- "ds": "Дата",
163
- "value": "Количество SMS"
164
- }
165
  )
166
  forecast_fig.add_scatter(
167
  x=df_future["ds"],
@@ -170,10 +172,7 @@ def process_data():
170
  name="Прогноз",
171
  line=dict(dash="dash", color="red")
172
  )
173
- forecast_fig.update_layout(
174
- showlegend=True,
175
- legend=dict(x=0, y=1)
176
- )
177
 
178
  return (bars_html, fig, forecast_fig)
179
 
 
15
  Возвращает:
16
  1) unique_count: количество уникальных SMS (по gender, generation, industry, opf)
17
  2) df_daily: дата, пользователь, дневное кол-во уникальных SMS (НЕ накопленное),
18
+ уже после удаления дубликатов по 4 столбцам.
19
  """
20
  df = pd.read_csv(url, na_values=["Не выбрано"])
21
  cols = ["gender", "generation", "industry", "opf", "timestamp"]
 
57
 
58
  # Генерируем HTML-прогресс-бары
59
  def get_progress_bar(label, abs_val, pct):
60
+ # Определяем "ёмкость"
61
+ if label in ["Даша", "Лера", "Света"]:
62
+ capacity = 234
63
+ else:
64
+ capacity = 702
65
  return f"""
66
  <div style='margin-bottom: 1em;'>
67
  <div><strong>{label}</strong></div>
68
  <div style='width: 100%; background-color: #ddd; text-align: left;'>
69
  <div style='width: {pct}%; background-color: #4CAF50; padding: 5px 0;'>
70
+ &nbsp;{abs_val} SMS ({pct}% из {capacity})
71
  </div>
72
  </div>
73
  </div>
 
86
  daily_all = daily_all.dropna(subset=["date"])
87
 
88
  # Считаем кумулятивное количество SMS отдельно для каждого пользователя
 
89
  daily_all = daily_all.sort_values(by=["user", "date"])
 
90
  daily_all["cumulative"] = daily_all.groupby("user")["count"].cumsum()
91
 
92
+ # Чтобы отразить "Всего", добавим user="Всего"
 
93
  total_by_date = daily_all.groupby("date")["count"].sum().reset_index(name="count")
94
  total_by_date = total_by_date.sort_values(by="date")
95
  total_by_date["cumulative"] = total_by_date["count"].cumsum()
 
98
  # Объединим с daily_all
99
  daily_all_final = pd.concat([daily_all, total_by_date], ignore_index=True)
100
 
101
+ # Определим порядок легенды, отсортировав по последнему кумулятивному значению
102
+ # (у кого больше — тот выше)
103
+ last_values = daily_all_final.groupby("user")["cumulative"].last().sort_values(ascending=False)
104
+ sorted_users = last_values.index.tolist() # в порядке убывания
105
+
106
+ # Явно зададим цвета
107
+ color_map = {
108
+ "Даша": "#1f77b4", # синий
109
+ "Лера": "#2ca02c", # зелёный
110
+ "Света": "#d62728", # красный
111
+ "Всего": "#9467bd" # фиолетовый
112
+ }
113
+
114
  # Строим накопительный (кумулятивный) график (линии)
 
115
  fig = px.line(
116
  daily_all_final,
117
  x="date",
118
  y="cumulative",
119
  color="user",
120
+ title="Кумулятивное количество уникальных SMS",
121
  labels={
122
  "date": "Дата",
123
  "cumulative": "Накопительное количество SMS",
124
  "user": "Пользователь"
125
+ },
126
+ category_orders={"user": sorted_users}, # порядок в легенде
127
+ color_discrete_map=color_map
128
  )
129
 
130
+ # Прогноз с помощью Prophet (делаем для "Всего" до 28.02.2025)
 
131
  forecast_fig = None
132
  if len(total_by_date) > 1:
 
133
  df_prophet = total_by_date[["date", "cumulative"]].copy()
134
  df_prophet.columns = ["ds", "y"]
135
  df_prophet["ds"] = pd.to_datetime(df_prophet["ds"])
136
 
 
137
  model = Prophet()
138
  model.fit(df_prophet)
139
 
140
+ # Рассчитаем, сколько дней до 28.02.2025
141
+ future = model.make_future_dataframe(periods=0) # на случай, если уже после
142
  last_date = df_prophet["ds"].max()
 
143
  end_date = pd.to_datetime("2025-02-28")
144
  additional_days = (end_date - last_date).days
145
  if additional_days > 0:
146
  future = model.make_future_dataframe(periods=additional_days)
147
 
 
148
  forecast = model.predict(future)
149
 
150
+ # Сопоставим исторические данные и прогноз
 
 
 
151
  df_plot = pd.merge(
152
  forecast[["ds", "yhat"]],
153
  df_prophet[["ds", "y"]],
154
  on="ds",
155
  how="left"
156
  )
157
+ df_history = df_plot.dropna(subset=["y"]) # исторические точки
158
+ df_future = df_plot[df_plot["y"].isna()] # будущее
159
 
160
+ # Отдельный график
 
 
 
 
 
161
  forecast_fig = px.line(
162
  df_history,
163
  x="ds",
164
  y="y",
165
  title="Прогноз до конца февраля 2025 (всего)",
166
+ labels={"ds": "Дата", "y": "Накопленное число SMS"}
 
 
 
167
  )
168
  forecast_fig.add_scatter(
169
  x=df_future["ds"],
 
172
  name="Прогноз",
173
  line=dict(dash="dash", color="red")
174
  )
175
+ forecast_fig.update_layout(showlegend=True)
 
 
 
176
 
177
  return (bars_html, fig, forecast_fig)
178