HardWorkingStation commited on
Commit
fccbfb8
1 Parent(s): 3fd6b1d

Initial commit

Browse files
Files changed (2) hide show
  1. src/tools.py +120 -16
  2. src/web_app.py +63 -8
src/tools.py CHANGED
@@ -2,29 +2,28 @@ 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_lenta
6
  from catboost import CatBoostClassifier
7
  import sklearn
8
  import streamlit as st
 
 
9
 
10
 
11
  @st.experimental_memo
12
- def get_data() -> sklearn.utils._bunch.Bunch:
13
-
14
- treat_dict = {
15
- 'test': 1,
16
- 'control': 0
17
- }
18
  # получаем датасет
19
- dataset = fetch_lenta()
20
- # преобразуем строковые значения колонки в числовыые значения
21
- dataset.treatment = dataset.treatment.map(treat_dict)
22
- # заполняем пропуски
23
- dataset.data['gender'] = dataset.data['gender'].fillna(value='Не определен')
24
- dataset.data['children'] = dataset.data['children'].fillna(0).astype('int')
25
- dataset.data['age'] = dataset.data['age'].fillna(0).astype('int')
26
- dataset.data['months_from_register'] = dataset.data['months_from_register'].fillna(0).astype('int')
27
- return dataset
 
 
28
 
29
 
30
  @st.experimental_memo
@@ -41,3 +40,108 @@ def data_split(data, treatment, target) -> tuple[Any, Any, Any, Any, Any, Any]:
41
  random_state=42
42
  )
43
  return X_train, X_val, trmnt_train, trmnt_val, y_train, y_val
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
7
  import sklearn
8
  import streamlit as st
9
+ import plotly.express as px
10
+ import plotly.graph_objects as go
11
 
12
 
13
  @st.experimental_memo
14
+ def get_data() -> tuple[Any, Any, Any]:
 
 
 
 
 
15
  # получаем датасет
16
+ dataset = fetch_hillstrom(target_col='visit')
17
+ dataset, target, treatment = dataset['data'], dataset['target'], dataset['treatment']
18
+ # выбираем два сегмента
19
+ dataset = dataset[treatment != 'Mens E-Mail']
20
+ target = target[treatment != 'Mens E-Mail']
21
+ treatment = treatment[treatment != 'Mens E-Mail'].map({
22
+ 'Womens E-Mail': 1,
23
+ 'No E-Mail': 0
24
+ })
25
+
26
+ return dataset, target, treatment
27
 
28
 
29
  @st.experimental_memo
 
40
  random_state=42
41
  )
42
  return X_train, X_val, trmnt_train, trmnt_val, y_train, y_val
43
+
44
+
45
+ def get_newbie_plot(data):
46
+ fig = px.histogram(
47
+ data['newbie'],
48
+ color=data['newbie'],
49
+ title='Распределение клиентов по флагу Newbie'
50
+ )
51
+
52
+ fig.update_xaxes(
53
+ title='',
54
+ ticktext=['"Старые" клиенты', 'Новые клиенты'],
55
+ tickvals=[0, 1]
56
+ )
57
+
58
+ fig.update_yaxes(
59
+ title='Количество'
60
+ )
61
+
62
+ fig.update_layout(
63
+ showlegend=False,
64
+ bargap=0.3
65
+ )
66
+
67
+ fig.update_traces(hovertemplate="Количество клиентов: %{y}")
68
+
69
+ return fig
70
+
71
+
72
+ def get_zipcode_plot(data):
73
+ fig = px.histogram(
74
+ data['zip_code'],
75
+ color=data['zip_code'],
76
+ title='Распределение клиентов по флагу zip_code'
77
+ )
78
+
79
+ fig.update_xaxes(
80
+ title='',
81
+ categoryorder='total descending'
82
+ )
83
+
84
+ fig.update_yaxes(
85
+ title='Количество'
86
+ )
87
+
88
+ fig.update_layout(
89
+ showlegend=False,
90
+ bargap=0.3
91
+ )
92
+
93
+ fig.update_traces(hovertemplate="Количество клиентов: %{y}")
94
+
95
+ return fig
96
+
97
+
98
+ def get_channel_plot(data):
99
+ fig = px.histogram(
100
+ data['channel'],
101
+ color=data['channel'],
102
+ title='Распределение клиентов по флагу zip_code'
103
+ )
104
+
105
+ fig.update_xaxes(
106
+ title='',
107
+ categoryorder='total descending'
108
+ )
109
+
110
+ fig.update_yaxes(
111
+ title='Количество'
112
+ )
113
+
114
+ fig.update_layout(
115
+ showlegend=False,
116
+ bargap=0.3
117
+ )
118
+
119
+ fig.update_traces(hovertemplate="Количество клиентов: %{y}")
120
+
121
+ return fig
122
+
123
+
124
+ def get_history_segment_plot(data):
125
+ fig = px.histogram(
126
+ data['history_segment'],
127
+ color=data['history_segment'],
128
+ title='Распределение клиентов по флагу history_segment'
129
+ )
130
+
131
+ fig.update_xaxes(
132
+ title='',
133
+ categoryorder='total descending'
134
+ )
135
+
136
+ fig.update_yaxes(
137
+ title='Количество'
138
+ )
139
+
140
+ fig.update_layout(
141
+ showlegend=False,
142
+ bargap=0.3
143
+ )
144
+
145
+ fig.update_traces(hovertemplate="Количество клиентов: %{y}")
146
+
147
+ return fig
src/web_app.py CHANGED
@@ -1,15 +1,70 @@
 
 
1
  import streamlit as st
