-
Notifications
You must be signed in to change notification settings - Fork 1
/
SMCRM_Ch04.Rmd
1552 lines (1182 loc) · 152 KB
/
SMCRM_Ch04.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
title: "Statistical Methods in Customer Relationship Management"
subtitle: "Chapter 4. Customer Retention"
author: "Alexander Rodionov"
date: "6 июня 2018 г."
output:
html_document:
highlight: tango
theme: readable
code_folding: hide
fig_caption: yes
fig_height: 4
fig_width: 6.3
toc: yes
toc_float: no
number_sections: no
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
options(width = 120)
```
Мы продолжаем рассматриваем в **R** примеры **SAS** на наборах данных из книги Kumar V., Petersen Andrew J. "Statistical Methods in Customer Relationship Management".
# Глава 4. Удержание клиентов
После того, как клиенты были приобретены, важно обсудить второй шаг CRM - *сохранить клиентов*. Стратегии удержания клиентов используются как в договорных условиях (когда клиенты привязаны к контрактам, таким как догвор на мобильный телефон с пакетом связи или подписка на журнал) и внедоговорные условия (где клиенты не связаны контрактами, такими как покупки в продуктах или покупки одежды). Рейхельд и Сассер (Reichheld and Sasser, 1990) заявили, что 5% -ное улучшение удержания клиентов может привести к увеличению рентабельности в пределах от 25 до 85% с точки зрения чистой текущей стоимости в зависимости от отрасли. С тех пор компании постоянно выделяют ресурсы на управление удержанием клиентов, и исследователи уделяют большое внимание изучению сохранению клиентов.
Исследования по сохранению клиентов имеют два основных направления. Одно направление заинтересовано в исследовании влияния различных маркетинговых переменных на удержание клиентов, что, в свою очередь, влияет на производительность фирмы. Другое напарвление заинтересовано в создании эконометрических и статистических моделей для оценки или прогнозирования решений о сохранении клиентов как со стороны клиента, так и со стороны компании.
```{r Picture 1, echo=FALSE, out.width=1155, fig.cap = 'The Picture 1'}
knitr::include_graphics("C:/Soft/R/Examples/CRM/SMCRM_Ch04-1.png")
```
На рисунке 1 показана интегрированная структура, которая описывает различные отношения, рассмотренные в разных исследованиях во многих отраслях. Эти отрасли включают в себя, в частности, телекоммуникации, финансовые услуги, сферу услуг, рестораны и розничную торговлю. Общей темой этих отношений является мышление, которое направлено на:
* a) повышение качества продукции и услуг, приводящее к повышению удовлетворенности клиентов;
* б) всемерная удовлетворенность клиентов приводит к увеличению удержания клиентов (что обусловлено качеством отношений, так что более высокое качество отношений положительно улучшает связь между удовлетворением и удержанием) и
* c) увеличение удержания клиентов приводит к повышению эффективности работы фирмы.
```{r Picture 2, echo=FALSE, out.width=1155, fig.cap = 'The Picture 2'}
knitr::include_graphics("C:/Soft/R/Examples/CRM/SMCRM_Ch04-2.png")
```
Авторам книги по понятным причинам импонирует второе направление исследований по удержанию клиентов (см. рисунок 2), которое влияет на решения, принимаемых менеджерами по текущим клиентам. Часто возникает несколько ключевых вопросов, в разрешении которых менеджеры заинтересованы при формировании ответа после привлечения клиента. К ним относятся:
* Будет ли недавно приобретенный покупатель купать или нет в дальнейшем?
* Какова будет продолжительность жизни клиента (т. е. когда клиент завершит сотрудничество с фирмой)?
* Учитывая, что клиент собирается выкупить:
+ Сколько предметов покупает клиент?
+ Сколько этот клиент способен потратить?
+ Будет ли этот клиент покупать / заказывать в нескольких категориях продуктов?
* Покупает ли потребитель в основном у одной фирмы (значительная доля в кошельке) или у многих разных фирм (низкая доля в кошельке)?
* Какое долгосрочное влияние покупательского поведения клиента на стоимость фирмы?
Чтобы дать полное понимание того, как моделировать процесс удержание клиентов, авторы рассматривают вышеперечисленные вопросы в исследованиях один за другим вместе с соответствующими методами моделирования. Они также представляют эмпирические примеры в конце каждого подраздела, чтобы продемонстрировать, как применять эти знания к представительной выборке клиентов из фирмы **B2C**.
***
Подобно моделям приобретения клиентов, первый вопрос, на который необходимо ответить при выборе модели, заключается в том, встпуют ли клиенты договорные и внедоговорные отношения с фирмой. В большинстве случаев это определяет тип статистической модели, который необходимо использовать для получения информации из данных.
## Данные для эмпирических примеров
В этой главе авторы дают описание основных этапов моделирования, в ходе которого пытаются ответить на каждый ключевой вопрос исследования, поднятый в начале главы. Они также предоставляют по крайней мере один эмпирический пример в конце каждого подраздела, который покажет, какие данные могут использоваться для формирования ответа на эти ключевые вопросы исследования. Для всех эмпирических примеров в этой главе авторы предлагают набор данных под названием «Удержание клиентов», который разбит на две связанные таблицы данных. В этом наборе данных вы найдете две таблицы данных, которые включают репрезентативную выборку из 500 клиентов из типичной фирмы **B2C**, где все клиенты принадлежат к одной когорте. В этом случае когорта состоит из случайной выборки из 500 клиентов, которые совершили первую покупку у фирмы в четвертом квартале. В первой таблице данных предоставлена информацию о транзакциях для каждого клиента в течение 12 кварталов ("`customerRetentionTransactions`"). Таким образом, таблица данных состоит из 6000 строк (500 клиентов * 12 кварталов) и 8 столбцов. Во второй таблице данных предоставлена демографическая информация по каждому клиенту ("`customerRetentionDemographics`"). Таким образом, таблица данных состоит из 500 строк (500 клиентов) и 6 столбцов.
Первая таблица данных ("`customerRetentionTransactions`") включает нижеследующие переменные, которые будут использоваться в некоторой комбинации в ходе каждого последующего этапа анализа:
| Переменные | Описание |
|:--------------- |:-------------------------------------------------------------------------------------|
| Customer | Номер клиента клиента (от 1 до 500) |
| Quarter | Квартал (от 1 до 12), когда произошла транзакция |
| Purchase | если **1**, когда покупатель приобрел в данном квартале, **0**, если в этом квартале не произошло покупок |
| Order_quantity | Долларовая стоимость покупок в данном квартале |
| Crossbuy | Количество различных категорий товаров / услуг, приобретенных в данном квартале |
| Ret_Expense | Доллары потраченные на маркетинговые усилия по удержанию этого клиента в данном квартале |
| Ret_Expense_SQ | Квадрат затрат на маркетинговые усилияпо удержанию этого клиента в данном квартале |
Вторая таблица данных ("`customerRetentionDemographics`") включает следующие переменные
которые будут использоваться в некоторой комбинации в ходе каждого последующего этапа анализа:
| Переменные | Описание |
|:--------------- |:-------------------------------------------------------------------------------------|
| Customer | Номер клиента клиента (от 1 до 500) |
| Gender | **1**, если клиент является мужчиной, **0**, если клиент является женщиной |
| Married | **1**, если клиент женат, **0**, если клиент не состоял в браке |
| Income | **1**, если доход < 30 000 долл. США, **2**; если 30 001 долл. США < доход < 45 000 долл. США; **3**, если 45 001 долл. США < доход < 60 000 долл. США; **4**, если 60 001 долл. США < доход < 75 000 долл. США; **5**, если 75 001 долл. США < доход < 90 000 долл. США; **6**, если доход > 90 001 долл. США |
| First_Purchase | Стоимость первой покупки, сделанной клиентом в 1 квартале |
| Loyalty | **1**, если клиент является членом программы лояльности, **0**, если нет |
| Share-of-Wallet (SOW) | Процент покупок клиента от данной фирмы, учитывая общий объем покупок по всем фирмам в этой категории |
| CLV | Дисконтированная стоимость всех ожидаемых будущих прибылей или стоимости жизни клиента|
Эти примеры будут охватывать темы "повторная покупка или нет"", "количество заказов", "размер заказа", "перекрестные покупки", "доля в кошельке (SOW)" и "доходность (CLV)".
```{r Ch04: Customer retention - Data}
library('tidyverse')
library('caret')
library('car')
utils::data('customerRetentionTransactions', package = 'SMCRM')
utils::data('customerRetentionDemographics', package = 'SMCRM')
```
Странно, но в авторском наборе данных отсутствует важнейший демографический показатель **возраст**.
## Эмпирический пример: Повторная покупка или нет (остаться или уйти)
Один из ключевых вопросов, на который авторы хотят ответить по удержанию клиентов, заключается в том, можем ли мы определить, какие клиенты имеют наибольшую вероятность повторной покупки ("`repurchase`"). Для этого сначала нужно узнать, какие текущие клиенты фактически совершили дополнительные покупки после их первоначальной первой покупки. В наборе данных, предоставленном для этой главы, имеется бинарная переменная, которая идентифицирует, покупает ли покупатель за данный период времени, в этом случае - квартале. Авторы также предоставляютм набор предикторов, которые могут помочь объяснить решение клиента о повторной покупке. В конце этого примера вы сможете сделать следующее:
1. Определите драйверы поведения клиентов для повторной покупки.
2. Интерпретируйте оценки параметров из модели повторной покупки.
3. Предскажите количество повторных покупок клиентами.
4. Определить предиктивную точность модели повторной покупки.
Авторы в обзоре литературы указали, что ряд исследователей включают в число предикторов в подобные модели показатели **RFM** (англ. **Recency** – How recently did the customer purchase? **Frequency** – How often do they purchase? **Monetary Value** – How much do they spend?) - CRM метрики, которая позволяет детально описать в трех переменных ранжированную совокупность клиентов. Однако сами авторы книги решили не прибегать к ее применению.
Компания **B2C** хочет увеличить доля клиентов, совершивших повторную покупку и сократить расходы на удержание клиентов, лучше понимая при этом, какие клиенты чаще всего покупают повторно за определенный период времени. Случайная выборка из 500 клиентов из одной когорты была взята из базы данных фирмы. Информация, необходимая для нашей модели, включает следующий список переменных:
| Переменные | Описание |
|:--------------- |:-------------------------------------------------------------------------------------|
| **Зависимая переменная** | |
| Purchase | если **1**, когда покупатель приобрел в данном квартале, **0**, если в этом квартале не произошло покупок |
| **Предикторы** | |
| Lag_Purchase | **1**, если клиент приобрел в предыдущем квартале, **0**, если в предыдущем квартале покупка не произошла |
| Avg_Order_Quantity | Средняя долларовая стоимость покупок во всех предыдущих кварталах |
| Ret_Expense | Доллары потраченные на маркетинговые усилия по удержанию этого клиента в данном квартале |
| Ret_Expense_SQ | Квадрат затрат на маркетинговые усилияпо удержанию этого клиента в данном квартале |
| Gender | **1**, если клиент является мужчиной, **0**, если клиент является женщиной |
| Married | **1**, если клиент женат, **0**, если клиент не состоял в браке |
| Income | **1**, если доход < 30 000 долл. США, **2**; если 30 001 долл. США < доход < 45 000 долл. США; **3**, если 45 001 долл. США < доход < 60 000 долл. США; **4**, если 60 001 долл. США < доход < 75 000 долл. США; **5**, если 75 001 долл. США < доход < 90 000 долл. США; **6**, если доход > 90 001 долл. США |
| First_Purchase | Стоимость первой покупки, сделанной клиентом в 1 квартале |
| Loyalty | **1**, если клиент является членом программы лояльности, **0**, если нет |
```{r Ch04 : Customer retention - Transformation data}
# Combine Data
library('sqldf') # Manipulate R Data Frames Using SQL
customerRetention <- sqldf("select distinct a.*, b.*
from customerRetentionTransactions a left join customerRetentionDemographics
b on a.customer = b.customer order by customer;")
# Repurchase Probability
customerRetentionRepurchase <- customerRetention %>%
mutate(lcustomer = lag(customer, 1), cb = if_else(crossbuy > 1, 1, 0)) %>% # Lag by customer
mutate(lpurchase = if_else(customer == lcustomer, lag(purchase), 0),
lcb = if_else(customer == lcustomer, lag(cb), 0),
lcrossbuy = if_else(customer == lcustomer, lag(crossbuy), 0)) %>%
mutate(lpurchase = if_else((quarter == 2), 1, lpurchase),
lcrossbuy = if_else((quarter == 2), 1, lcrossbuy),
lcb = if_else((quarter == 2), 0, lcb)) %>%
group_by(customer) %>%
mutate(quantity_sum = cumsum(order_quantity)) %>%
mutate(avg_order_quantity = quantity_sum / quarter) %>%
ungroup %>%
mutate(lavg_order_quantity = lag(avg_order_quantity, 1)) %>% # should `avg_order_quantity` by lag 1
mutate(ID = row_number()) %>%
arrange(desc(ID)) %>%
select(-one_of("ID", "quantity_sum", "customer..8")) %>%
filter(quarter != 1)
# Check for Class Imbalances
customerRetentionRepurchase$purchase %>%
factor() %>%
table() %>%
prop.test()
# ## Open workbook into temporary file
# openxlsx::addWorksheet(wb0 <- openxlsx::createWorkbook(), sheetName = "Output", gridLines = FALSE)
# openxlsx::writeData(wb0, sheet = 1, x = customerRetentionRepurchase, withFilter = TRUE); openxlsx::openXL(wb0)
```
Бинарный класс *"Повторной покупки"* получился сбалансированный - нулевую гипотезу о равном разбиении после теста пропорций долей следует признать верной.
Нужно смоделировать вероятность того, что клиент купит за данный период времени. Поскольку зависимая переменная (`purchase`) является бинарной, выбирают *логическую* регрессию для оценки модели. Также можно выбрать модель *пробита* и в целом достичь тех же результатов. В этом случае зависимая переменная представляет собой `Purchase`, а предикторы представляют девять независимых переменных.
### Построение и верификация модели *повторной покупки* {.tabset}
#### Logit
```{r Ch04 : Repurchase - Logit, warning=FALSE}
# # Fit Logistic Regression Model for Customer Retention by Authors
Ch04.logit <- glm(purchase ~ lpurchase + avg_order_quantity + ret_expense + ret_expense_sq +
gender + married + income + first_purchase + loyalty,
# lavg_order_quantity + factor(income) + factor(loyalty),
data = customerRetentionRepurchase, family = binomial(link = 'logit'))
summary(Ch04.logit)
writeLines(sprintf("-2 Log L of Intercept and Only Covariates: %.3f", -2 * logLik(Ch04.logit)[1]))
writeLines(sprintf(" AIC (smaller is better): %.3f", extractAIC(Ch04.logit)[2]))
# Odds Ratio Estimates and 95% CI
writeLines("\n Odds Ratio Estimates and 95% CI")
car::Confint(Ch04.logit) %>%
exp() %>%
arm::pfround(digits = 3)
writeLines("\n Wald test of predictors")
car::Anova(Ch04.logit, type="II", test="Wald")
writeLines("\n Variance Inflation Factors - if vif() > 2 - feature has multicollinearity with others")
car::vif(Ch04.logit) # Variance Inflation Factors - if vif() > 2 - feature has multicollinearity
writeLines("\n Repurchase Probability (Logit): Association of Predicted Probabilities and Observed Responses \n")
prob <- predict(Ch04.logit, newdata = customerRetentionRepurchase, type = "response")
caret::confusionMatrix(data = ifelse(prob > 0.5, "1", "0") %>% factor,
reference = customerRetentionRepurchase$purchase %>% factor,
positive = "1", mode = "everything")
```
Во-первых, это означает, что `Lag_Purchase` оказывает положительное влияние на текущую покупку, то есть клиенты, совершившие покупку в предыдущем квартале, с большей вероятностью совершают покупку в текущем квартале. Во-вторых, поскольку коэффициент по `Avg_Order_Quantity является` положительным и статистически значимым, это означает, что клиенты, которые в прошлом потратили больше в среднем, также чаще покупают в текущем периоде времени. В-третьих, авторы обнаружилм положительный, но уменьшающий доход от эффекта удерживающих расходов (Ret_Expense) при покупке в том же квартале, поскольку коэффициент на Ret_Expense положителен, а коэффициент Ret_Expense_SQ отрицателен. В-четвертых, нашли небольшой положительный эффект для женщин (отрицательный коэффициент по полу), что означает, что женщины, как правило, чаще приобретают, чем мужчины. В-пятых, обнаружен положительный эффект дохода, предполагающий, что клиенты, имеющие более высокий доход, с большей вероятностью будут покупать в текущем квартале. Наконец, поскольку коэффициент при лояльности положителен, это говорит о том, что клиенты, которые являются членами программы лояльности, с большей вероятностью будут покупать в текущем квартале.
Поскольку проблема *несбалансированности классов* практически отсутствует, то в качестве меры точности модели можно рекомендовать коэффициента **Cohen's Kappa** и **коэффициент аккуратности**.
#### Logit (Version AR)
Следует заметить, что расчет среднеквартального объема заказа `avg_order_quantity` при подсчете по приведенному в книге коду **SAS** фактически включает также *текущий квартал*. Хотя в описании авторы указали, что среднеквартальных объем заказа относиться только в предыдущим месяцам. В результате возникает смещение, учитывающее влияние объема заказа текущего квартала, которые и следует предсказывать, что особенно заметно проявляется в первых кварталах наблюдений. На мой взгляд было бы более точным брать предиктором `avg_order_quantity` с однопериодным лагом (кварталом).
Замечено, что если предикторы `income` и `loyalty` объявить порядковым и бинарным факторами, соответствено, а незначимые признаки `married`, `first_purchase` вовсе удалить, то и с меньшим числом предикторов можно получить устойчивую логистическую модель, но без смещения средних продаж на текущий квартал. Кроме того, в связи со значительной **мультиколлинеарностью** показателей затрат на удержание в текущем квартале и их квадрата - `ret_expense` и `ret_expense_sq` следует исключить.
```{r Ch04 : Repurchase Logit Improved, warning=FALSE}
# Fit Logit Regression Model for Customer Repurchase (Improved)
uno = 'logit'
set.seed(2018) #From random.org
(Ch04lg.AR <- train(factor(purchase) ~ lpurchase + lavg_order_quantity + ret_expense +
ordered(income) + first_purchase + factor(loyalty), metric = 'Kappa',
data = customerRetentionRepurchase, method = "glm", family = binomial(link = uno)))#,
# trControl = trainControl(method = "none", number = 1)))
summary(Ch04lg.AR)
# Odds Ratio Estimates and 95% CI
writeLines("\n Odds Ratio Estimates and 95% CI")
car::Confint(Ch04lg.AR$finalModel) %>%
exp() %>%
arm::pfround(digits = 3)
# Logistic regression diagnostics
writeLines("\n Wald test of predictors")
car::Anova(Ch04lg.AR$finalModel, type="II", test="Wald")
writeLines("\n Variance Inflation Factors - if vif() > 2 - feature has multicollinearity with others")
car::vif(Ch04lg.AR$finalModel) # Variance Inflation Factors - if vif() > 2 - feature has multicollinearity
writeLines("\n Variable Importance for Model \n")
caret::varImp(Ch04lg.AR) %>% .$importance %>% print.AsIs()
# Create the scatter plots Logit versus model predictors
# prob <- predict(Mod04lg.AR, newdata = customerRetentionRepurchase, type = "prob")[, "1"]
# mutate(logit = log(prob / (1 - prob))) %>%
set.seed(2018)
Ch04LG.AR <- train(factor(purchase) ~ lpurchase + lavg_order_quantity + ret_expense +
income + first_purchase + loyalty, metric = 'Kappa',
data = customerRetentionRepurchase, method = "glm", family = binomial(link = uno))
predictors <- Ch04LG.AR$coefnames
Ch04LG.AR$trainingData %>%
dplyr::select(one_of(predictors)) %>%
mutate(link = predict(Ch04LG.AR$finalModel, newdata = customerRetentionRepurchase, type = "link")) %>%
gather(key = "predictors", value = "predictor.value", -link) %>%
ggplot(aes(predictor.value, link))+
geom_point(size = 0.05, alpha = 0.05) +
geom_smooth(method = "loess") +
facet_wrap(~ predictors, scales = "free_x") +
ylab(stringr::str_to_title(uno))
remove(Ch04LG.AR)
# Plot matrix of statistical model diagnostics
GGally::ggnostic(Ch04lg.AR$finalModel, title = paste(paste(formula(Ch04lg.AR)[c(2, 1, 3)], collapse = " ")))
# wide variety of diagnostic plots for checking the quality of regression fit
# https://bookdown.org/jefftemplewebb/IS-6489/logistic-regression.html
car::influenceIndexPlot(Ch04lg.AR$finalModel)
writeLines("\n Improved Logit Model: Association of Predicted Probabilities and Observed Responses \n")
caret::confusionMatrix(data = predict(Ch04lg.AR, newdata = customerRetentionRepurchase),
reference = customerRetentionRepurchase$purchase %>% factor,
positive = "1", mode = "everything")
qplot(`Observed Classes`, `Predicted Classes`,
data=bind_cols(`Observed Classes`= factor(customerRetentionRepurchase$purchase),
`Predicted Classes` = predict(Ch04lg.AR, newdata = customerRetentionRepurchase)),
colour= `Observed Classes`, geom = c("boxplot", "jitter"),
main = "Predicted Classes vs. Observed Classes", xlab = "Observed Classes", ylab = "Predicted Classes")
```
Но авторы на такие шаги не пошли, вероятно, для большей дидактической ясности. Правда, аккуратность модели с лагом, т. е. `**l**avg_order_quantity` будет немного ниже, но зато устойчивость (модель получена бутстреп-методом - англ. `bootstrap` с 25-тью "псевдовыборок") станет существенной.
### Как это использовать?
Авторы полагали, что поведение при проведении транзакций в прошлом, скорее всего, объяснит будущее поведение покупателей. В результате в этом примере они использовали несколько операций из предыдущего квартала по отношению текущему в качестве независимых переменных (предикторов). В дальнейшем менеджерам будет полезно знать какие драйверы влияют на поведения последующих покупок клиентами.
Во-первых, авторы знают, приобрел ли покупатель в последнем квартале (`Lag_Purchase`). Эта переменная может быть получена путем принятия запаздывающего значения переменной индикатора покупки, отмечая, что одно наблюдение будет потеряно для каждого клиента. В этом случае мы используем только однопериодное отставание - квартальное. Во-вторых, мы имеем среднюю величину прошлых заказов (`Avg_Order_Quantity`). В этом случае значение для среднего количества заказа является средним значением переменной `Order_Quantity` во всех кварталах до текущего периода времени (как я показал выше, фактически это нет и текущий период авторами включается в расчет средней). В-третьих, у авторам известно, сколько долларов фирма потратила на каждого клиента (`Ret_Expense`) за каждый период времени и квадрат значения этой переменной (`Ret_Expense_SQ`). Авторы хотили использовать как линейные, так и квадратичные термины, так как ожидали, что для каждого дополнительного доллара, потраченного на усилия по удержанию для данного клиента, будет уменьшаться возврат к стоимости этого доллара (*"закон убывающей доходности"*). Наконец, поскольку фирма этого примера относится к сектору **B2C**, остальные пять переменных являются социально-демографическими характеристиками клиентов. К ним относятся пол клиента `gender`, является ли клиент женатым (`married`), порядковый ранг дохода клиента (`income`), стоимость первой покупки клиента (`First_Purchase)` и является ли клиент членом программы *лояльности* (`loyalty`).
В результате мы теперь знаем, как изменения в расходах на удержание, прошлые транзакции клиентов и характеристики клиентов могут либо увеличить, либо уменьшить вероятность последующих покупок. И мы также знаем, что эти драйверы споосбы быть полезными, помогая нам предсказать, собирается ли клиент купать или нет. Эта информация может дать значительную информацию руководителям, которым поручено определить оптимальный объем ресурсов для проведения усилий по удержанию.
## Эмпирический пример: Продолжительность сотрудничества с клиентом
Один из ключевых вопросов, на которые авторы хотят ответить в отношении продолжительности жизни, заключается в том, можем ли мы определить, какие клиенты имеют наибольшую вероятность быть активными в будущем. В условиях без контракта это означает оценку вероятности того, что клиент в настоящее время активен, учитывая его прошлую историю покупок. В случае контрактных установок это означает оценку ожидаемого срока службы клиентов, которые еще не получили недостатков, учитывая историческую информацию обо всех клиентах в прошлом (в том числе тех, кто уже отказался от сотрудничества). Это часто делается с использованием моделей Времени Ускореннного Отказа (англ. `Accelerated Failure Time (AFT) Models`) или Пропорциональной Опасности (англ. `Proportional Hazards (PH) models`). Поскольку данные, приведенные в этой главе, представляют собой неконтрактную установку (т. е. авторы не наблюдали непосредственно завершение сотрудничества с клиентами), их цель - определить вероятность того, что клиент активен, учитывая прошлую историю покупок клиента. Для этого нам необходимо иметь информацию о поведении транзакций каждого клиента, включая время первой покупки, время последней покупки и количество транзакций, которые произошли во время окна наблюдения. В наборе данных, приведенном в этой главе, авторы подробно описывали историю транзакций для каждого клиента. Просто нужно вычислить значения для каждой из трех требуемых переменных. В ходе этого примера можно определить следующее:
1. Вероятность того, что клиент активен в конце конца наблюдений (12-го квартала).
Компания B2C хочет улучшить свою способность идентифицировать клиентов, которые, вероятно, будут активно участвовать в отношениях с фирмой. Случайная выборка из 500 клиентов из одной когорты была взята из базы данных клиентов. Информация, необходимая для модели авторов, включает следующий список переменных:
| Переменные | Описание |
|:--------------- |:-------------------------------------------------------------------------------------|
| x | Количество транзакций данного клиента за все периоды времени. Здесь мы предполагаем, что это сумма переменной Purchase, где клиенты в наибольшей степени совершили 1 покупку за квартал |
| tx | Это время последней транзакции, то есть последний квартал, где наблюдалось `Purchase == 1` |
| T | Общее время между первой покупкой и окончанием окна наблюдения, то есть 12 кварталов для всех клиентов |
В этом случае авторы не имели зависимую переменную, так как фактически не наблюдали отток клиентов. Вместо этого они использовали атрибуты информации о транзакции клиента для формирования вероятности того, что клиент активен. Во первых, в этом случае нам требуется количество транзакций, которые клиент имел в окне наблюдения (`x`), в данном примере - 12 кварталов. Чтобы упростить этот случай, предполагается, что клиенты покупают не более одного раза в любом квартале. Таким образом, при `Purchase == 1` наблюдается как бы одну транзакция. Во-вторых, требуется, чтобы последний раз, когда у клиента была транзакция с фирмой (`tx`). В этом случае это последний квартал, где наблюдалось `Purchase == 1`. Наконец, также требуется продолжительность времени, когда клиент мог быть активным. Поскольку это когорта клиентов, которые сделали первые покупки в первом квартале, все они получают значение **12** для `T`.
Так как в сегменте **B2C** фирмы зачастую не имеют долгосрочных контрактов, то для построения модели продолжительности сотрудничества с клиентом без контрактных установок применяют подход BG/NBD (от англ. `"Beta Gamma / Negative Binomial Distribution"`), [описанный](http://brucehardie.com/papers/018/fader_et_al_mksc_05.pdf) в 2005 г.:
$$ L(r, \alpha, a, b|X=x, t_x, T) = \dfrac{B(a, b + x + 1)}{B(a, b)} \dfrac{\Gamma(r + x) \alpha ^r }{\Gamma(r)(\alpha + T) ^{r + x} } + \dfrac{B(a + 1, x)}{B(a, b)} \dfrac{\Gamma(r + x) \alpha ^r }{\Gamma(r)(\alpha + t_x) ^{r + x}} , $$
где B(˚) - функция бета-распределения,
G(˚) - функция гамма-распределения,
a и b - параметры функции бета-распределения,
r и $\alpha$ - параметры функции гамма-распределения, и
x, tx, и T - данные по клиентам без контрактных установок от фирмы.
Описание в *MS Excel* данного подхода к построению модели BG/NBD, благодаря Брюсу Харди, имеется на странице [Implementing the BG/NBD Model for Customer Base Analysis in Excel](http://www.brucehardie.com/notes/004/)
Несложно заметить, что показатель `tx` соответствует признаку **Recency** из упоминавшейся выше модели **RFM**, а `x` - **Frequency**. В стороне остается только **Monetary Value**, сумма сделок `order_quantity` по каждому клиенту за весь период наблюдений `T`, т.е. за **12** кварталов. Далее мы рассчитаем недостающий показатель и полноценно применим эти сведения для прогнозирования.
Бельгийский исследователь Тобиас Вербеке предусмотрительно подготовил обозначенный авторами набор данных в пакете [`SMCRM`](http://cran.rstudio.com/web/packages/SMCRM) - `customerRetentionLifetimeDuration`, содержащий сведения о продолжительности сотрудничества клиентов с фирмой. Однако мы можем его получить самостоятельно прямо исполнив команды **SQL** из приведенного кода **SAS** благодаря пакету [`sqldf`](http://cran.rstudio.com/web/packages/sqldf) в составе **R**.
```{r Ch04 : customerRetention - LifetimeDuration Data }
# P(Alive)
palive_x <- sqldf("select customer, sum(purchase) as x
from customerRetentionTransactions
group by customer order by customer;")
palive_tx <- sqldf("select customer, max(quarter) as tx
from customerRetentionTransactions
where purchase = 1 group by customer order by customer;")
palive_T <- sqldf("select customer, max(quarter) as T, sum(order_quantity) as M
from customerRetentionTransactions group by customer order by customer;")
palive_xtx <- sqldf("select a.*, b.tx
from palive_x a left join palive_tx b
on a.customer = b.customer;")
customerRetentionLTDuration <- sqldf("select distinct a.*, b.T, b.M
from palive_xtx a left join palive_T b
on a.customer = b.customer order by customer;")
remove(palive_x, palive_tx, palive_T, palive_xtx)
# Description of an empirical distribution for non-censored data using Cullen & Frey graph
library('fitdistrplus')
fitdistrplus::descdist(customerRetentionLTDuration$x, boot = 500, discrete = FALSE)
x <- fitdist((customerRetentionLTDuration$x / max(customerRetentionLTDuration$x)),
"beta", method = "mme", discrete = FALSE)
plot(x)
writeLines("\n Beta distribution of `customerRetentionLTDuration$x`")
gofstat(x)
fitdistrplus::descdist(customerRetentionLTDuration$tx, boot = 500, discrete = FALSE)
(x <- fitdist((customerRetentionLTDuration$tx / max(customerRetentionLTDuration$tx)),
"beta", method = "mme", discrete = FALSE))
plot(x)
writeLines("\n Beta distribution of `customerRetentionLTDuration$x`")
gofstat(x)
```
Независимые переменные `x`, `tx`, `M` из нового набора данных `customerRetentionLTDuration` распределены по непрерывному бета-распределению
Теперь у нас в распоряжении полный набор данных для построения модели *продолжительности сотрудничества с клиентом* и при помощи пакета [`Buy ’Til You Die - BTYD`](http://cran.rstudio.com/web/packages/BTYD). Должен заметить, что в пакете **SAS** нельзя напрямую рассчитать эти параметры.
Вероятность активности на момент времени T клиента без контрактных установок рассчитывается по формуле:
$$ P(Alive \enspace | \enspace r, \alpha, a, b, x, t_x, T) = 1 / \left\{ 1 + \dfrac{a}{b + x} \left( \dfrac{\alpha + T }{\alpha + t_x }\right) ^{r + x} \right\} $$
```{r Ch04 : BG/NBD}
# Customers without contractual settings : Buy ’Til You Die - Beta Gamma / Negative Binomial Distribution
# http://srepho.github.io/CLV/CLV
library('BTYD') # Implementing Buy 'Til You Die Models
cal.cbs <- customerRetentionLTDuration %>%
dplyr::select(x, tx, `T`) %>% # calibration period CBS (customer by sufficient statistic)
dplyr::rename(x = x, t.x = tx, T.cal = `T`)
params <- BTYD::bgnbd.EstimateParameters(cal.cbs)
LL <- BTYD::bgnbd.cbs.LL(params, cal.cbs)
params <- c(params, LL)
names(params) <- c("r", "alpha", "a", "b", "LL (Log-likelihood)")
# Parameters from the book
params0 <- c(126.5368069, 159.8644711, 0.512114268, 3.328751451, -4676.1)
names(params0) <- c("r", "alpha", "a", "b", "LL (Log-likelihood)")
writeLines("\n BG/NBD Model: Parametres of AR Prediction \n")
params
writeLines("\n BG/NBD Model: Parametres of V. Kumar, J. Andrew Petersen Prediction \n")
params0
P_Alive <- customerRetentionLTDuration %>%
mutate(p = 1/(1+(params["a"]/(params["b"] + x))*
((params["alpha"] + `T`)/(params["alpha"] + tx))^(params["r"] + x)))
utils::data(customerRetentionLifetimeDuration, package = 'SMCRM')
P_Alive0 <- customerRetentionLifetimeDuration %>%
mutate(p = 1/(1+(params0["a"]/(params0["b"] + x))*
((params0["alpha"] + `T`)/(params0["alpha"] + tx))^(params0["r"] + x)))
writeLines("\n BG/NBD Model: Association of AR Prediction vs. V. Kumar, J. Andrew Petersen Prediction \n")
caret::confusionMatrix(data = ifelse(P_Alive$p > 0.5, "1", "0") %>% factor,
reference = ifelse(P_Alive0$p > 0.5, "1", "0") %>% factor,
dnn = c("AR Prediction", "V. Kumar, J. Andrew Petersen Prediction"),
positive = "1", mode = "everything")
customerRetentionLTDuration$p <- P_Alive0$p
remove(params, P_Alive, params0, P_Alive0)
```
Хотя в моих расчетах, которые производились не в *MS Excel*, а в специализированном пакете [BTYD](https://cran.r-project.org/web/packages/BTYD/) для **R**, получены неcколько иные параметры бета- и гамма- распределений. Возможно из-за разных алгоритмов оптимизации, во всяком случае логарифмическое правдоподобие (англ. "`Log-likelihood [LL]`") у них практически совпадают. Схоже и попадание в классы по авторскому разбиению. Разница лишь в том, что по авторской модели BG/NBD клиенты которые совершили лишь две покупки (в начале окна наблюдения - в 1 квартале и почти за год до его завершения - в 9 квартале) по-прежнему считаются активными, а по более строгому алгоритму оптимизации нужно совершить между этими двумя крайними трансакциями хотя бы еще одну покупку. Это представляется более разумным при построении модели *продолжительности сотрудничества с клиентом*, чем опора только на две точки взаимодействия с фирмой.
### Как это использовать?
Такой подход к моделированию *продолжительности сотрудничества с клиентом* в условия отсутстия контрактных установок представляется крайне полезным для менеджемента, давая ему возможность оптимально управлять расходами на удержание клиентов.
## Эмпирический пример: величина заказа
Многие фирмы поняли, что недостаточно просто сосредоточиться только на попытке заставить клиента выкупить. Фирма также должна обратить внимание на то, каким размером может оказать покупка. Исследования в области маркетинга показали, что стоимость заказа может быть ценным предиктором в будущей стоимости клиента для фирмы - или, по крайней мере, оправдать сумму денег, затрачиваемую на усилия по удержанию клиентов. Таким образом, может быть полезно понять драйверы величины заказов и, в свою очередь, иметь возможность прогнозировать ожидаемую величину заказов каждого потенциального клиента при условии, что заказ будет иметь место. В конце этого примера мы должны иметь возможность сделать следующее:
1. Определить драйверы величину заказа (по стоимости).
2. Предсказать ожидаемую величину заказа для каждого клиента.
3. Измерить предиктивную точность модели.
Информация, необходимая для этой модели, включает следующий список переменных:
| Переменные | Описание |
|:--------------- |:-------------------------------------------------------------------------------------|
| **Зависимая переменная** | |
| Purchase | если **1**, когда покупатель приобрел в данном квартале, **0**, если в этом квартале не произошло покупок |
| Order_quantity | Долларовая стоимость покупок в данном квартале |
| **Предикторы** | |
| imr_purchase или *Lambda* ($\lambda$) | Рассчитанное *обратное отношение Миллса* из модели повторного заказа клиента |
| Lag_Purchase | **1**, если клиент приобрел в предыдущем квартале, **0**, если в предыдущем квартале покупка не произошла |
| Avg_Order_Quantity | Средняя долларовая стоимость покупок во всех предыдущих кварталах |
| Ret_Expense | Доллары потраченные на маркетинговые усилия по удержанию этого клиента в данном квартале |
| Ret_Expense_SQ | Квадрат затрат на маркетинговые усилияпо удержанию этого клиента в данном квартале |
| Gender | **1**, если клиент является мужчиной, **0**, если клиент является женщиной |
| Married | **1**, если клиент женат, **0**, если клиент не состоял в браке |
| Income | **1**, если доход < 30 000 долл. США, **2**; если 30 001 долл. США < доход < 45 000 долл. США; **3**, если 45 001 долл. США < доход < 60 000 долл. США; **4**, если 60 001 долл. США < доход < 75 000 долл. США; **5**, если 75 001 долл. США < доход < 90 000 долл. США; **6**, если доход > 90 001 долл. США |
| First_Purchase | Стоимость первой покупки, сделанной клиентом в 1 квартале |
| Loyalty | **1**, если клиент является членом программы лояльности, **0**, если нет |
Из вышеописанных перменных мы видим, что для определения драйверов величины заказов нам нужно иметь две зависимые переменные: `Purchase` and `Order_Quantity`. Это связано с тем, что ожидаемая величина заказа получается из следующего уравнения:
$$ E(Order \enspace Quantity) = P(Purchase = 1) * E(Order \text _ quantity | Purchase = 1) $$
Смещение выборки является проблемой, которая распространена во многих маркетинговых проблемах и должна быть статистически учтена во многих процессах моделирования. В этом случае у клиента есть выбор: покупать или не покупать, прежде чем принимать решение о покупке. Если бы мы проигнорировали этот выбор, мы бы смещали оценки от модели, и у нас были бы менее точные предсказания для значения `Order_Quantity`. Чтобы учесть эту проблему, мы должны иметь возможность предсказать величину как вероятности покупки (аналогично тому, что мы сделали для первого эмпирического примера в этой главе), так и ожидаемого значения `Order_Quantity`, учитывая, что клиент должен сделать покупку. Важно отметить, что мы не можем просто запускать две модели независимо, так как, вероятно, существует корреляция между условиями ошибки двух моделей. Таким образом, авторы указывают на необходимость использовать структуру моделирования, которая может одновременно оценивать коэффициенты двух моделей или, по крайней мере, учитывать соотношение между `Order_Quantity` и `Purchase`. Для этого мы используем двухэтапную структуру моделирования, аналогичную описанной ранее в [третьей главе](https://rpubs.com/A_Rodionoff/SMCRM_Ch03). Первым этапом идет формирование *пробит-модели*, дающей нам *обратное отношение Миллса* ($\lambda$).
### Первый этап построения и верификации *величины заказа* {.tabset}
#### Probit
```{r Ch04 : Repurchase Probit}
# Fit Probit Model for Customer Repurchase by Authors
Ch04.probit <- glm(purchase ~ lpurchase + avg_order_quantity + ret_expense + ret_expense_sq +
gender + married + income + first_purchase + loyalty,
data = customerRetentionRepurchase, family = binomial(link = 'probit'))
summary(Ch04.probit)
writeLines(sprintf("-2 Log L of Intercept and Only Covariates: %.3f", -2 * logLik(Ch04.probit)[1]))
writeLines(sprintf(" AIC (smaller is better): %.3f", extractAIC(Ch04.probit)[2]))
writeLines("\n Wald test of predictors")
car::Anova(Ch04.probit, type="II", test="Wald")
writeLines("\n Variance Inflation Factors - if vif() > 2 - feature has multicollinearity with others")
car::vif(Ch04.probit) # Variance Inflation Factors - if vif() > 2 - feature has multicollinearity
writeLines("\n Probit Model: Association of Predicted Probabilities and Observed Responses \n")
prob <- predict(Ch04.probit, newdata = customerRetentionRepurchase, type = "response")
caret::confusionMatrix(data = ifelse(prob > 0.5, "1", "0") %>% factor,
reference = customerRetentionRepurchase$purchase %>% factor,
positive = "1", mode = "everything")
```
Качество решения классификационной задачи *повторной покупки* довольно высокое.
#### Probit (AR Version)
Вместе с тем очевидно, что предикторы `married` и `first_purchase` не значимы в пробит-регрессии, что отмечают даже авторы. Недалеко от них ушел по значимости фактор `gender`. Также вместо полученной со смещением переменной `avg_order_quantity` я буду использовать корректно рассчитанную `lavg_order_quantity`. Кроме того, проверка по **VIF** демонстрирует большие значения по признакам `acq_expense` и `acq_expense_sq`. Однако, принимая во внимание проявление *закона убывающей доходности* мы должны оставить оба *мультиколлинеарных* предиктора в этой модели. Теперь бинарную модель мы проверяем более тщательно, оставля только значимые предикторы.
```{r Ch04 : Repurshase Probit Improved, warning=FALSE}
# Fit Probit Regression Model for Customer Repurchase (Improved)
uno = 'probit'
set.seed(2018)
(Ch04pr.AR <- train(factor(purchase) ~ lpurchase + lavg_order_quantity + ret_expense + ret_expense_sq +
income + loyalty, metric = 'Kappa',
data = customerRetentionRepurchase, method = "glm", family = binomial(link = uno)))#,
# trControl = trainControl(method = "none", number = 1)))
summary(Ch04pr.AR)
# Odds Ratio Estimates and 95% CI
writeLines("\n Odds Ratio Estimates and 95% CI")
car::Confint(Ch04pr.AR$finalModel) %>%
exp() %>%
arm::pfround(digits = 3)
# Logistic regression diagnostics
writeLines("\n Wald test of predictors")
car::Anova(Ch04pr.AR$finalModel, type="II", test="Wald")
writeLines("\n Variance Inflation Factors - if vif() > 2 - feature has multicollinearity with others")
car::vif(Ch04pr.AR$finalModel) # Variance Inflation Factors - if vif() > 2 - feature has multicollinearity
writeLines("\n Variable Importance for Model \n")
caret::varImp(Ch04pr.AR) %>% .$importance %>% print.AsIs()
# Create the scatter plots Probit versus model predictors
predictors <- Ch04pr.AR$coefnames
Ch04pr.AR$trainingData %>%
dplyr::select(one_of(predictors)) %>%
mutate(link = predict(Ch04pr.AR$finalModel, newdata = customerRetentionRepurchase, type = "link")) %>%
gather(key = "predictors", value = "predictor.value", -link) %>%
ggplot(aes(predictor.value, link))+
geom_point(size = 0.05, alpha = 0.05) +
geom_smooth(method = "loess") +
facet_wrap(~ predictors, scales = "free_x") +
ylab(stringr::str_to_title(uno))
# Plot matrix of statistical model diagnostics
GGally::ggnostic(Ch04pr.AR$finalModel, title = paste(paste(formula(Ch04pr.AR)[c(2, 1, 3)], collapse = " ")))
# wide variety of diagnostic plots for checking the quality of regression fit
# https://bookdown.org/jefftemplewebb/IS-6489/logistic-regression.html
car::influenceIndexPlot(Ch04pr.AR$finalModel)
writeLines("\n Improved Probit Model: Association of Predicted Probabilities and Observed Responses \n")
caret::confusionMatrix(data = predict(Ch04pr.AR, newdata = customerRetentionRepurchase),
reference = customerRetentionRepurchase$purchase %>% factor,
positive = "1", mode = "everything")
qplot(`Observed Classes`, `Predicted Classes`,
data=bind_cols(`Observed Classes`= factor(customerRetentionRepurchase$purchase),
`Predicted Classes` = predict(Ch04pr.AR, newdata = customerRetentionRepurchase)),
colour= `Observed Classes`, geom = c("boxplot", "jitter"),
main = "Predicted Classes vs. Observed Classes", xlab = "Observed Classes", ylab = "Predicted Classes")
```
Улучшенная пробит-регрессия *вероятности повторной покупки* хотя и снизила немного качества, получена без незначимых факторов `gender` и `married`, а также предиктора `first_purchase`, поэтому мне представляется более надежной, так как избавилась от этих малозначимых признаков и более устойчивой, так как модель построена бутстреп-методом - англ. `bootstrap` с 25-тью "псевдовыборок".
### Второй этап построения и верификации модели *величины заказа* {.tabset}
Переходим ко второму этапу модели *величины заказа*, которая использует в качестве предиктора результаты пробит-модели из первого этапа, обозначенное как *обратное отношение Миллса* ($\lambda$).
#### Linear
```{r Ch04 : Order quantity - Linear Regression}
# Fit Linear Regression Model for Order quantity by Authors
# SAS Code: imr_acquisition = (pdf(’Normal’, xb_probit))/(probnorm(xb_probit));
xbeta <- predict(Ch04.probit, newdata = customerRetentionRepurchase, type = "link")
customerRetentionRepurchase <- customerRetentionRepurchase %>%
mutate(imr_purchase = dnorm(xbeta) / pnorm(xbeta)) # Cumulative normal pdf
(Ch04.linear <- lm(order_quantity ~ lpurchase + avg_order_quantity + ret_expense +
ret_expense_sq + gender + married + income + first_purchase + loyalty + imr_purchase,
data = filter(customerRetentionRepurchase, order_quantity > 0) )) %>%
summary
writeLines("Variance Inflation Factors - if vif() > 2 - feature has multicollinearity with others")
car::vif(Ch04.linear) # Variance Inflation Factors - if vif() > 2 - feature has multicollinearity
```
Авторы получили результаты, говорящие что регрессионная задача решена удовлетворительно. Мы видим, что $\lambda$ является положительной и значимой. Можно её интерпретировать так, что существует потенциальная проблема смещения выбора, поскольку коэффициент ошибки нашего уравнения выбора положительно коррелирует с погрешностью нашего уравнения пробит-регрессии. Также видно, что все другие переменные модели *величины заказов* являются значимыми, за исключением `Married`, что означает, вероятно, обнаружение многие из драйверов величины заказа.
#### Linear (AR version)
Теперь попробуем исключить из линейной модели незначимый фактор `married`, а вместо полученной со смещением переменной `avg_order_quantity` использовать корректно рассчитанную `lavg_order_quantity`.
```{r Ch04 : Order quantity - Linear Regression Improved, warning=FALSE}
# Fit Linear Regression Model for Customer Order quantity (Improved)
uno = 'y_hat'
# Log Transformation of Order_Quantity
customerRetentionRepurchase <- customerRetentionRepurchase %>%
mutate(log_order_quantity = log(order_quantity))
set.seed(2018)
(Ch04ln.AR <- train(log_order_quantity ~ lpurchase + lavg_order_quantity + ret_expense + ret_expense_sq +
gender + income + first_purchase + imr_purchase,
data = filter(customerRetentionRepurchase, order_quantity > 0), method = "lm"))#,
# trControl = trainControl(method = "none", number = 1)))
summary(Ch04ln.AR)
#Coefficient Estimates and 95% CI
writeLines("\n Coefficient Estimates and 95% CI")
car::Confint(Ch04ln.AR$finalModel) %>%
exp() %>%
arm::pfround(digits = 3)
# Linear regression diagnostics
writeLines("\n Chisq test of predictors")
car::Anova(Ch04ln.AR$finalModel, type="II", test="Chisq")
writeLines("\n Variance Inflation Factors - if vif() > 2 - feature has multicollinearity with others")
car::vif(Ch04ln.AR$finalModel) # Variance Inflation Factors - if vif() > 2 - feature has multicollinearity
writeLines("\n Variable Importance for Model \n")
caret::varImp(Ch04ln.AR) %>% .$importance %>% print.AsIs()
# Create the scatter plots Linear Model versus model predictors
# https://stats.idre.ucla.edu/r/seminars/ggplot2_intro/
predictors <- Ch04ln.AR$trainingData %>% colnames(.) %>% .[-1]
Ch04ln.AR$trainingData %>%
rename(y_hat = `.outcome`) %>%
gather(key = "predictors", value = "predictor.value", -y_hat) %>%
ggplot(aes(predictor.value, y_hat))+
geom_point(size = 0.5, alpha = 0.5) +
geom_smooth(method = "loess") +
facet_wrap(~ predictors, scales = "free_x") +
ylab(stringr::str_to_title(uno))
# Plot matrix of statistical model diagnostics
GGally::ggnostic(Ch04ln.AR$finalModel, title = paste(paste(formula(Ch04ln.AR)[c(2, 1, 3)], collapse = " ")))
# wide variety of diagnostic plots for checking the quality of regression fit
# https://bookdown.org/jefftemplewebb/IS-6489/linear-regression.html
car::influenceIndexPlot(Ch04ln.AR$finalModel)
```
Исключение из модели факторов `married` и даже `loyalty` не нанесло какого-либо вреда качеству модели. Однако избавление от смещения по независимой переменной `avg_order_quantity` понизило качество линейной модели. Чтобы его поднять пришлось прибегнуть к логарифмированию зависимой переменной `order_quantity` и независимой `lavg_order_quantity`, что часто применяется в эконометрических моделях на стоимостных показателях, имеющих склонность к лог-нормальному распределению.
### Как это использовать?
Авторы нашли, что `Lag_Purchase` положительна, предполагая, что покупатели, купившие в предыдущем квартале, с большей вероятностью потратят также в текущем квартале. Также обнаружено, что `Avg_Order_Quantity` как и `Lag_Avg_Order_Quantity` также является положительным, предполагая, что чем выше средние значения прошлые величины заказов клиента, тем выше текущее значение значение. Очевидно, что `Ret_Expense` имеет положителеный коэфициент с уменьшающимся возвратом, как отмечено положительным коэффициентом на `Ret_Expense` и отрицательным коэффициент для `Ret_Expense_SQ`. Это означает, что маркетинговые усилия, направленные на сохранение и построение отношений с клиентом, заставляют клиента приобретать больше, лишь до определенной степени. Затем, после достижения некоторого порога, маркетинговые усилия фактически снижают стоимость покупки в среднем. Вероятно, это связано с тем, что чрезмерное общение с клиентами может часто напрягать клиентов и подвергать эрозии отношения между ними и фирмой. Авторы обнаружили, что несколько характеристик клиента являются положительными (`Income`, `First_Purchase`), давая менеджерам вполне разумную мысль о том, что клиенты, которые имеют более высокий доход, как впрочем имеющие более высокую стоимость первой покупки, как правило, имеют большую величину заказа.
Следующий шаг - предсказать значение `Order_Quantity`, чтобы увидеть, насколько авторская модель совпадает с фактическими значениями.
```{r Ch04 : Error of Linear Model}
# Computing the Mean Absolute Deviation (MAD) and Mean Absolute Percent Error (MAPE)
with(customerRetentionRepurchase, {
# pred_oq <- predict(Ch04pr.AR$finalModel, newdata = customerRetentionRepurchase, type = "link") %>% pnorm() *
# exp(predict(Ch04ln.AR$finalModel, newdata = customerRetentionRepurchase))
pred_oq <- predict(Ch04.probit, newdata = customerRetentionRepurchase, type = "link") %>% pnorm() *
predict(Ch04.linear, newdata = customerRetentionRepurchase)
# mean_order_quantity
writeLines(sprintf("Mean of Order_Quantity: %.2f долл.", mean(customerRetentionRepurchase$order_quantity)))
# mad = mean(abs(first_purchase - pred_oq));
writeLines(sprintf("Mean Absolute Deviation (MAD): %.2f долл.", mean(abs(order_quantity - pred_oq))))
# mad1 = mean(abs(order_quantity - mean(order_quantity));
mad1 <- mean(abs(order_quantity - mean(order_quantity)))
writeLines(sprintf("Naive Mean Absolute Deviation (MAD1): %.2f долл.", mad1))
})
```
Поскольку значительное количество клиентов не заказывало ещеквартально повторные заказы, то метрику MAPE рассчитать авторам не удалось. Среднее значение по всей выборочной совокупности заказов (без первого квартала) составило `r sprintf("%.2f", mean(customerRetentionRepurchase$order_quantity))` долл. Этот показатель авторы применили в качестве *наивного* прогноза. Созданная ими модель *величины заказов* оказалось заметно аккуратнее *наивной* модели среднего, у которого MAD1 = `r sprintf("%.2f", mean(abs(customerRetentionRepurchase$order_quantity - mean(customerRetentionRepurchase$order_quantity))))` долл.
## Эмпирический пример: перекрестные продажи
Перекрестные продажи (англ. "`Cross-buying`") - это наиболее распространенная технология, используемая компаниями для увеличения числа случаев повторного приобретения, величины заказа и доходов компаний. После того, как компании создали определенный уровень лояльности с существующими клиентами, эти клиенты с большей вероятностью будут перекрестно покупать у компании.
Еще один ключевой вопрос, на который авторы книги хотели ответить в отношении удержания клиентов, заключается в том, можно ли определить, какие клиенты имеют наивысшую вероятность перекрестых продаж в нескольких категориях. Для этого сначала нужно знать, какие текущие клиенты фактически приобретали в нескольких категориях, когда они совершили покупку.
В наборе данных, представленном в этой главе, имеется переменная `Crossbuy`, которая идентифицирует, сколько категорий продуктов покупает покупатель за определенный период времени. Также предоставляется набор драйверов, которые, вероятно, помогут объяснить решение клиента о перекрестной покупке. В конце этого примера читатели смогут сделать следующее:
1. Определить драйверы поведения при перекрестных покупок клиента.
2. Интерпретировать оценки параметров из модели перекрестной покупки.
3. Предсказать может ли клиент перекрестно купить или нет.
4. Определить предиктивную точность модели перекрестной покупки.
Компания B2C хочет понять, какие клиенты, скорее всего, перекрестно покупают за данный период времени. Это важно знать, поскольку многие исследования показали, что клиенты, покупающие по нескольким категориям, с большей вероятностью будут более прибыльными, чем покупатели, которые покупают меньшее количество категорий. Случайная выборка из 500 клиентов из одной когорты была взята из базы данных клиентов. Информация, необходимая для нашей модели, включает следующий список переменных:
| Переменные | Описание |
|:--------------- |:-------------------------------------------------------------------------------------|
| **Зависимая переменная** | |
| Crossbuy | Количество различных категорий товаро / услуг, приобретенных в данном квартале |
| **Предикторы** | |
| Lag_Purchase | **1**, если клиент приобрел в предыдущем квартале, **0**, если в предыдущем квартале покупка не произошла |
| Lag_Crossbuy | Количество различных категорий товаров / услуг, приобретенных в предыдущем квартале |
| Ret_Expense | Доллары потраченные на маркетинговые усилия по удержанию этого клиента в данном квартале |
| Ret_Expense_SQ | Квадрат затрат на маркетинговые усилияпо удержанию этого клиента в данном квартале |
| Gender | **1**, если клиент является мужчиной, **0**, если клиент является женщиной |
| Married | **1**, если клиент женат, **0**, если клиент не состоял в браке |
| Income | **1**, если доход < 30 000 долл. США, **2**; если 30 001 долл. США < доход < 45 000 долл. США; **3**, если 45 001 долл. США < доход < 60 000 долл. США; **4**, если 60 001 долл. США < доход < 75 000 долл. США; **5**, если 75 001 долл. США < доход < 90 000 долл. США; **6**, если доход > 90 001 долл. США |
| First_Purchase | Стоимость первой покупки, сделанной клиентом в 1 квартале |
| Loyalty | **1**, если клиент является членом программы лояльности, **0**, если нет |
В этом случае автору упоминают о дискретной зависимлй переменной (`Crossbuy`), которая сообщает сколько категорий покупает покупатель в данном квартале. Чтобы понять вероятность перекрестного покупки, следует преобразовать эту дискретную переменную в двоичную переменную. Авторы делали это, устанавливая `CB` равным 1, когда `Crossbuy > 1` и `CB` равны 0 в противном случае. Также имеется девять независимых переменных, которые, по мнению авторов, станут драйверами поведения повторной покупки.
Авторы полагали, что поведение клиентов на транзакциях в прошлом, скорее всего, объяснит поведение покупателей с перекрестными покупками. В результате в этом примере авторы использовали несколько отложенных переменных, т.е. взятых с лагом, в качестве независимых переменных. Во-первых, имеется информация о том, приобрел ли покупатель в предыдущем квартале (`Lag_Purchase`). Также имеется переменная для количества категорий товаров, приобретенных покупателем в предыдущем квартале (`Lag_Crossbuy`). Эти две переменные могут быть получены путем взятия стоимости покупки / `cross-buy` с отставание в один месяц, отметив, что одно наблюдение будет потеряно для каждого клиента. В этом случае мы используем однопериодное (квартальное) отставание для обеих переменных. Во-вторых, имеется среднеквартальное количество прошлых заказов (`Avg_Order_Quantity`). В этом случае значение для среднего количества заказа является средним значением переменной `Order_Quantity` во всех кварталах до текущего периода времени. В-третьих, есть информация сколько долларов фирма потратила на каждого клиента (`Ret_Expense`) за каждый период времени и квадрат значения этой переменной (`Ret_Expense_SQ`). Авторы хотели использовать как линейные, так и квадратичные термины, так как ожидали, что для каждого дополнительного доллара, потраченного на усилия по удержанию для данного клиента, будет уменьшаться возврат к стоимости этого доллара. Наконец, поскольку фокусная фирма этого примера является фирмой **B2C**, остальные пять переменных являлись социально-демографическими характеристиками клиентов. К ним относятся `Gender` клиента, является ли клиент `Married`, `Income` клиента, стоимость первой покупки клиента (`First_Purchase`) и является ли клиент членом программы лояльности (`Loyalty`).
Во-первых, авторы смоделировали вероятность того, что клиент будет перекрестно покупать в данный период времени. Поскольку зависимая переменная (`CB`) является бинарной, авторы остановились на логистической регрессии для оценки модели. Авторы упоминали, что могли бы также выбрать пробит-модель и в целом добиться тех же результатов. В этом случае переменная y является `CB`, а предикторы представляют 10 независимых переменных в базе данных. Следует также выбирать только те случаи, когда покупка произошла, так как фирмы заинтересованы в том, чтобы клиенты перекрестно покупали в условиях покупки. Это дает нам `r sprintf("%.0f", sum(customerRetentionRepurchase$purchase))` наблюдений для построения этой модели.
### Построение и верификация модели *перекрестных продаж* {.tabset}
#### Logit
```{r Ch04 : Crossbuy - Logit, warning=FALSE}
# # Fit Logistic Regression Model for Customer Crossbuy by Authors
Ch04.cb <- glm(cb ~ lpurchase + lcrossbuy + avg_order_quantity + ret_expense + ret_expense_sq +
gender + married + income + first_purchase + loyalty,
data = filter(customerRetentionRepurchase, purchase == 1), family = binomial(link = 'logit'))
summary(Ch04.cb)
writeLines(sprintf("-2 Log L of Intercept and Only Covariates: %.3f", -2 * logLik(Ch04.cb)[1]))
writeLines(sprintf(" AIC (smaller is better): %.3f", extractAIC(Ch04.cb)[2]))
# Odds Ratio Estimates and 95% CI
writeLines("\n Odds Ratio Estimates and 95% CI")
car::Confint(Ch04.cb) %>%
exp() %>%
arm::pfround(digits = 3)
writeLines("\n Wald test of predictors")
car::Anova(Ch04.cb, type="II", test="Wald")
writeLines("\n Variance Inflation Factors - if vif() > 2 - feature has multicollinearity with others")
car::vif(Ch04.cb) # Variance Inflation Factors - if vif() > 2 - feature has multicollinearity
writeLines("\n Crossbuy Probability (Logit): Association of Predicted Probabilities and Observed Responses \n")
prob <- predict(Ch04.cb, newdata = filter(customerRetentionRepurchase, purchase == 1), type = "response")
caret::confusionMatrix(data = ifelse(prob > 0.5, "1", "0") %>% factor,
reference = filter(customerRetentionRepurchase, purchase == 1) %>% .$cb %>% factor,
positive = "1", mode = "everything")
```
Авторы получили логистическую регрессию довольно хорошего качества для описательных целей. Несмотря на то, что признак `married` является малозначимым предиктором в этой модели.
Во-первых, это означает, что `Lag_Crossbuy` положительно влияет на текущую кросс-покупку, то есть клиенты, которые приобрели больше категорий в предыдущем квартале, с большей вероятностью перекрестно покупают в текущем квартале. Во-вторых, поскольку коэффициент по `Avg_Order_Quantity` является положительным и статистически значимым, то клиенты, которые в прошлом тратили больше средств, чем в среднем, также чаще перекрестно покупают в текущем периоде времени. В-третьих, авторы обнаружили положительную, но уменьшающуюся отдачу от эффекта удерживающих расходов (Ret_Expense) при перекрестной покупке в том же квартале, поскольку коэффициент на Ret_Expense положителен, а коэффициент Ret_Expense_SQ отрицателен. В-четвертых, авторы отметили, что мужчины чаще совершают перекрестные покупку, чем женщины. В-пятых, авторы нашли положительный эффект от клиентского дохода, т.е. клиенты, имеющие более высокий доход, с большей вероятностью будут перекрестно покупать в текущем квартале. В-шестых, авторы определили, что клиенты, у которых была более высокая `First_Purchase`, с большей вероятностью закупят несколько категорий продуктов / услуг. Наконец, поскольку коэффициент для `Loyality` положителен, это говорит о том, что клиенты, которые являются членами программы лояльности, чаще всего перекрестно покупают в текущем квартале.
#### Logit (AR version)
Авторы по-прежнему прибегают в `Avg_Order_Quantity`, который в их примере охватывает текущий квартал и тем самым дает смещение в оценке модели в сторону увеличения качества модели. Я рассмотрю эту модель с более корректным предиктором с однопериодным лагом - `Lag_Avg_Order_Quantity`.
```{r Ch04 : Crossbuy Logit Improved, warning=FALSE}
# Fit Logit Regression Model for Customer Crossbuy (Improved)
uno = 'logit'
set.seed(2018) #From random.org
(Ch04cb.AR <- train(factor(cb) ~ lpurchase + lcrossbuy + lavg_order_quantity + ret_expense + ret_expense_sq +
gender + married + income + first_purchase + loyalty, metric = 'Kappa',
data = filter(customerRetentionRepurchase, purchase == 1), method = "glm", family = binomial(link = uno)))#,
# trControl = trainControl(method = "none", number = 1)))
summary(Ch04cb.AR)
# Odds Ratio Estimates and 95% CI
writeLines("\n Odds Ratio Estimates and 95% CI")
car::Confint(Ch04cb.AR$finalModel) %>%
exp() %>%
arm::pfround(digits = 3)
# Logistic regression diagnostics
writeLines("\n Wald test of predictors")
car::Anova(Ch04cb.AR$finalModel, type="II", test="Wald")
writeLines("\n Variance Inflation Factors - if vif() > 2 - feature has multicollinearity with others")
car::vif(Ch04cb.AR$finalModel) # Variance Inflation Factors - if vif() > 2 - feature has multicollinearity
writeLines("\n Variable Importance for Model \n")
caret::varImp(Ch04cb.AR) %>% .$importance %>% print.AsIs()
# Create the scatter plots Logit versus model predictors
predictors <- Ch04cb.AR$coefnames
Ch04cb.AR$trainingData %>%
dplyr::select(one_of(predictors)) %>%
mutate(link = predict(Ch04cb.AR$finalModel, newdata = filter(customerRetentionRepurchase, purchase == 1), type = "link")) %>%
gather(key = "predictors", value = "predictor.value", -link) %>%
ggplot(aes(predictor.value, link))+
geom_point(size = 0.05, alpha = 0.05) +
geom_smooth(method = "loess") +
facet_wrap(~ predictors, scales = "free_x") +
ylab(stringr::str_to_title(uno))
# Plot matrix of statistical model diagnostics
GGally::ggnostic(Ch04cb.AR$finalModel, title = paste(paste(formula(Ch04cb.AR)[c(2, 1, 3)], collapse = " ")))
# wide variety of diagnostic plots for checking the quality of regression fit
# https://bookdown.org/jefftemplewebb/IS-6489/logistic-regression.html
car::influenceIndexPlot(Ch04cb.AR$finalModel)
writeLines("\n Improved Logit Model: Association of Predicted Probabilities and Observed Responses \n")
caret::confusionMatrix(data = predict(Ch04cb.AR, newdata = filter(customerRetentionRepurchase, purchase == 1)),
reference = filter(customerRetentionRepurchase, purchase == 1) %>% .$cb %>% factor,
positive = "1", mode = "everything")
qplot(`Observed Classes`, `Predicted Classes`,
data=bind_cols(`Observed Classes`= filter(customerRetentionRepurchase, purchase == 1) %>% .$cb %>% factor,
`Predicted Classes` = predict(Ch04cb.AR, newdata = filter(customerRetentionRepurchase, purchase == 1))),
colour= `Observed Classes`, geom = c("boxplot", "jitter"),
main = "Predicted Classes vs. Observed Classes", xlab = "Observed Classes", ylab = "Predicted Classes")
```
Конечно, без смещения качество модели немного пострадает, зато она будет более правдоподобной и безусловно устойчивой. При этом даже значимость переменной `Married` повысилось.
### Как это использовать?
Полезно рассмотреть значения коэффициентов *отношения шансов* (англ. "`odds ratio`"). Что касается `Lag_Crossbuy`, мы видим, что каждая дополнительная категория, купленная покупателем в предыдущем квартале, делает клиента на 19,7% более вероятным для перекрестную покупку в текущем квартале. Что касается `Avg_Order_Quantity`, авторы отмечали, что при каждом увеличении на 1 доллар шанс перекрестной покупки в текущем квартале увеличивается на 1,0%. Что касается расходов на удержание клиентов `Ret_Expense`, то и *отношение шансов* зависит от уровня `Ret_Expense`. Это связано с тем, что мы включаем как собственно его уровень, так и его квадрат `Ret_Expense_SQ`. Например, если обычно в этой выборке тратили `r sprintf("%.0f", mean(customerRetentionRepurchase$ret_expense))` долл. ежеквартально на данного клиента, тратя больше долларов, мы должны увидеть увеличение вероятности перекрестной покупки.
И важно отметить, что это будет зависеть от начального уровня Ret_Expense. Что касается гендерных факторов, авторы указывают, что мужчины на 33,7% имеют шансов чаще покупают перекрестно, чем женщины. Что касается клиентского дохода, мы видим, что при каждом повышении уровня доходов на один уровень (`Income`) вероятность шанса кросс-покупки увеличится на 28,2%. Что касается `First_Purchase`, авторы пишут, что при каждом увеличении на 1 долл. вероятность кросс-покупки увеличивается на 2,5%. Наконец, что касается лояльности (`Loyalty`), становится ясным, что, будучи членом программы лояльности, вероятность перекрестной покупки в данном квартале на 30,8% выше, чем у клиента, который не входит в программу лояльности.
Менеджерам будет полезно знать, как изменения в расходах на удержание, прошлые транзакции клиентов и характеристики клиентов могут либо увеличить, либо уменьшить вероятность шанса перекрестной покупки. Эта модель поможет предсказать, собирается ли клиент покупать в другой категории или нет. Эта информация может дать существенную информацию руководителям, которым поручено определить, какие клиенты, скорее всего, склонны к кросс-покупкам.
## Эмпирический пример: доля покупок в кошельке
Программы лояльности и прямые рассылки - это два способа, которыми компании используют для управления отношениями с клиентами. Цель состоит в том, чтобы установить тесные отношения с клиентами и таким образом улучшить восприятие отношений с клиентами. Помимо понимания моделей покупки клиента у данной фирмы, многие фирмы также хотят знать, как клиент распределяют покупки в данной категории среди всех фирм. Для этого надо знать доля покупок в кошельке клиента (англ. `"Share-of-Wallet, SOW"`). Исследования показали, что понимание `SOW` клиента в данной фирме может помочь понять вероятность того, что клиент собирается купить у данной фирмы и неизбежно долгосрочную ценность клиента для фирмы (`CVL`). Таким образом, может быть полезно понять драйверы `SOW` и, в свою очередь, иметь возможность прогнозировать ожидаемое `SOW` каждого клиента. В этом примере авторы дают возможность возможность:
1. Определите драйверы SOW.
2. Предскажите ожидаемое SOW для каждого клиента.
3. Определите предиктивную точность модели.
Информация, необходимая для этой модели, включает следующий список переменных:
| Переменные | Описание |
|:--------------- |:-------------------------------------------------------------------------------------|
| **Зависимая переменная** | |
| Share-of-Wallet (SOW) | Процент покупок клиента от данной фирмы, учитывая общий объем покупок по всем фирмам в этой категории |
| **Предикторы** | |
| Purchase_Rate | Средняя доля кварталов с покупками во всех 12 кварталах |
| Avg_Order_Quantity | Средняя долларовая стоимость покупок за все 12 кварталов |
| Avg_Crossbuy | Среднее значение для кросс-покупки за все 12 кварталов |
| Avg_Ret_Expense | Средние расходы, потраченные на маркетинговые усилия по удержанию данного клиента за все 12 кварталов |
| Avg_Ret_Expense_SQ | Квадрат средних расходов, потраченные на маркетинговые усилия по удержанию данного клиента за все 12 кварталов |
Для получения этих агрегированных показателей необходимо получить массив данных, обобщенный за все 12 кварталов:
```{r Ch04 : Customer retention - Share-of-Wallet (SOW) data}
# Calculation Share-of-Wallet (SOW) Database
library('sqldf')
customerRetentionSOW <- sqldf("select customer, avg(purchase) as purchase_rate,
avg(order_quantity) as avg_order_quantity,
avg(crossbuy) as avg_crossbuy, avg(ret_expense) as avg_ret_exp,
(avg(ret_expense) * avg(ret_expense)) as avg_ret_exp_sq, gender,
married, income, first_purchase, sow, loyalty
from customerRetentionRepurchase group by customer, gender,
married, income, first_purchase, sow, loyalty order by customer;")
ggplot(customerRetentionSOW, aes(x = purchase_rate)) +
geom_histogram(breaks = seq(0, 1, by = .1), col = "gray", aes(fill = ..count..)) +
scale_fill_gradient("Count", low = "green", high = "red") +
geom_density(adjust = 1/5, alpha = .2, fill = "#FF6666") +
geom_vline(xintercept = mean(customerRetentionSOW$purchase_rate), linetype="dashed", color = "coral")
# Description of an empirical distribution for non-censored data using Cullen & Frey graph
library('fitdistrplus')
descdist(customerRetentionSOW$purchase_rate, boot = 500, discrete = FALSE)
x <- fitdist(customerRetentionSOW$purchase_rate, "unif", method = "mle", discrete = FALSE)
plot(x)
writeLines("\n Uniform distribution of `customerRetentionSOW$purchase_rate`")
gofstat(x)
```
Полученный непрерывный признак `Purchase_Rate` представлен на графике выше - очевидно, что он имеет равномерное распределение (англ. "`Uniform distribution`"). Это подтвержает тест при помощи графика Cullen & Frey.
В этом случае мы имеем цензуированную зависимую переменную (`SOW`), которая падает на континуум между 1 и 100. Минимальный размер этого случая составляет 1%, поскольку все клиенты в нашей базе данных совершили по крайней мере одну покупку у данной фирмы, а максимальный составляет 100%, поскольку все клиенты в базе данных могут потенциально покупать эти продукты только у этой фирмы. Таким образом, мы должны учитывать эту цензуированную зависимую переменную. В этом случае авторы предлагали использовать вариацию тобит-модели, которую использовали в предыдущих примерах в [третьей главе](https://rpubs.com/A_Rodionoff/SMCRM_Ch03). В стандартном случае тобит-модель имеет ситуацию, когда нижняя граница зависимой переменной определяется, как правило, равной 0, а верхняя граница тобит-модель бесконечна. Однако в этом случае нам нужно учитывать цензуирование как с нижней границей, так и верхней границы, где нижняя граница равна 1, а верхняя граница равна 100. Таким образом, мы имеем следующее определение для SOW:
$$ \displaystyle \begin{array}{ll}
SOW_i = \begin{cases}
100 & {\text{if}}\ SOW ^* _i \geq 100 \\
SOW ^* _i & {\text{if}}\ 1 < SOW ^* _i < 100 \\
1 & {\text{if}}\ SOW ^* _i \leq 1 \\
\end{cases}
\end{array} $$
### Построение и верификация модели *доли покупок в кошельке* {.tabset}
#### Tobit
```{r Ch04: Share-of-Wallet (SOW) - Tobit}
# Censored Regression of Accelerated Failure Time (AFT) model on Time-to-Failure Data
# https://stats.idre.ucla.edu/sas/dae/tobit-analysis/ & https://stats.idre.ucla.edu/r/dae/tobit-models/ & http://rpubs.com/Joaquin_AR/381600
library('VGAM') # Vector Generalized Linear and Additive Models
# Left- & Right-Censored Tobit (Normally distributed error term) AFT Model from 'VGAM' package
(Ch04.tb <- VGAM::vglm(sow ~ purchase_rate + avg_order_quantity + avg_crossbuy + avg_ret_exp + avg_ret_exp_sq +
gender + married + income + first_purchase + loyalty,
family = tobit(Lower = 1, Upper = 100, type.fitted = "censored"),
data = customerRetentionSOW)) %>%
summary
# # Censored Normal Distribution of error term Or Censored Tobit
# Extra <- with(customerRetentionSOW,
# list(leftcensored = (sow < 1), rightcensored = (sow > 100)))
#
# (Ch04.nr <- VGAM::vglm(sow ~ purchase_rate + avg_order_quantity + avg_crossbuy + avg_ret_exp + avg_ret_exp_sq +
# gender + married + income + first_purchase + loyalty,
# family = cens.normal(), extra = Extra,
# data = customerRetentionSOW)) %>%
# summary
```
Задача авторов состояла в том, чтобы максимизировать функцию логарифмического правдоподобия путем оценки коэффициентов и стандартной ошибки уравнения. При оценке модели получаны вышеприведенные результаты.
Авторы нашли, что все переменные, за исключением `Purchase_Rate`, `Gender` и `Married`, статистически значимы при `p < 0,05`.
Следующий шаг - предсказать значение `SOW`, чтобы увидеть, насколько хорошо наша модель сравнивается с фактическими значениями. Авторы сделали это, сравненивая предсказания по двухстороннему цензуированному регрессионому уравнению с фактическими значениями `SOW`.
#### Error of SOW
```{r Ch04: Error of SOW Models}
# mean_order_quantity
y <- customerRetentionSOW$sow
writeLines(sprintf("Mean of Share-of-Wallet (SOW): %.2f", mean(y)))
# Accuracy measures for Naïve AFT Model
m <- forecast::accuracy(rep(mean(customerRetentionSOW$sow), length(y)), y)
attributes(m)$ dimnames[[1]] <- " Naïve Model (Mean) Accuracy: "; m
# Accuracy measures for Censored Tobit
y_hat <- fitted(Ch04.tb)[, 1]
m <- forecast::accuracy(y_hat, y); attributes(m)$ dimnames[[1]] <- " Censored Tobit's Accuracy: "; m
# # Accuracy measures for Censored Normal Distribution AFT Model
# y_hat <- if_else(fitted(Ch04.nr) > 100, 100, if_else(fitted(Ch04.nr) < 1, 1, fitted(Ch04.nr)))
# m <- forecast::accuracy(y_hat, y); attributes(m)$ dimnames[[1]] <- "Censored Normal Model's Accuracy: "; m
```
Полученная авторами модель дает для приобретенных клиентов MAD = `r sprintf("%.2f", forecast::accuracy(y_hat, y)[, "MAE"])` или в среднем `r sprintf("%.2f", forecast::accuracy(y_hat, y)[, "MAPE"])`% от фактического SOW. Если бы мы вместо этого использовали среднее значение `SOW` (`r sprintf("%.2f", mean(customerRetentionSOW$sow))`) для всех клиентов в качестве нашего прогноза для всех клиентов (это было бы *наивным* примером модели), мы бы обнаружили, что MAD `r sprintf("%.2f", forecast::accuracy(rep(mean(customerRetentionSOW$sow), length(y)), y)[, "MAE"])` или в среднем на `r sprintf("%.2f", forecast::accuracy(rep(mean(customerRetentionSOW$sow), length(y)), y)[, "MAE"])`% от фактического `SOW`. Следовательно, авторская модель значительно улучшает работу по прогнозированию значения `SOW`, чем прогнозирование по среднему значению `SOW`.
#### Tobit (AR version)
```{r Ch04: SOW - Tobit Improved}
# Censored Regression of Accelerated Failure Time (AFT) model on Time-to-Failure Data
# Left- & Right-Censored Tobit (Normally distributed error term) AFT Model from 'VGAM' package
(Ch04tb.AR <- VGAM::vglm(sow ~ avg_order_quantity + avg_crossbuy + avg_ret_exp_sq +
income + first_purchase + loyalty,
family = tobit(Lower = 1, Upper = 100, type.fitted = "censored"),
data = customerRetentionSOW)) %>%
summary
# Calculate the upper and lower 95% confidence intervals for the coefficients.
b <- coef(Ch04tb.AR)
se <- sqrt(diag(vcov(Ch04tb.AR)))
writeLines("\n The Upper and Lower 95% confidence intervals for the coefficients of Left- & Right-Censored Tobit")
cbind(`Lower Intervals` = b - qnorm(0.975) * se, `Upper Intervals` = b + qnorm(0.975) * se)
dat <- customerRetentionSOW
dat$yhat <- fitted(Ch04tb.AR)[, 1]
dat$rr <- resid(Ch04tb.AR, type = "response")
dat$rp <- resid(Ch04tb.AR, type = "pearson")[, "mu"]
# Goodness-of-fit of normal distributions to residuals of Tobit-Model (if Kolmogorov-Smirnov statistic < 0.05)
resid(Ch04tb.AR, type = "response")[, 1] %>% fitdist("norm") %>% gofstat()
par(mfcol = c(2, 3))
with(dat, {
plot(yhat, rr, main = "Fitted vs Residuals")
qqnorm(rr, main = "Normal Q-Q Plot of Residuals")
plot(yhat, rp, main = "Fitted vs Pearson Residuals")
qqnorm(rp, main = "Normal Q-Q Plot of Pearson Residuals (mu)")
plot(sow, rp, main = "Actual vs Pearson Residuals")
plot(sow, yhat, main = "Actual vs Fitted")
})
par(mfcol = c(1, 1))
# Accuracy measures for Censored Tobit Improved
y <- customerRetentionSOW$sow
y_hat <- fitted(Ch04tb.AR)[, 1]
m <- forecast::accuracy(y_hat, y); attributes(m)$ dimnames[[1]] <- "Censored Tobit Improved Accuracy: "; m
remove(y, y_hat, m, b, se)
```
Если исключить три незначащие признаки `Purchase_Rate`, `Gender` и `Married` из числа предикторов, то получилась более устойчивую модель c незначительно увеличившейся ошибкой по MAE и MAPE. Первый свободный член `(Intercept):1` равный 10 надо интерепретировать как обычный сводобный член линейного уравнения, а второй сводобный член `(Intercept):2` равный 2.4 следует проэкспоненцировать и применить полученное число `11.0 = exp(2.4)` как стандартное отклонение, задаваемое при формировании нормально распределенных остатков sd в этом линейном уравнении. При этом следует признать, что что остатки улучшинной тобит-модели и в самом деле распределяются по нормальному распределению, поскольку значение статистики Колмогорова-Смирнова близко **p < 0.05**
### Как это использовать?
Авторы обнаружили, что коэффициент `Avg_Order_Quantity` положителен, что указывает на то, что чем выше средние значения заказа клиента в прошлом, тем выше значение `SOW`. Авторы также нашли, что `Avg_Crossbuy` позитивен, предполагая, что чем больше клиент закупил в нескольких категориях в прошлом, тем выше клиентский `SOW`. Мы находим, что `Ret_Expense` положителен с уменьшающимся возвратом, как отмечено положительным коэффициентом на `Ret_Expense` и отрицательным коэффициентом на `Ret_Expense_SQ`. Это означает, что маркетинговые усилия, направленные на сохранение и построение отношений с клиентом, заставляют клиента иметь более высокое значение `SOW`. Затем, после достижения порога, маркетинговые усилия фактически уменьшают `SOW` в среднем. Вероятно, это связано с тем, что чрезмерное общение с клиентами может часто напрягать отношения между клиентом и фирмой. Оказывается, что три из характеристики клиента являются положительными (`Income`, `First_Purchase` и `Loyalty`), предполагая, что клиенты с более высоким доходом, более высокая стоимость первой покупки и кто являются членами программы лояльности, вероятно, будут иметь более высокое значение`SOW`.
## Эмпирический пример: Рентабельность или Пожизненная финансовая ценность клиента (CLV)
Конечный вопрос для фирм, заинтересованных в удержании клиентов, связан с тем, насколько рентабельным может быть нынешний клиент в будущем. В этом примере авторы не фокусировались на прогнозе ожидаемой будущей прибыльности клиента или `CLV` (англ. "`Customer Lifetime Value`") или Пожизненная финансовая ценность клиента. Вместо этого попробуем сосредоточиться на драйверах `CLV`. Таким образом, авторы построили прогноз `CLV` для каждого из клиентов в выборке из 500. Затем авторы использовали это предсказание, чтобы понять, какая из переменных в данной базе данных поможет объяснить будущую ценность клиента. Если драйверы эффективно объясняют будущую ценность клиента, можно иметь возможность использовать результаты оценки в предсказании `CLV` для любого клиента, не входящего в текущую выборку. В конце этой главы авторы книги должны иметь возможность сделать следующее:
1. Определить драйверы `CLV`.
2. Предскажить ожидаемый `CLV` для каждого клиента.
3. Рассчитать предиктивную точность модели.