Для данного проекта я выбрала базу данных о клиентах банка.
Для начала нужно понять, какие переменные могут быть полезны для данного анализа. Вся база данных не требуется, но интуитивно некоторые характеристики кажутся важными. Проверим гипотезы с помощью нескольких запросов:
kable(dbGetQuery(data, "SELECT Exited, COUNT(*) AS n FROM churn
GROUP BY Exited")) %>% kable_styling(font_size = 15)
Exited | n |
---|---|
0 | 7963 |
1 | 2037 |
Как видно из таблички, 2037 клиентов отказались от услуг банка. Посмотрим, сколько это в процентах:
kable(dbGetQuery(data,"SELECT Exited, (COUNT (Exited) * 100 / (SELECT COUNT(*) FROM churn)) AS percent
FROM churn GROUP BY Exited")) %>% kable_styling(font_size = 15)
Exited | percent |
---|---|
0 | 79 |
1 | 20 |
Отток 20% . С чем это может быть связано?
IsActiveMember | n |
---|---|
0 | 1302 |
1 | 735 |
И тут мы видим, что не активные клиенты почти в два раза чаще покидают компанию. Значит эта характеристика важна для анализа оттока.
kable(dbGetQuery(data, "SELECT HasCrCard, COUNT(*) AS n FROM churn WHERE Exited = 1
GROUP BY HasCrCard")) %>% kable_styling(font_size = 15)
HasCrCard | n |
---|---|
0 | 613 |
1 | 1424 |
Удивительно, но по цифрам кажется, что люди, имеющие кредитную карту, чаще отказывают от услуг банка. Это интересно и можно будет изучать в дальнейшем анализе.
kable(dbGetQuery(data, "SELECT NumOfProducts, COUNT(*) AS n FROM churn WHERE Exited = 1
GROUP BY NumOfProducts")) %>% kable_styling(font_size = 15)
NumOfProducts | n |
---|---|
1 | 1409 |
2 | 348 |
3 | 220 |
4 | 60 |
В табличке показаны значения только для ушедших клиентов. И, как видно по цифрам, самое малое количество ушедших клиентов имели 4 продукта. Большинство имело 1 продукт, поэтому отказывалось от услуг компании с большей легкостью.
kable(dbGetQuery(data, "SELECT count(*) AS churn, country
FROM churn
INNER JOIN country ON churn.CountryId = country.CountryId
WHERE Exited = 1
GROUP BY country")) %>% kable_styling(font_size = 15)
churn | Country |
---|---|
810 | France |
814 | Germany |
413 | Spain |
kable(dbGetQuery(data, "SELECT count(*) AS stay, country
FROM churn
INNER JOIN country ON churn.CountryId = country.CountryId
WHERE Exited = 0
GROUP BY country")) %>% kable_styling(font_size = 15)
stay | Country |
---|---|
4204 | France |
1695 | Germany |
2064 | Spain |
С первого взгляда можно сказать, что в Германии меньше всего клиентов в принципе пользуются услугами нашего банка, но при этом там самый большой отток по количеству людей. Проверим с помощью графика, действительно ли большой отток клиентов в Германии.
ger = dbGetQuery(data, "SELECT Exited, Country
FROM churn
INNER JOIN country ON churn.CountryId = country.CountryId
WHERE Country = 'Germany' ")
cbbPalette <- c("#b8eaff", "#fff3bf", "ffbfd5")
ger$Exited = ifelse(ger$Exited == 1, "Churn", "Stay")
ger %>%
group_by(Exited) %>%
summarise(Number = n()) %>%
mutate(Percent = prop.table(Number)*100) %>%
ggplot(aes(Exited, Percent)) +
geom_col(aes(fill = Exited)) +
labs(title = "Процент оттока клиентов в Германии") + scale_fill_manual(values=cbbPalette) +
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(aes(label = sprintf("%.2f%%", Percent)), vjust = 3,size = 4) +
theme(plot.title = element_text(size=14, hjust = 0.5, face="bold"),
axis.ticks = element_blank(),
panel.grid = element_blank(),
rect = element_blank(),
panel.grid.major.y = element_line(color = "grey92", size = 0.5))
32.44% , довольно значительное количество людей в Германии перестают пользоваться услугами нашего банка. Будет логично сосредоточиться на изучении возможных причин оттока именно в этой стране.
Итак, мы посмотрели некоторые характеристики, которые возможно влияют на отток и теперь можем изучить их поближе. В финальный датасет анализа оттока клиентов Германии для работы включены следующие переменные:
Посмотрим распределение некоторых характеристик и то, как они связаны с оттоком:
df_ger$IsActiveMember = as.factor(df_ger$IsActiveMember)
s2 = df_ger %>% ggplot(aes(x=IsActiveMember,fill=Exited)) +
geom_bar(position = 'fill') +
labs(y = "") +
geom_text(data = . %>%
group_by(IsActiveMember, Exited) %>%
tally() %>%
mutate(p = n / sum(n)) %>%
ungroup(),
aes(y = p, label = scales::percent(p)),
position = position_stack(vjust = 0.5), show.legend = FALSE) +
scale_y_continuous(labels = scales::percent) + scale_fill_manual(values=cbbPalette)+
theme_bw()
df_ger$HasCrCard = as.factor(df_ger$HasCrCard)
s1 = df_ger %>% ggplot(aes(x=HasCrCard,fill=Exited)) +
geom_bar(position = 'fill') +
labs(y = "") +
geom_text(data = . %>%
group_by(HasCrCard, Exited) %>%
tally() %>%
mutate(p = n / sum(n)) %>%
ungroup(),
aes(y = p, label = scales::percent(p)),
position = position_stack(vjust = 0.5), show.legend = FALSE) +
scale_y_continuous(labels = scales::percent) + scale_fill_manual(values=cbbPalette)+
theme_bw()
plot_grid(s1, s2, label_size = 16, label_fontface = "bold")
Из графиков выше можно сделать вывод, что наличие кредитной карты практически никак не влияет на решение клиента уйти из компании. Зато активность влияет значительно. Мы видим, что процент оттока неактивных клиентов на на 17% выше, чем отток активных клиентов.
Посмотрим, как в Германии на отток влияет количество продуктов
Как видно из барчарта, наиболее большой отток наблюдается у клиентов, пользующихся 3-4 продуктами компании. Это странно, но, наверное, можно объяснить. Например, у клиента есть несколько кредитов из банка, кредитная карточка и он, выплатив кредиты, больше не нуждается в услугах банка и поэтому уходит.
Возраст и срок пребывания в компании также может играть значительную роль. С возрастом люди, возможно, меньше пользуются услугами компании и чаще покидают ее. А те, кто дольше пользуется услугами компании в месяцах также могут меньше уходить, т.к. они уже “устовяшиеся” клиенты.
df_ger$Tenure = as.numeric(df_ger$Tenure)
df_ger$Age = as.numeric(df_ger$Age)
graph1 = df_ger %>%
group_by(Tenure, Exited) %>%
summarise(Number = n()) %>%
ggplot(aes(Tenure, Number)) +
geom_line(aes(col = Exited)) +
labs(x = "Tenure (month)",
y = "",
title = "Отток в зависимости от срока пребывания") +
scale_x_continuous(breaks = seq(0, 80, 10)) + scale_fill_manual(values=cbbPalette) + theme_bw()
graph2 = df_ger %>%
group_by(Age, Exited) %>%
summarise(Number = n()) %>%
ggplot(aes(Age, Number)) + geom_line(aes(col = Exited)) +
labs(x = "Age",
y = "",
title = "Отток в зависимости от возраста") +
scale_x_continuous(breaks = seq(0, 120, 20)) + scale_fill_manual(values=cbbPalette)+ theme_bw()
grid.arrange(graph1, graph2)
Выводы из лайнплотов выше:
Срок пребывания в компании не сильно влияет на отток. Долгие клиенты также уходят из компании, как и остаются. Новые клиенты чаще остаются в компании в первые месяцы, но потом также могут и оставаться, и уходить.
Возраст влияет на отток. Видно четкую зависимость оттока от возраста. Клиенты в возрасте 20-40 чаще остаются в компании, клиенты 40-60 чаще уходят.
Чтобы выявить наиболее важные характеристики, влияющие на отток, построим модель, предсказывающую уход клиентов. Я использовала модель random forest, т.к. этот алгоритм показал лучшие результаты на моих данных.
df_model = df_ger %>% dplyr::select( - Country)
df_model$Exited = as.factor(df_model$Exited)
set.seed(926)
train_ind = createDataPartition(df_model$Exited, p = 0.8, list = FALSE)
test = df_model[-train_ind,]
train = df_model[train_ind,]
set.seed(926)
model.rf2=randomForest(Exited~.,data=train, mtry=5, ntree = 15)
predTest.rf2 = predict(model.rf2, test)
confusionMatrix(predTest.rf2, test$Exited, positive = "Churn", mode = "prec_recall")
## Confusion Matrix and Statistics
##
## Reference
## Prediction Churn Stay
## Churn 92 43
## Stay 70 296
##
## Accuracy : 0.7745
## 95% CI : (0.7353, 0.8103)
## No Information Rate : 0.6766
## P-Value [Acc > NIR] : 8.983e-07
##
## Kappa : 0.4611
##
## Mcnemar's Test P-Value : 0.01445
##
## Precision : 0.6815
## Recall : 0.5679
## F1 : 0.6195
## Prevalence : 0.3234
## Detection Rate : 0.1836
## Detection Prevalence : 0.2695
## Balanced Accuracy : 0.7205
##
## 'Positive' Class : Churn
##
Посмотрим, какие переменные больше всего влияют на определение оттока
vip(model.rf2, method = "firm", fill = "#f07180", width = 0.5, alpha = 5) + theme_minimal()
Наиболее важными предикторами являются:
Менее важные предикторы:
Совсем не важный предиктор:
Некоторые характеристики, влияющие на отток, не зависят от действий банка, а скорее от жизни клиента. Например, Уровень зарплаты или кредитный скоринг. Но тем не менее, на самые важные предикторы банк может повлиять.
1) Количество продуктов, Наиболее хорошим для компании исходом будет, если большинство клиентов будут пользоваться 2 продуктами банка. Для клиентов, пользующихся одним продуктом, можно предлагать скидку на второй. Например, если у клиента уже есть кредитная карта банка, то ставка на кредит от этого же банка будет немного ниже, чем для держателей карты другого банка
2) Возраст, Наиболее молодые клиенты чаще остаются с компанией, чем более взрослые. Банку стоит проводить маркетинговую кампанию по привлечению более молодых клиентов в возрасте от 20 до 40. Например, предлагать более низкие ставки по кредиту, ипотеке или разработать молодежную карту (например, как сейчас есть такая программа у Сбербанка)
3) Активность клиента Чем чаще клиент совершает действия, тем меньше вероятность того, что он покинет компанию. Чтобы увеличить активность, банк может предоставлять для этого больше возможностей. Например, удобные приложения для понимания своего финансового состояния. Приведу пример: у Сбербанка есть приложение “Сбербанк онлайн”, в котором можно наблюдать за своими расходами, смотреть историю покупок, планировать бюджет, производить разные переводы, а также можно привязать несколько карт, что очень удобно для пользователей. Или у Тинькофф банка есть специальное приложение для инвестиций, в котором можно наблюдать за ростом акций, совершать покупки и т.д. Таким образом, у пользователей будет увеличиваться активность взаимодействия с банком
test2 = test
test2$NumOfProducts[test2$NumOfProducts == "1"] =
sample(c("1", "2"),
size = length(test2$NumOfProducts[test2$NumOfProducts == "1"]),
replace = T, prob = c(0.8, 0.2))
predTest = predict(model.rf2, test2)
gr1 = ggplot(data.frame(predTest)) + geom_bar(aes(x = predTest), alpha = 0.5, fill = "#5ca1fa") +
geom_bar(data = test, aes(x = Exited), alpha = 0.5) + ylab('Количество клиентов') + xlab('') + theme_minimal()
ggplotly(gr1)
Как мы видим, отток немного снизился. Если раньше на этой выборке у нас уходили 162 человека, то теперь 125.
test3 = test
test3$Age[test3$Age >= "65"] =
sample(c("65", "25"),
size = length(test3$Age[test3$Age >= "65"]),
replace = T, prob = c(0.9, 0.1))
predTest2 = predict(model.rf2, test3)
gr2 = ggplot(data.frame(predTest2)) + geom_bar(aes(x = predTest2), alpha = 0.5, fill = "#5ca1fa") +
geom_bar(data = test, aes(x = Exited), alpha = 0.5)+ ylab('Количество клиентов') + xlab('') + theme_minimal()
ggplotly(gr2)
Такие меры приводят к значительному снижениию оттока. Количество ушедших клиентов снизилось на 120 человек!
test4 = test
test4$IsActiveMember[test4$IsActiveMember == "0"] =
sample(c("0", "1"),
size = length(test4$IsActiveMember[test4$IsActiveMember == "0"]),
replace = T, prob = c(0.85, 0.15))
predTest3 = predict(model.rf2, test4)
gr3 = ggplot(data.frame(predTest3)) + geom_bar(aes(x = predTest3), alpha = 0.5, fill = "#5ca1fa") +
geom_bar(data = test, aes(x = Exited), alpha = 0.5) + ylab('Количество клиентов') + xlab('') + theme_minimal()
ggplotly(gr3)
Как и с прошлым эффектом, отток значительно снижается. Отток уменьшился на 64 человека.
Основными причинами оттока являются:
Чтобы уменьшить отток клиентов в банке Германии, компании следует осуществить некоторые маркетинговые кампании: