Сегментация клиентской базы телекоммуникационной компании
Аналитическая задача — провести анализ данных с целью выделения наиболее типичных групп клиентов и разработки предложений для каждой из групп.
Описание данных
Каждый клиент описывается следующим набором признаков:
Возраст, Среднемесячный расход, Средняя продолжительность разговоров, Звонков днем за месяц, Звонков вечером за месяц, Звонков ночью за месяц, Звонки в другие города, Звонки в другие страны, Доля звонков на стационарные телефоны, Количество SMS за месяц, Дата подключения тарифа.
План по выполнению проекта:
Шаг 1. Загрузка данных;Шаг 1. Загрузка данных
df = pd.read_csv('/content/dataset_telecom.csv')Информация о датафрейме
df.info()
--- ------ -------------- -----Шаг 2. Первичная обработка данных:
корректировка заголовков
корректировка типов признаков
проверка на наличие дублирующих записей
df.duplicated().sum()График плотности распределения признаков после обработки аномальных значений
Выводим процент обработанных аномалий и формируем новый датасет
(1 - df[no_anomals_avr_monthly_exp & no_anomals_day_calls_monthly\По значениям признака Возраст вводим новую переменную "Возрастная категория" студент, если Возраст ∈[19,24];аспирант,если Возраст ∈[25,33];бизнесмен,если Возраст ∈[34,56];знаток,если Возраст ∈[57,70].
bins = [0,24,33,56,70]По значениям признака "Дата подключения" тарифа выделяем признаки: Год подключения, Месяц подключения, Дата подключения
df_clear.head(5)
Шаг 3. Проводим исследовательский анализ данных:
в разрезе значений признаков Год подключения, Месяц подключения, Дата подключения исследуем:Посмотрим медиану, моду по всем признакам в разрезе Возрастной категории
В разрезе значений признака Возрастная категория исследуем распределение признаков Среднемесячный расход, Средняя продолжительность разговоров, Звонков днем за месяц, Звонков вечером за месяц, Звонков ночью за месяц, Звонки в другие города, Доля звонков на стационарные телефоны, Количество SMS за месяц. Построим графики. Сделаем выводы о предпочтениях клиентов разных возрастных категорий в отношении используемых услуг (звонков и SMS; времени суток)
Клиенты возрастных категорий (ТОП-2):
Заключение:
Согласно аналитической задаче при проведенном анализе, мы можем сделать следующие выводы о предпочтениях клиентов разных возрастных категорий в отношении используемых услуг:
Шаг 4. Проведем кластерный анализ
Загрузка библиотек и методовОтберем и стандартизируем признаки
Считаем матрицу попарных расстояний для признаков
Построим дендрограмму из 7 последних кластеров.
Дадим оценку качества построенной кластеризации с помощью коэффициента кофенетической корреляции
Метрика Евклида показывает лучший коэффициент корреляции расстояния по центроиду
Посмотрим на структуру с помощью метода локтя
Посмотрим метод f-cluster
Выделим три макс. кластера по двум признакам и составим портрет клиентов по кластерамШаг 5. Сформулируем и проверим следующие гипотезы
____________________________
подключение методов для проверки гипотез о виде закона распределения,
from scipy.stats import shapiro______________________
Сформулируем и проверим гипотезу о нормальности распределения признаков с помощью теста Шапиро
H_0 Признак 'evening_calls_monthly' имеет нормальное распределение
H_1 Признак 'evening_calls_monthly' имеет распределение, отличное от нормального
ShapiroResult(statistic=0.9721884727478027, pvalue=1.0613379830048937e-28)
pvalue(1.0613379830048937e-28) < alfa(0,05), гипотезу о нормальности распределения отвергаем! Принимаем гипотезу H1
___________________________________
Сформулируем и проверим гипотезу о том, имеют ли признаки одинаковое либо разные распределения с помощью теста Колмогорова-Смирнова
H_0 Признаки 'evening_calls_monthly', day_calls_monthly' имеют одинаковое распределение
H_1 Признаки 'evening_calls_monthly',day_calls_monthly' имеют разные распределения распределение
KstestResult(statistic=0.9792823370529647, pvalue=0.0, statistic_location=3.0, statistic_sign=-1)
KstestResult(statistic=0.9795049550404982, pvalue=0.0, statistic_location=3.0, statistic_sign=-1)
pvalue(0,0) < alfa(0,05), гипотезу об одинаковом распределении признаков отвергаем! Принимаем гипотезу H1
Рис 1. показывает, что признаки 'evening_calls_monthly' (ежемесячные звонки вечером-blue)
и 'day_calls_monthly' (ежемесячные звонки днем-red) имеют разные распределения и отличные от нормального
____________________________________
Сформулируем и проверим гипотезы с помощью критерия Манна-Уитни
H_0 Разница между количеством звонков совершаемых клиентами днем и вечером, статистически не значима
H_1 Количество звонков совершаемых клиентами днем меньше количества звонков совершаемых клиентами вечером
MannwhitneyuResult(statistic=7799836.5, pvalue=1.007006308442071e-77)
pvalue(1.007006308442071e-77) < alfa(0,05) - гипотезу Н_0 отвергаем, принимаем Н_1
_____________________________________
клиенты больше звонили в 2019 году по сравнению с 2021 годом по количеству звонков
H_0 Признак 'tariff_activation_date = 2019' по отношению к клиентам имеет нормальное распределение
H_1 Признак 'tariff_activation_date = 2019' по отношению к клиентам имеет распределение, отличное от нормального
ShapiroResult(statistic=0.8143370747566223, pvalue=0.14920618818837372)
pvalue(0,14) > alfa(0,05), гипотезу H_0 о нормальности распределения принимаем
__________________________________________
Сформулируем и проверим гипотезу о том, подчиняются ли признаки закону о нормальном распределения с помощью теста Колмогорова-Смирнова
H_0 Обе выборки (df.tariff_activation_date == 2019/df.tariff_activation_date == 2021) подчиняются закону о нормальном распределении
H_1 Обе выборки (df.tariff_activation_date == 2019/df.tariff_activation_date == 2021) подчиняются закону, отличному от закона о нормальном распределении
KstestResult(statistic=0.3333333333333333, pvalue=1.0, statistic_location=42137.0, statistic_sign=1)
pvalue(1.0)>alfa(0,05) - принимаем гипотезу H_0
_____________________________________________
H_0 Разница между количеством звонков совершаемых клиентами в 2019 и 2021 годах, статистически не значима.
H_1 Количество звонков совершаемых клиентами в 2019 меньше количества звонков совершаемых клиентами в 2021.
MannwhitneyuResult(statistic=4.0, pvalue=0.5)
pvalue(0,5)>alfa(0,05) - принимаем гипотезу Н_0
Заключение:
Критерий Манна-Уитни показал, что разница между количеством звонков совершаемых клиентами в 2019 и 2021 годах, статистически не значима, т.е. клиенты одинаково совершают звонки как в 2019, так и в 2021. А количество звонков, совершаемых клиентами днем, меньше количества звонков, совершаемых клиентами вечером.СЕГМЕНТАЦИЯ ЗАЕМЩИКОВ БАНКА ПО КРЕДИТНОЙ ИСТОРИИ
Шаг 1. Загрузка данных
df = pd.read_csv('/content/dataset_segment_bank.csv')Смотрим описательные статистики, выявляем аномальные значения
Выделим категориальные и интервальные признаки в датафрейме
Шаг 2. Первичная обработка данных
Этапы:Поиск и обработка аномальных аномальных значений
Делим признаки на непрерывные и категориальные:
vars_cont = ['количество переводов', 'сумма перевода',Посмотрим уникальные значения категориальных признаков и их распределение
Проведем исследование отдельно категориальных признаков: `география переводов`, география телефона`, оператор связи, тип переводов`.
Проведем исследования аномальных значений непрерывных признаков, построим графики распределений и ящик с усами, где обозначим линии нижнего и верхнего усов, линии квантилей.
Напишем фильтр на аномальные значения по интервальным признакам и сформируем новый датафрейм
Исследуем пропущенные значения
df_no_anomals.isna().sum()Шаг 3. Добавление новых признаков:
для каждого клиента рассчитаем его возраст на настоящий момент времени (на 2023 год);Шаг 4. Исследовательский анализ данных
в разрезе значений целевого признака (Дисциплина клиентов) исследуем распределения числовых и категориальных признаков;Построим графики распределения числовых признаков в разрезе целевого
Рассчитаем доли по признакам и нормируем показатели
columns = ['канал клиента', 'оператор связи', 'пол', 'тип переводов', 'откуда_перевод']Перекодируем признаки и посмотрим взаимосвязь
from sklearn.preprocessing import LabelEncoderОтбираем признаки [ количество переводов, сумма перевода, откуда_перевод, оператор связи, канал] согласно коэффициентам корреляции для составления портрета клиента и проверяем гипотезы
Проверим гипотезы в отношении непрерывных признаков
[ количество переводов, сумма перевода, возраст]
Формируем выборки
X = df_no_anomals[df_no_anomals['дисциплина клиента'] == 'BAD']['количество переводов']
Y = df_no_anomals[df_no_anomals['дисциплина клиента'] == 'GOOD']['количество переводов']
проверяем нормальность распределения при помощи теста Колмогорова-Смирнова
H_0 Признак 'количество переводов' имеет нормальное распределение
H_1 Признак 'количество переводов' имеет распределение, отличное от нормального
KstestResult (statistic=0.0766741564329253, pvalue=7.390241215370946e-47, statistic_location=45.0, statistic_sign=1)
т.к. 0 = p_value < alpha = 0.05, то гипотезу о нормальном законе распределения X отвергаем, принимаем гипотезу H_1
-------------------
проверяем гипотезу в отношении параметров -- медиана, при помощи критерия Манна-Уитни и теста Краскела-Уоллиса
H_0: количество переводов клиентов с дисциплиной <<BAD>> не отличается
от количества переводов клиентов с дисциплиной <<GOOD>>
H_1: количество переводов клиентов с дисциплиной <<BAD>> меньше
количества переводов с клиентов дисциплиной <<GOOD>>
MannwhitneyuResult(statistic=93928805.0, pvalue=6.09947592155125e-192)
т.к. 2.947261207847815e-205 = p_value < alpha = 0.05, то гипотезу о равенстве отвергаем
KruskalResult(statistic=871.9653915351048, pvalue=1.219873554501589e-191), результат аналогичен, гипотезу о равенстве отвергаем, принимаем H_1 (количество переводов клиентов с дисциплиной <<BAD>> отличается от
количества переводов с клиентов дисциплиной <<GOOD>>
--------------------
X = df_no_anomals[df_no_anomals['дисциплина клиента'] == 'BAD']['сумма перевода"]
Y = df_no_anomals[df_no_anomals['дисциплина клиента'] == 'MIDDLE']['сумма перевода']
H_0: сумма перевода клиентов с дисциплиной <<BAD>> не отличается
от суммы перевода клиентов с дисциплиной <<MIDDLE>>
H_1: сумма перевода клиентов с дисциплиной <<BAD>> меньше
суммы перевода клиентов с дисциплиной <<MIDDLE>>
KstestResult(statistic=0.1742165978834355, pvalue=2.0856105096193907e-241, statistic_location=30000.0, statistic_sign=-1)
т.к. 2.0856105096193907e-241= p_value < alpha = 0.05, то гипотезу о нормальном законе распределения X отвергаем, принимаем гипотезу H_1
MannwhitneyuResult(statistic=50352526.0, pvalue=9.005618664243352e-89)
т.к. 9.005618664243352e-89 = p_value < alpha = 0.05, то гипотезу о равенстве отвергаем
KruskalResult(statistic=397.63607891297033, pvalue=1.8010854742980258e-88)
т.к. 1.8010854742980258e-88 = p_value < alpha = 0.05, то гипотезу о равенстве отвергаем
----------------------------
X = df_no_anomals[df_no_anomals['дисциплина клиента'] == 'BAD']['возраст]
Y = df_no_anomals[df_no_anomals['дисциплина клиента'] == 'GOOD']['возраст']
H_0: возраст клиентов с дисциплиной <<BAD>> не отличается
от возраста клиентов с дисциплиной <<GOOD>>
H_1: возраст клиентов с дисциплиной <<BAD>> меньше
возраста клиентов с дисциплиной <<GOOD>>
KstestResult(statistic=0.07667823062627172, pvalue=7.306656320761953e-47, statistic_location=45.0, statistic_sign=1)
т.к. 7.306656320761953e-47= p_value < alpha = 0.05, то гипотезу о нормальном законе распределения X отвергаем, принимаем гипотезу H_1
MannwhitneyuResult(statistic=93928584.5, pvalue=6.051812863407449e-192)
т.к. 6.051812863407449e-192 = p_value < alpha = 0.05, то гипотезу о равенстве отвергаем
KruskalResult(statistic=871.9810635613217, pvalue=1.210341111705094e-191)
т.к. 1.210341111705094e-191 = p_value < alpha = 0.05, то гипотезу о равенстве отвергаем
Гипотезы в отношении категориальных признаков
[ канал клиента, откуда_перевод, оператор связи ]
[ канал клиента]
Для биномиальных распределений применяем z-критерий и рассчитываем по формуле
z_value = (m1/n1 - m2/n2) / math.sqrt(((m1+m2)/(n1+n2))*(1-((m1+m2)/(n1+n2)))*(1/n1+1/n2))
test_z_criterion(n1, n2, m1, m2)
Результаты проверки гипотезы H_0 по z-критерию:
Уровень значимости alpha=0.05
P-value: 0.00
Отвергаем нулевую гипотезу: разница в долях статистически значима.
[откуда_перевод]
Результаты проверки гипотезы H_0 по z-критерию:
Уровень значимости alpha=0.05
P-value: 0.00
Отвергаем нулевую гипотезу: разница в долях статистически значима.
[оператор связи]
Результаты проверки гипотезы H_0 по z-критерию:
Уровень значимости alpha=0.05
P-value: 0.00
Отвергаем нулевую гипотезу: разница в долях статистически значима.
Выводы:
На основе проведенных исследований и согласно аналитической задаче провести анализ данных с целью выделения портретов заемщиков по каждой группе целевого признака можно следующие выводы:
Количество переводов является значимым признаком, если клиент совершает 6 и меньше переводов, то с высокой долей вероятности он будет классифицироваться банком как Плохой заемщик, если переводов больше 6, то - Хороший.
Если клиент делает меньше 137000 переводов, то с высокой долей вероятности, по оценке банка, он Плохой заемщик, от 183000 переводов- Средний заемщик.
По возрастной группе, клиенты моложе 49 лет попадают в категорию Плохой заемщик, т.е. меньше осуществляют транзакций, клиенты в возрасте 54 лет и старше, рассматриваются банком как Хорошие заемщики.
Плохие заемщики, по каналу, чаще всего обращаются в банк через Партнера и Стойку, нежели Хорошие заемщики обращаются напрямую в Офис, которых меньше.
Между заемщиками из родного и чужого региона, по локации перевода, есть статистически значимая разница, клиенты с дисциплиной Плохой заемщик, чаще делают перевод из чужого региона, т.е. можно предположить, что клиент приезжает в другой регион на заработки, откуда и совершает переводы.
По оператору связи, Плохие заемщики чаще выбирают более известных операторов, МТС, Мегафон и Билайн, нежели региональных.
АНАЛИЗ КРЕДИТНЫХ ПРЕДЛОЖЕНИЙ
Шаг 1. Загрузка данных
import seaborn as sns
df = pd.read_csv('/content/vkr_dataset_open_credit_card.csv')df.head(2)
Шаг 2. Первичная обработка данных
Корректировка заголовков
корректировка не требуется.
Корректировка типов признаков
df.info()
RangeIndex: 10464 entries, 0 to 10463dtypes: float64(3), int64(5), object(10)
поиск дублирующих записей
df.duplicated().sum() 0
Проверка на аномальные значения
Выделим признаки непрерывные и категориальные
vars_cont = ['age','credit_sum','score_shk','avregzarplata','monthly_income']
vars_cat = ['gender','marital_status', 'job_position','credit_month'\
,'education','tariff_id','living_region','okrug','credit_count'\
,'overdue_credit_count','open_account_flg']
Исследуем категориальные признаки
просмотр уникальных значений признаков и их распределение
---- конец признака open_account_flg ----
Сократим признак job_position до 6 значений "14, 15, 2, 10, 4, 1"
Сократим признак education до 4 значений "2.0. 3.0 4.0 5.0"
Сократим признак credit_count до 6 значений "0.0 1.0 2.0. 3.0 4.0 5.0"
Сократим признак okrug до 7 значений "1.0 2.0 3.0. 4.0 5.0 6.0 7.0"
Признак overdue_credit_count сократим до значений 1 и 0
Исследуем непрерывные признаки
У признаков age, credit_sum, monthly_income отсечем аномалии по границам усов,
признак avregzarplata - отсечем после 99 квантили
Потеря данных составила 14,22%
Шаг 3. Исследовательский анализ данных:
исследуем распределение признаков:
Исследуем возможные зависимости между признаками c помощью тепловой карты
Шаг 4. Отбор признаков и портреты клиентов:
Сформулируем и проверим гипотезы в отношении непрерывных признаков
vars_cont = ['credit_sum', 'score_shk']
Формируем выборки
X = df_no_anomals[df_no_anomals['open_account_flg'] == 0]['credit_sum']
Y = df_no_anomals[df_no_anomals['open_account_flg'] == 1]['credit_sum']
проверяем нормальность распределения при помощи теста Колмогорова-Смирнова
H_0 Признак 'credit_sum' имеет нормальное распределение
H_1 Признак 'credit_sum'' имеет распределение, отличное от нормального
KstestResult(statistic=0.09616544557312695, pvalue=0.0, statistic_location=20008.0, statistic_sign=1)
т.к. 0.0 = p_value < alpha = 0.05, то гипотезу о нормальном законе распределения X отвергаем, принимаем гипотезу H_1
___________________________________
Проверяем гипотезу в отношении параметров -- медиана, при помощи критерия Манна-Уитни и теста Краскела-Уоллиса
H_0: сумма кредита клиентов с неоткрытым кредитным счетом в банке не отличается
от суммы кредита клиентов с открытым кредитным счетом
H_1: сумма кредита клиентов с неоткрытым кредитным счетом в банке больше
суммы кредита клиентов с открытым кредитным счетом
MannwhitneyuResult(statistic=1477416854.5, pvalue=1.3967706945421116e-124)
KruskalResult(statistic=562.1995058558035, pvalue=2.793535433495171e-124)
т.к. 1.3967706945421116e-124= p_value < alpha = 0.05, то гипотезу о равенстве параметров H_0 отвергаем, принимаем гипотезу H_1
_____________________________________________
-------[ 'score_shk']-------
проверяем нормальность распределения при помощи теста Колмогорова-Смирнова
H_0 Признак 'score_shk' имеет нормальное распределение
H_1 Признак 'score_shk' имеет распределение, отличное от нормального
KstestResult(statistic=0.026520177299070802, pvalue=1.0552911752083077e-70, statistic_location=0.441129, statistic_sign=1)
т.к. 1.0552911752083077e-70 = p_value < alpha = 0.05, то гипотезу о нормальном законе распределения X отвергаем, принимаем гипотезу H_1
___________________________
проверяем гипотезу в отношении параметров -- медиана, при помощи критерия Манна-Уитни и теста Краскела-Уоллиса
проверяем гипотезу в отношении параметров -- медиана
H_0: внутренняя скоринговая оценка банка клиентов с неоткрытым кредитным счетом в банке не отличается
от внутренней скоринговой оценки банка клиентов с открытым кредитным счетом
H_1: внутренняя скоринговая оценка банка клиентов с неоткрытым кредитным счетом в банке меньше
внутренней скоринговой оценки банка клиентов с открытым кредитным счетом
MannwhitneyuResult(statistic=53930.5, pvalue=0.4571374765169218)
KruskalResult(statistic=0.011591325450781226, pvalue=0.9142630062808981)
т.к. 0.4571374765169218= p_value > alpha = 0.05, то гипотезу о равенстве параметров H_0 принимаем, гипотезу H_1 отвергаем
________________________________________________________________________________
Гипотезы в отношении категориальных признаков
[gender, job_position, tariff_id, education, credit_count, okrug]
[ gender]
Для биномиальных распределений применяем z-критерий и рассчитываем по формуле
z_value = (m1/n1 - m2/n2) / math.sqrt(((m1+m2)/(n1+n2))*(1-((m1+m2)/(n1+n2)))*(1/n1+1/n2))
test_z_criterion(n1, n2, m1, m2)
Результаты проверки гипотезы H_0 по z-критерию:
Уровень значимости alpha=0.05
P-value: 0.00
Отвергаем нулевую гипотезу: разница в долях статистически значима.
[ okrug]
Сравним 1.0 & 3.0 и 1.0 & 7.0, среди не открывших карту
Результаты проверки гипотезы H_0 по z-критерию:
Уровень значимости alpha=0.05
P-value: 0.00
Отвергаем нулевую гипотезу: разница в долях статистически значима.
[job_position]
Сравним 1.0 и 'квал_позиции', среди не открывших карту
Сравним 1.0 и 'квал_позиции', среди открывших карту
Результаты проверки гипотезы H_0 по z-критерию:
Уровень значимости alpha=0.05
P-value: 0.00
Отвергаем нулевую гипотезу: разница в долях статистически значима.
[credit_count]
Сравним 0.0 и 0.5, среди не открывших карту, и, среди открывших карту
Результаты проверки гипотезы H_0 по z-критерию:
Уровень значимости alpha=0.05
P-value: 0.00
Отвергаем нулевую гипотезу: разница в долях статистически значима
Портреты клиентов
На основе проведенных исследований, можно сделать вывод, что с высокой долей вероятности, клиент, открывший карту, будет иметь сл. характеристики:
age (возраст) - до 35
gender (пол) - 2
job_position (работа) - 4
education (образование) -4
okrug (округ) - 1
score_shk (внутренняя скоринговая оценка) - 0,4572
Клиент, склонный не открывать карту, с высокой долей вероятности, будет иметь следующие характеристики:
age(возраст) - от 35
gender (пол)r - 1
job_position (работа) - 10
education (образование) - 2
okrug (округ) - 3
score_shk (внутренняя скоринговая оценка) - 0.467237Шаг 5. Построим классификационные модели
Загрузка библиотек, классификаторов и метрик
Сформируем признаковое пространство
Балансируем показатели с помощью SMOTE
Разделим признаки на обучающее и тестирующее множества
С помощью StandartScaler преобразуем независимые переменные
При помощи Логрегрессии построим прогнозную модель
При помощи Случайного леса построим прогнозную модель
A/B-тест для мобильного приложения
Инструкция по выполнению проекта
Шаг 1. Загрузка данныхШаг 2. Подготовка данных
Корректируем заголовки и типы признаков
df.columns = ['event_name','user_id','event_time','group_id']Исследуем пропуски и дубликаты
df.drop_duplicates(keep='first', inplace=True)
Проведем исследование, посмотрим корректность а/b теста
Шаг 3. EDA Исследовательский анализ
Построим гистограмму по дате и количеству событий
Оставим для исследования период с наибольшим кол-вом событий в день
Шаг 4. Анализ воронки событий
Распределение событий: какие события и в каком количестве
Сколько пользователей совершали каждое из этих событий
Построим воронку событий: отобразим долю пользователей проходящих на следующий шаг воронки
Шаг 5. Анализ результатов эксперимента
.Сколько пользователей в каждой группе
Посчитаем долю пользователей, совершивших каждое из событий
Сформулируем и проверим гипотезу о наличие значимых отличий по результатам теста
H1: Имеется статистически значимая разница между долями пользователей из групп 247 и 248, совершивших одно и тоже событие
--------------------------------------------------------
z_value = (m1/n1 - m2/n2) / math.sqrt(((m1+m2)/(n1+n2))*(1-((m1+m2)/(n1+n2)))*(1/n1+1/n2))