2
 
3
  import tools
4
- from time import sleep
5
 
6
- norm_columns = ['age', 'children', 'gender', 'main_format', 'months_from_register', 'response_sms', 'response_viber']
7
- dataset = tools.get_data()
8
 
9
  st.title('Uplift lab')
10
 
11
- st.write('Какие данные выбрать для рассылки?')
12
- st.write(dataset.data[norm_columns].head())
13
- columns = st.multiselect(options=norm_columns, label='Выберите признак')
14
- age = st.select_slider(label='', options=range(1, 101), value=[18, 100])
15
- st.write(dataset.data[dataset.data['age'].isin(age)][norm_columns])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
  import streamlit as st
4
 
5
  import tools
 
6
 
7
+
8
+ dataset, target, treatment = tools.get_data()
9
 
10
  st.title('Uplift lab')
11
 
12
+ st.markdown(
13
+ """
14
+ #### Рассмотрим пример применения одного из подходов прогнозирования _uplift_.
15
+
16
+ Данные для примера взяты из [_The MineThatData E-Mail Analytics And Data Mining Challenge_](https://blog.minethatdata.com/2008/03/minethatdata-e-mail-analytics-and-data.html)
17
+
18
+ Этот набор данных содержит 42 693 строк с данными клиентов, которые в последний раз совершали покупки в течение двенадцати месяцев.
19
+
20
+ Среди клиентов была проведена рекламная кампания с помощью _email_ рассылки:
21
+ - 1/3 клиентов были выбраны случайным образом для получения электронного письма, рекламирующего мужскую продукцию;
22
+ - 1/3 клиентов были выбраны случайным образом для получения электронного письма, рекламирующего женскую продукцию;
23
+ - С оставшейся 1/3 коммуникацию не проводили.
24
+
25
+ Для каждого клиента из выборки замерили факт перехода по ссылке в письме, факт совершения покупки и сумму трат за
26
+ две недели, следующими после получения письма.
27
+
28
+ Пример данных приведен ниже.
29
+ """
30
+ )
31
+ refresh = st.button('Обновить выборку')
32
+ title_subsample = dataset.sample(7)
33
+ if refresh:
34
+ title_subsample = dataset.sample(7)
35
+ st.dataframe(title_subsample, width=700)
36
+ st.write( f"Всего записей: {dataset.shape[0]}")
37
+
38
+ st.write('Описание данных')
39
+ st.markdown(
40
+ """
41
+ | Колонка | Обозначение |
42
+ |-------------------|------------------------------------------------------------------------|
43
+ | _recency_ | Месяцев с момента последней покупки |
44
+ | _history_Segment_ | Классификация долларов, потраченных в прошлом году |
45
+ | _history_ | Фактическая стоимость в долларах, потраченная в прошлом году |
46
+ | _mens_ | Флаг 1/0, 1 = клиент приобрел мужские товары в прошлом году |
47
+ | _womens_ | Флаг 1/0, 1 = клиент приобрел женские товары в прошлом году |
48
+ | _zip_code_ | Классифицирует почтовый индекс как городской, пригородный или сельский |
49
+ | _newbie_ | Флаг 1/0, 1 = Новый клиент за последние двенадцать месяцев |
50
+ | _channel_ | Описывает каналы, которые клиент приобрел в прошлом году |
51
+
52
+ ---
53
+ """
54
+ )
55
+ st.write("Для того, чтобы лучше понять на какую аудиторию лучше запустить рекламную кампанию, проведем небольшой \
56
+ анализ данных")
57
+
58
+ with st.expander('Развернуть блок анализа данных'):
59
+
60
+ st.plotly_chart(tools.get_newbie_plot(dataset))
61
+ st.write(f'В данных примерно одинаковое количество новых и "старых клиентов". '
62
+ f'Отношение новых клиентов к старым: {(dataset["newbie"] == 1).sum() / (dataset["newbie"] == 0).sum():.2f}')
63
+
64
+ st.plotly_chart(tools.get_zipcode_plot(dataset))
65
+ st.write(f'Большинство клиентов из пригорода: {(dataset["zip_code"] == "Surburban").sum()}')
66
+
67
+ st.plotly_chart(tools.get_channel_plot(dataset))
68
+
69
+ st.plotly_chart(tools.get_history_segment_plot(dataset))
70
+