Spaces:
Runtime error
Runtime error
HardWorkingStation
commited on
Commit
•
3a9a180
1
Parent(s):
455282f
Initial commit
Browse files- src/test.ipynb +23 -7
- src/tools.py +91 -10
- src/web_app.py +36 -0
src/test.ipynb
CHANGED
@@ -158,26 +158,42 @@
|
|
158 |
},
|
159 |
{
|
160 |
"cell_type": "code",
|
161 |
-
"execution_count":
|
162 |
"outputs": [
|
163 |
{
|
164 |
"data": {
|
165 |
-
"text/plain": "
|
166 |
},
|
167 |
"metadata": {},
|
168 |
"output_type": "display_data"
|
169 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
170 |
{
|
171 |
"data": {
|
172 |
-
"text/plain": "
|
173 |
},
|
|
|
174 |
"metadata": {},
|
175 |
-
"output_type": "
|
176 |
}
|
177 |
],
|
178 |
"source": [
|
179 |
-
"
|
180 |
-
"display(res.index[1], res[1])"
|
181 |
],
|
182 |
"metadata": {
|
183 |
"collapsed": false,
|
|
|
158 |
},
|
159 |
{
|
160 |
"cell_type": "code",
|
161 |
+
"execution_count": 50,
|
162 |
"outputs": [
|
163 |
{
|
164 |
"data": {
|
165 |
+
"text/plain": "1 50.261167\n0 49.738833\nName: newbie, dtype: float64"
|
166 |
},
|
167 |
"metadata": {},
|
168 |
"output_type": "display_data"
|
169 |
+
}
|
170 |
+
],
|
171 |
+
"source": [
|
172 |
+
"res = data.newbie.value_counts(normalize=True) * 100\n",
|
173 |
+
"display(res)"
|
174 |
+
],
|
175 |
+
"metadata": {
|
176 |
+
"collapsed": false,
|
177 |
+
"pycharm": {
|
178 |
+
"name": "#%%\n"
|
179 |
+
}
|
180 |
+
}
|
181 |
+
},
|
182 |
+
{
|
183 |
+
"cell_type": "code",
|
184 |
+
"execution_count": 54,
|
185 |
+
"outputs": [
|
186 |
{
|
187 |
"data": {
|
188 |
+
"text/plain": "Surburban 19275\nUrban 17098\nRural 6320\nName: zip_code, dtype: int64"
|
189 |
},
|
190 |
+
"execution_count": 54,
|
191 |
"metadata": {},
|
192 |
+
"output_type": "execute_result"
|
193 |
}
|
194 |
],
|
195 |
"source": [
|
196 |
+
"data.zip_code.value_counts()"
|
|
|
197 |
],
|
198 |
"metadata": {
|
199 |
"collapsed": false,
|
src/tools.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
from typing import Any
|
2 |
|
3 |
import pandas as pd
|
|
|
4 |
from sklearn.model_selection import train_test_split
|
5 |
from sklift.datasets import fetch_hillstrom
|
6 |
from catboost import CatBoostClassifier
|
@@ -46,7 +47,7 @@ def get_newbie_plot(data):
|
|
46 |
fig = px.histogram(
|
47 |
data['newbie'],
|
48 |
color=data['newbie'],
|
49 |
-
title='Распределение клиентов по флагу
|
50 |
)
|
51 |
|
52 |
fig.update_xaxes(
|
@@ -61,7 +62,8 @@ def get_newbie_plot(data):
|
|
61 |
|
62 |
fig.update_layout(
|
63 |
showlegend=False,
|
64 |
-
bargap=0.3
|
|
|
65 |
)
|
66 |
|
67 |
fig.update_traces(hovertemplate="Количество клиентов: %{y}")
|
@@ -72,8 +74,8 @@ def get_newbie_plot(data):
|
|
72 |
def get_zipcode_plot(data):
|
73 |
fig = px.histogram(
|
74 |
data['zip_code'],
|
75 |
-
color=data['
|
76 |
-
title='Распределение клиентов по
|
77 |
)
|
78 |
|
79 |
fig.update_xaxes(
|
@@ -86,7 +88,11 @@ def get_zipcode_plot(data):
|
|
86 |
)
|
87 |
|
88 |
fig.update_layout(
|
89 |
-
showlegend=
|
|
|
|
|
|
|
|
|
90 |
bargap=0.3
|
91 |
)
|
92 |
|
@@ -98,8 +104,8 @@ def get_zipcode_plot(data):
|
|
98 |
def get_channel_plot(data):
|
99 |
fig = px.histogram(
|
100 |
data['channel'],
|
101 |
-
color=data['
|
102 |
-
title='Распределение клиентов по
|
103 |
)
|
104 |
|
105 |
fig.update_xaxes(
|
@@ -112,7 +118,11 @@ def get_channel_plot(data):
|
|
112 |
)
|
113 |
|
114 |
fig.update_layout(
|
115 |
-
showlegend=
|
|
|
|
|
|
|
|
|
116 |
bargap=0.3
|
117 |
)
|
118 |
|
@@ -125,7 +135,7 @@ def get_history_segment_plot(data):
|
|
125 |
fig = px.histogram(
|
126 |
data['history_segment'],
|
127 |
color=data['history_segment'],
|
128 |
-
title='Распределение клиентов по
|
129 |
)
|
130 |
|
131 |
fig.update_xaxes(
|
@@ -140,9 +150,80 @@ def get_history_segment_plot(data):
|
|
140 |
|
141 |
fig.update_layout(
|
142 |
showlegend=False,
|
143 |
-
bargap=0.3
|
|
|
144 |
)
|
145 |
|
146 |
fig.update_traces(hovertemplate="Количество клиентов: %{y}")
|
147 |
|
148 |
return fig
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
from typing import Any
|
2 |
|
3 |
import pandas as pd
|
4 |
+
import numpy as np
|
5 |
from sklearn.model_selection import train_test_split
|
6 |
from sklift.datasets import fetch_hillstrom
|
7 |
from catboost import CatBoostClassifier
|
|
|
47 |
fig = px.histogram(
|
48 |
data['newbie'],
|
49 |
color=data['newbie'],
|
50 |
+
title='Распределение клиентов по флагу newbie'
|
51 |
)
|
52 |
|
53 |
fig.update_xaxes(
|
|
|
62 |
|
63 |
fig.update_layout(
|
64 |
showlegend=False,
|
65 |
+
bargap=0.3,
|
66 |
+
margin=dict(l=20, r=10, t=80, b=10)
|
67 |
)
|
68 |
|
69 |
fig.update_traces(hovertemplate="Количество клиентов: %{y}")
|
|
|
74 |
def get_zipcode_plot(data):
|
75 |
fig = px.histogram(
|
76 |
data['zip_code'],
|
77 |
+
color=data['newbie'],
|
78 |
+
title='Распределение клиентов по почтовым индексам'
|
79 |
)
|
80 |
|
81 |
fig.update_xaxes(
|
|
|
88 |
)
|
89 |
|
90 |
fig.update_layout(
|
91 |
+
showlegend=True,
|
92 |
+
legend_orientation="h",
|
93 |
+
legend=dict(x=.66, y=.99, title='Новый клиент'),
|
94 |
+
margin=dict(l=20, r=10, t=80, b=10),
|
95 |
+
hovermode="x",
|
96 |
bargap=0.3
|
97 |
)
|
98 |
|
|
|
104 |
def get_channel_plot(data):
|
105 |
fig = px.histogram(
|
106 |
data['channel'],
|
107 |
+
color=data['newbie'],
|
108 |
+
title='Распределение клиентов по каналам покупки товаров'
|
109 |
)
|
110 |
|
111 |
fig.update_xaxes(
|
|
|
118 |
)
|
119 |
|
120 |
fig.update_layout(
|
121 |
+
showlegend=True,
|
122 |
+
legend_orientation="h",
|
123 |
+
legend=dict(x=.66, y=.99, title='Новый клиент'),
|
124 |
+
margin=dict(l=20, r=10, t=80, b=10),
|
125 |
+
hovermode="x",
|
126 |
bargap=0.3
|
127 |
)
|
128 |
|
|
|
135 |
fig = px.histogram(
|
136 |
data['history_segment'],
|
137 |
color=data['history_segment'],
|
138 |
+
title='Распределение клиентов по количеству $, потраченных в прошлом году'
|
139 |
)
|
140 |
|
141 |
fig.update_xaxes(
|
|
|
150 |
|
151 |
fig.update_layout(
|
152 |
showlegend=False,
|
153 |
+
bargap=0.3,
|
154 |
+
margin=dict(l=20, r=10, t=80, b=10)
|
155 |
)
|
156 |
|
157 |
fig.update_traces(hovertemplate="Количество клиентов: %{y}")
|
158 |
|
159 |
return fig
|
160 |
+
|
161 |
+
|
162 |
+
def get_recency_plot(data):
|
163 |
+
fig = px.histogram(
|
164 |
+
data['recency'],
|
165 |
+
color=data['newbie'],
|
166 |
+
title='Распределение клиентов по количеству месяцев с последней покупки'
|
167 |
+
)
|
168 |
+
|
169 |
+
fig.update_xaxes(
|
170 |
+
title='Месяцев после покупки'
|
171 |
+
)
|
172 |
+
|
173 |
+
fig.update_yaxes(
|
174 |
+
title='Количество клиентов'
|
175 |
+
)
|
176 |
+
|
177 |
+
fig.update_layout(
|
178 |
+
showlegend=True,
|
179 |
+
legend_orientation="h",
|
180 |
+
legend=dict(x=.66, y=.99, title='Новый клиент'),
|
181 |
+
margin=dict(l=20, r=10, t=80, b=10),
|
182 |
+
hovermode="x",
|
183 |
+
bargap=0.3
|
184 |
+
)
|
185 |
+
|
186 |
+
fig.update_traces(hovertemplate="<br>".join(
|
187 |
+
[
|
188 |
+
"Месяцев: %{x}",
|
189 |
+
"Клиентов: %{y}"
|
190 |
+
]
|
191 |
+
)
|
192 |
+
)
|
193 |
+
|
194 |
+
return fig
|
195 |
+
|
196 |
+
|
197 |
+
def get_history_plot(data):
|
198 |
+
fig = px.histogram(
|
199 |
+
data['history'],
|
200 |
+
color=data['newbie'],
|
201 |
+
title='Распределение клиентов по количеству месяцев с последней покупки'
|
202 |
+
)
|
203 |
+
|
204 |
+
fig.update_xaxes(
|
205 |
+
title='Месяцев после покупки'
|
206 |
+
)
|
207 |
+
|
208 |
+
fig.update_yaxes(
|
209 |
+
title='Количество клиентов'
|
210 |
+
)
|
211 |
+
|
212 |
+
fig.update_layout(
|
213 |
+
showlegend=True,
|
214 |
+
legend_orientation="h",
|
215 |
+
legend=dict(x=.66, y=.99, title='Новый клиент'),
|
216 |
+
margin=dict(l=20, r=10, t=80, b=10),
|
217 |
+
hovermode="x",
|
218 |
+
bargap=0.3
|
219 |
+
)
|
220 |
+
|
221 |
+
fig.update_traces(hovertemplate="<br>".join(
|
222 |
+
[
|
223 |
+
'Совершено покупок на: $%{x}',
|
224 |
+
'Количество клиентов: %{y}'
|
225 |
+
]
|
226 |
+
)
|
227 |
+
)
|
228 |
+
|
229 |
+
return fig
|
src/web_app.py
CHANGED
@@ -76,3 +76,39 @@ with st.expander('Развернуть блок анализа данных'):
|
|
76 |
st.write(f'К сегментам \$350-\$500 и \$500-\$750 относится {tmp_res[3]:.2f}% и {tmp_res[4]:.2f}% пользователей соответственно.')
|
77 |
st.write(f'Меньше всего пользователей в сегментах \$750-\$1.000 ({tmp_res[-2]:.2f}%) и \$1.000+ ({tmp_res[-1]:.2f}%).')
|
78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
st.write(f'К сегментам \$350-\$500 и \$500-\$750 относится {tmp_res[3]:.2f}% и {tmp_res[4]:.2f}% пользователей соответственно.')
|
77 |
st.write(f'Меньше всего пользователей в сегментах \$750-\$1.000 ({tmp_res[-2]:.2f}%) и \$1.000+ ({tmp_res[-1]:.2f}%).')
|
78 |
|
79 |
+
tmp_res = list(dataset.recency.value_counts(normalize=True) * 100)
|
80 |
+
st.plotly_chart(tools.get_recency_plot(dataset), use_container_width=True)
|
81 |
+
st.write(f'Большинство клиентов являются активными клиентами платформы, и совершали покупки в течение месяца ({tmp_res[0]:.2f}%)')
|
82 |
+
st.write('Также заметно, что 9 и 10 месяцев назад, много клиентов совершали покупки. Это может свидетельствовать о проведении'
|
83 |
+
'рекламной кампании в это время или чего-то еще.')
|
84 |
+
st.write('Также интересно понаблюдать за долями новых клиентов в данном распределении.')
|
85 |
+
|
86 |
+
st.plotly_chart(tools.get_history_plot(dataset), use_container_width=True)
|
87 |
+
st.markdown('_График интерактивный_')
|
88 |
+
st.write('Абсолютное большинство клиентов тратят \$25-\$35 на покупки, но есть и малая доля тех, кто тратит более \$3.000')
|
89 |
+
st.write('Интересный факт: все покупки более \$500 совершают только новые клиенты')
|
90 |
+
|
91 |
+
st.subheader('Какие данные возьмем для проведения рекламной кампании?')
|
92 |
+
clients_filter = st.radio('На каких клиентов будем воздействовать?', options=['Все', 'Только на новых', 'Только на старых'])
|
93 |
+
|
94 |
+
|
95 |
+
st.write('Выберите класс клиентов, по объему денег, потраченных в прошлом году (history segments).')
|
96 |
+
first_group = st.checkbox('$0-$100', value=True)
|
97 |
+
second_group = st.checkbox('$100-$200', value=True)
|
98 |
+
third_group = st.checkbox('$200-$350', value=True)
|
99 |
+
fourth_group = st.checkbox('$350-$500', value=True)
|
100 |
+
fifth_group = st.checkbox('$500-$750', value=True)
|
101 |
+
sixth_group = st.checkbox('$750-$1.000', value=True)
|
102 |
+
seventh_group = st.checkbox('$1.000+', value=True)
|
103 |
+
|
104 |
+
st.write('Каких пользователей по почтовому коду выберем')
|
105 |
+
surburban = st.checkbox('Surburban', value=True)
|
106 |
+
urban = st.checkbox('Urban', value=True)
|
107 |
+
rural = st.checkbox('Rural', value=True)
|
108 |
+
|
109 |
+
recency = st.slider(label='Месяцев с момента покупки', min_value=int(dataset.recency.min()), max_value=int(dataset.recency.max()), value=(int(dataset.recency.min()), int(dataset.recency.max())))
|
110 |
+
|
111 |
+
if not first_group and not second_group and not third_group and not fourth_group and not fifth_group and not sixth_group and not seventh_group:
|
112 |
+
pass
|
113 |
+
else:
|
114 |
+
st.button('Отфильтровать')
|