Se presenta información de los clientes de manera individual, sin tener en cuenta el tipo de licencia que poseen. Se han calculado los siguientes atributos:
Se filtran los clientes que tienen menos de 12 meses en la empresa y que no hayan realizado al menos una renovacion de servicio.
# Se calcula el tiempo entre facturaciones en meses
client_info_elapsed_time=invoice_data %>% group_by(client_id) %>% summarise(firstdate=min(timestamp),lastdate=max(timestamp)) %>% mutate(elapsed_time=(lastdate-firstdate)/60/60/24/30) %>% select(client_id,elapsed_time)
# Aquellos clientes con una operacion se los considera con un mes como tiempo minimo de permanencia
client_info_elapsed_time$elapsed_time=ifelse(client_info_elapsed_time$elapsed_time<1,1,client_info_elapsed_time$elapsed_time)
# Se calcula el numero de operaciones que se facturaron
client_info_operations=invoice_data %>% group_by(client_id) %>%
summarise(total_operation_count_per_client=n_distinct(invoice_id))
# Numero de veces que un cliente realizo un increase o upgrade
number_of_increase_server=invoice_data %>% filter(invoice_item_kind=='increase'& invoice_item_article=='server') %>%
group_by(client_id) %>%
summarise(n_server_increase=n())
number_of_renew_server=invoice_data %>% filter(invoice_item_kind=='renew'& invoice_item_article=='server') %>%
group_by(client_id) %>%
summarise(n_server_renew=n())
number_of_renew_sp=invoice_data %>% filter(invoice_item_kind=='renew'& invoice_item_article=='supercache') %>%
group_by(client_id) %>%
summarise(n_sp_renew=n())
number_of_increase_sp=invoice_data %>% filter(invoice_item_kind=='increase'& invoice_item_article=='supercache') %>%
group_by(client_id) %>%
summarise(n_sp_increase=n())
number_of_remove=invoice_data %>% filter(invoice_item_kind=='remove') %>%
group_by(client_id) %>%
summarise(n_remove=n())
server_type_by_client=invoice_data %>% group_by(client_id,server_id) %>% select(client_id,server_number_of_clients) %>% ungroup() %>% distinct() %>% select(client_id,server_id,server_number_of_clients)
server_type_by_client=server_type_by_client %>% filter(!is.na(server_id))
server_type_by_client=reshape2::dcast(server_type_by_client,client_id~server_number_of_clients)
#server_type_by_client=server_type_by_client[,1:ncol(server_type_by_client)-1]
number_of_servers_per_client = invoice_data %>% group_by(client_id) %>% summarise(n_servers=n_distinct(server_id,na.rm = TRUE))
# Extrayendo informacion de facturacion por cliente
client_invoice_amount= invoice_data %>% group_by(client_id) %>%
summarise(total_invoice_amount=sum(invoice_item_amount)/1000)
# Extrayendo informacion personal del cliente
client_personal_info = invoice_data %>%
select(client_id,client_name,client_company_name,client_country_name,client_geo_provice) %>%
distinct()
client_info=
full_join(client_info_operations,client_info_elapsed_time,by="client_id") %>%
full_join(client_invoice_amount,by="client_id") %>%
full_join(client_personal_info,by="client_id") %>%
full_join(number_of_increase_server,by="client_id") %>%
full_join(number_of_renew_server,by="client_id") %>%
full_join(number_of_increase_sp,by="client_id") %>%
full_join(number_of_renew_sp,by="client_id") %>%
full_join(number_of_servers_per_client,by="client_id") %>%
full_join(number_of_remove,by="client_id") %>%
full_join(server_type_by_client,by="client_id")
client_info = client_info %>% mutate( n_server_increase = replace(n_server_increase, is.na(n_server_increase), 0)) %>%
mutate( n_server_renew = replace(n_server_renew, is.na(n_server_renew), 0)) %>%
mutate( n_sp_increase = replace(n_sp_increase, is.na(n_sp_increase), 0)) %>%
mutate( n_sp_renew = replace(n_sp_renew, is.na(n_sp_renew), 0)) %>%
mutate( n_remove = replace(n_remove, is.na(n_remove), 0))
# Se calcula promedio mensual de facturacion por cliente
client_info$avg_monthly_invoice=(client_info$total_invoice_amount/client_info$elapsed_time)
client_info=client_info %>% rowwise() %>% mutate(n_top_operations=sum(n_server_increase,n_server_renew,n_sp_increase,n_sp_renew,na.rm=T))
# Solo consideramos aquellos que han estado por lo menos 12 meses y hayan hecho al menos un renew
client_info=client_info %>% filter(elapsed_time >12 & (n_sp_renew >=1 | n_server_renew>=1))
client_info$client_id=factor(client_info$client_id)
library(DT)
datatable(client_info[,-c(5,6,7,8)], filter="bottom", options = list(
search = list(regex = TRUE, caseInsensitive = FALSE),
pageLength = 5
), class = 'cell-border stripe', extensions = 'Buttons'
)
El siguiente grafico muestra la relación entre el tiempo transcurrido en la empresa y el monto total de facturación por cada cliente. Cada punto representa un cliente. Ademas, el color indica el promedio de facturacion mensual de cada cliente y el tamaño, la cantidad de operaciones de alta importancia (server o superache increase o renew) . Finalmente, la recta de color cyan, muestra la tendencia observada.
gg=ggplot(client_info,aes(x=elapsed_time,y=total_invoice_amount))+
geom_jitter(aes(colour=avg_monthly_invoice,size=n_top_operations, text = paste0("client_name:", client_name)),alpha=0.8)+
scale_x_continuous('Tiempo de permanencia en la empresa [meses]', expand=c(0.01,0.3 ) )+ylab("monto total de facturacion [Ku$S]")+
labs(colour = 'Facturacion promedio mensual', size = 'numero de renovaciones y upgrades (increase|renew)')+
scale_color_gradient2(low = "cyan", mid='blue',high = "red")+
ggtitle("Información por cliente (sin considerar tipo de server)")+
theme(plot.title = element_text(lineheight=3.5, face="bold"))+
scale_size(range = c(1, 10))+
geom_smooth(aes(x=elapsed_time,y=total_invoice_amount),method='lm',colour='skyblue',se = F)
# facet_wrap(~client_country_name)
#gg
ggplotly(gg,layerData=1)
El indicador de facturacion mensual parece ser un buen discriminador, se pueden diferenciar al menos 4 tipos de clientes sin importar el tiempo transcurrido
El siguiente boxplot muestra la distribucion del indicador de facturacion mensual. En base a este grafico se pueden establecer los rangos que definen a las 4 categorias y considerar en una 5ta a aquellos clientes que estan fuera de lo normal. (ver Code)
par(mfrow=c(3,1))
bwplot(~avg_monthly_invoice,data=client_info,horizontal = T,xlab="promedio de facturacion mensual")
client_info=client_info %>% mutate(client_category=ifelse(avg_monthly_invoice >0 & avg_monthly_invoice <=0.0338,1,
ifelse(avg_monthly_invoice >0.0338 & avg_monthly_invoice <=0.057,2,
ifelse(avg_monthly_invoice >0.057 & avg_monthly_invoice <=0.1,3,
ifelse(avg_monthly_invoice >0.1 & avg_monthly_invoice <=0.2,4,
ifelse(avg_monthly_invoice>0.2 ,5,NA)))
)))
client_info$client_category=factor(client_info$client_category)
summary(client_info$avg_monthly_invoice)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.006294 0.038820 0.057850 0.080530 0.106600 0.455600
Se definen 5 categorias de clientes en base a su facturación mensual. Se observa que las categorias 3 y 4 representan el mayor porcentaje de la facturacion .
#client_info %>% group_by(client_category) %>% summarise(mean=mean(avg_monthly_invoice),sd=sd(avg_monthly_invoice))
#shapiro.test(unlist(client_info %>% filter(client_category==3) %>% select(avg_monthly_invoice)))
#densityplot(~avg_monthly_invoice,data=client_info %>% filter(client_category==4))
#shapiro.test(unlist(client_info %>% filter(client_category==4) %>% select(avg_monthly_invoice)))
info_by_client_category_percent=client_info %>%
group_by(client_category) %>%
summarise(client_category_invoice_total=sum(total_invoice_amount)) %>%
mutate(percent=(client_category_invoice_total/sum(client_category_invoice_total))*100)
barchart(percent~factor(client_category),data=info_by_client_category_percent,xlab='categoria cliente',ylab='porcentaje de facturacion total',main="Distribución de la facturacion total por tipo de cliente",scales=list(x=list(rot='45')),)
bwplot(~avg_monthly_invoice|client_category,data=client_info,horizontal = T,
panel = function(x, y, ...) {
panel.bwplot(x, y, ...)
nn <- table(x)
panel.text(nn, x = seq_along(nn),
y = current.panel.limits()$y[1], pos = 3,cex=0.5)
},scales=list(x = list(relation = "free")),xlab="promedio de facturacion mensual",cex=0.4)
cbind(cat1=summary(client_info %>% filter(client_category==1) %>% select(avg_monthly_invoice)),
cat2=summary(client_info %>% filter(client_category==2) %>% select(avg_monthly_invoice)),
cat3=summary(client_info %>% filter(client_category==3) %>% select(avg_monthly_invoice)),
cat4=summary(client_info %>% filter(client_category==4) %>% select(avg_monthly_invoice)),
cat5=summary(client_info %>% filter(client_category==5) %>% select(avg_monthly_invoice)))
## avg_monthly_invoice avg_monthly_invoice avg_monthly_invoice
## "Min. :0.006294 " "Min. :0.03390 " "Min. :0.05772 "
## "1st Qu.:0.017157 " "1st Qu.:0.03970 " "1st Qu.:0.06325 "
## "Median :0.022034 " "Median :0.04608 " "Median :0.07350 "
## "Mean :0.021332 " "Mean :0.04508 " "Mean :0.07573 "
## "3rd Qu.:0.026798 " "3rd Qu.:0.05048 " "3rd Qu.:0.08950 "
## "Max. :0.033708 " "Max. :0.05631 " "Max. :0.09918 "
## avg_monthly_invoice avg_monthly_invoice
## "Min. :0.1003 " "Min. :0.2036 "
## "1st Qu.:0.1170 " "1st Qu.:0.2253 "
## "Median :0.1338 " "Median :0.2479 "
## "Mean :0.1364 " "Mean :0.2663 "
## "3rd Qu.:0.1535 " "3rd Qu.:0.2779 "
## "Max. :0.1983 " "Max. :0.4556 "
Definidas estas primeras categorias, resulta importante caracterizar cada una de ellas, para tal fin, se analizan diferentes atributos de interes.
Los siguientes boxplot muestran la distribucion de otros atributos de interes para cada categoria de clientes En particular se presenta información sobre:
Total de facturación
Tiempo transcurrido
Numero de operaciones de alta importancia (supercache,server,renew,increase)
Numero de operaciones de renovacion de server
bwplot(total_invoice_amount~client_category,data=client_info,horizontal = F,
panel = function(x, y, ...) {
panel.bwplot(x, y, ...)
nn <- table(x)
panel.text(nn, x = seq_along(nn),
y = current.panel.limits()$y[1], pos = 3,cex=0.5)
},ylab="monto total de facturación")
La facturación total presenta diferencias y se observa un comportamiento esperado donde los clientes de las categorias mas altas son los que mayor monto de facturacion tienen.
par(mfrow=c(1,3))
bwplot(elapsed_time~client_category,data=client_info,horizontal = F,
panel = function(x, y, ...) {
panel.bwplot(x, y, ...)
nn <- table(x)
panel.text(nn, x = seq_along(nn),
y = current.panel.limits()$y[1], pos = 3,cex=0.5)
},ylab="tiempo de permanencia en la empresa")
histogram(~elapsed_time,data=client_info %>% filter(client_category==1),main="Categoria 1")
histogram(~elapsed_time,data=client_info %>% filter(client_category==2),main="Categoria 2")
histogram(~elapsed_time,data=client_info %>% filter(client_category==3),main="Categoria 3")
histogram(~elapsed_time,data=client_info %>% filter(client_category==4),main="Categoria 4")
Sin embargo,el tiempo no parece ser un atributo significantivo para caracterizar las categorias de clientes. En principio se podria esperar que los clientes que mas facturación mensual tienen, sean aquellos que mas tiempo han permanecido con la empresa. Esto sin embargo no se observe en el grafico, ya que para todas las categorias de clientes se observan una variacion similar en el tiempo.
bwplot(n_top_operations~client_category,data=client_info,horizontal = F,
panel = function(x, y, ...) {
panel.bwplot(x, y, ...)
nn <- table(x)
panel.text(nn, x = seq_along(nn),
y = current.panel.limits()$y[1], pos = 3,cex=0.5)
},ylab="numero de operaciones de importancia")
histogram(~n_top_operations,data=client_info %>% filter(client_category==1),,main="Categoria 1")
histogram(~n_top_operations,data=client_info %>% filter(client_category==2),,main="Categoria 2")
histogram(~n_top_operations,data=client_info %>% filter(client_category==3),,main="Categoria 3")
histogram(~n_top_operations,data=client_info %>% filter(client_category==4),,main="Categoria 4")
El numero de operaciones de alta importancia sigue una tendencia similar a la de la facturación total, entre los clientes del tipo 2 y 3 no se observan tantas diferencias en general, aunque si se observa un numero de outliers. Queda entonces discriminar el tipo de operaciones de alta importancia.
bwplot(n_server_renew~client_category,data=client_info,horizontal = F,ylab="numero de renovaciones de licencias")
El numero de renovaciones de no ofrece diferencias salvo para las categorias 1 y 5. Las restantes (2,3,4) parece tener comportamiento similar.
bwplot(n_servers~client_category,data=client_info,horizontal = F,
panel = function(x, y, ...) {
panel.bwplot(x, y, ...)
nn <- table(x)
panel.text(nn, x = seq_along(nn),
y = current.panel.limits()$y[1], pos = 3,cex=0.5)
},ylab="numero de licencias")
El numero de licencias ofrece algunas diferencias significativas, sin embargo entre la categoria 3 y 4 no se observan practicamente diferencias mas alla de los outliers de la categoria 3. Cabe entonces preguntarse si la diferencia en la facturacion mensual radica el tipo especifico de licencia.
Para analizar las caratecteristicas de los clientes en base al tipo y numero de licencia que estos poseen se grafica la información de cliente por tipo de licencia. Donde cada punto representa un tipo de licencia para un cliente dado. El eje X muestra los distintos tipos de licencias y el eje la facturación mensual. Las categorias son diferencias por color. Los distintos tipos de licencias para un mismo cliente se ordenan sobre el eje Y. Por ultimo si posee mas de una licencia de un mismo tipo se incremente el tamaño del punto.
heat=client_info[,c(1,2,9,13,15:28,29,30,31)]
heat=reshape2::melt(heat[,1:21],id.vars=c("avg_monthly_invoice","client_category","client_id","n_servers","n_server_increase","n_top_operations","total_operation_count_per_client"),variable.name="server_type")
#heat$client_category=factor(heat$client_category)
#heat$server_type=factor(heat$server_type)
gg=ggplot(heat %>% filter(value!=0),aes(y=avg_monthly_invoice,x=server_type))+
geom_jitter(aes(size=value,colour=client_category,text=paste("client_id",client_id,"<BR>n_servers",n_servers,"<BR>n_server_increase",n_server_increase,"<BR>n_top_operations",n_top_operations,"<BR>n_total_operations",total_operation_count_per_client)) ,width = 0.05,alpha=0.5) +
ylab("monto total de facturacion mensual [Ku$S]")+
xlab("tipo de servidor")+
labs(size = 'numero de licencias',color="categoria de clientes")+
ggtitle("Información por cliente por tipo de licencia")+
theme(plot.title = element_text(lineheight=3.5, face="bold"))+
theme(axis.text.x = element_text(angle = 45, hjust = 1))
ggplotly(gg)
En general, se observa una ligera tendencia en donde los montos de facturación mensuales tienden a estar correlacionados con el tipo de licencia. Por ejemplo, la categoria 1 solo tienen licencias que van de 50 a 350, mientras que la cat 2 y la 3 tienen de 50 a 1500, la categoria 4 llega en algunos casos a 3000 y la categoria 5 llega a 4000 usuarios. SIn embargo no parece ser la unica explicación para la variación en los montos mensuales de facturación.
Los diferentes tipos de licencias que puede poseer un mismo cliente influyen en el monto mensual de un cliente. Es decir que la catgoria de un cliente esta influenciada por los distintos tipos de licencias que poseen. Aunque hay casos dificiles de explicar como el cliente 29 y 44. Los cuales estan en diferentes categorias y poseen licencias parecidas. Luego de observar las diferencias de ambos clientes se observan que el cliente 44 (cat 4) posee una licencia de 500 usuarios, y por otro lado el cliente 29 (cat 3) tiene licencias 150 a 350 usuarios, lo que se suma el hecho de que alguna de estas licencias fue incrementada recientemente.
clients=client_info %>% filter(client_id==44 | client_id==29)
clients=clients[,c(2,3,4,9:13,15:28,31)]
datatable(clients, filter="bottom", options = list(
search = list(regex = TRUE, caseInsensitive = FALSE),
pageLength = 5
), class = 'cell-border stripe', extensions = 'Buttons'
)
El analisis anterior muestra que la categoria de un cliente esta influenciada por diversas variables que deben analizarse en conjunto. Los arboles de decision son una herramienta que permite establecer diferentes combinaciones de variables/atributos utilizando un enfoque Divide & Conquer. Se seleccionan aquellos atributos y valores que tienen mayor impacto a la hora de discriminar entre las posibles categorias. Cada una de la hojas del arbol termina siendo una regla que explica una categoria con una probabilidad determininada.
library(rpart)
library(rattle)
library(rpart.plot)
library(rpart.utils)
#client_info_tree=client_info[,c(9:13,15:28,29,31)]
#formula <- as.formula(avg_monthly_invoice~.)
client_info_tree=client_info[,c(9:13,15:28,31)]
formula <- as.formula(client_category~.)
tree=rpart(formula,data=client_info_tree,control = rpart.control(minsplit=6, cp=0.001))
prp(tree,cex=0.85 )
printcp(tree)
##
## Classification tree:
## rpart(formula = formula, data = client_info_tree, control = rpart.control(minsplit = 6,
## cp = 0.001))
##
## Variables actually used in tree construction:
## [1] 100 1000 150
## [4] 1500 250 2500
## [7] 350 50 500
## [10] 800 n_server_increase n_server_renew
## [13] n_servers n_sp_increase n_sp_renew
##
## Root node error: 190/270 = 0.7037
##
## n= 270
##
## CP nsplit rel error xerror xstd
## 1 0.1105263 0 1.00000 1.00000 0.039490
## 2 0.0631579 1 0.88947 0.88947 0.041847
## 3 0.0421053 2 0.82632 0.86842 0.042160
## 4 0.0263158 3 0.78421 0.82632 0.042663
## 5 0.0157895 4 0.75789 0.79474 0.042936
## 6 0.0131579 6 0.72632 0.80526 0.042855
## 7 0.0105263 8 0.70000 0.80526 0.042855
## 8 0.0078947 18 0.58947 0.78421 0.043008
## 9 0.0052632 20 0.57368 0.81579 0.042764
## 10 0.0026316 42 0.45789 0.85789 0.042301
## 11 0.0013158 44 0.45263 0.84737 0.042432
## 12 0.0010000 48 0.44737 0.84737 0.042432
#plot(tree,uniform=T,main="Regression Tree for Customer categories")
#text(tree,cex=0.7,minlength=20,all=T,use.n=T,xpd=T)
#asRules(tree)
client_info_tree=client_info[,c(9:13,15:28,29)]
formula <- as.formula(avg_monthly_invoice~.)
tree=rpart(formula,data=client_info_tree,control = rpart.control(minsplit=15, cp=0.001))
prp(tree,cex=0.6 )
printcp(tree)
##
## Regression tree:
## rpart(formula = formula, data = client_info_tree, control = rpart.control(minsplit = 15,
## cp = 0.001))
##
## Variables actually used in tree construction:
## [1] 100 1000 150
## [4] 1500 250 350
## [7] 50 500 800
## [10] n_server_increase n_server_renew n_servers
## [13] n_sp_renew
##
## Root node error: 1.143/270 = 0.0042335
##
## n= 270
##
## CP nsplit rel error xerror xstd
## 1 0.1460795 0 1.00000 1.00897 0.16867
## 2 0.0841328 1 0.85392 0.95025 0.16884
## 3 0.0580047 2 0.76979 0.89084 0.16834
## 4 0.0572352 3 0.71178 0.85898 0.16815
## 5 0.0555879 4 0.65455 0.84634 0.16843
## 6 0.0182684 5 0.59896 0.70167 0.13785
## 7 0.0136391 7 0.56242 0.65307 0.13270
## 8 0.0106498 10 0.52151 0.63299 0.12931
## 9 0.0096720 11 0.51086 0.63316 0.12778
## 10 0.0090067 12 0.50118 0.61413 0.12113
## 11 0.0077965 14 0.48317 0.60627 0.12114
## 12 0.0064596 15 0.47537 0.60484 0.11897
## 13 0.0062628 16 0.46891 0.60523 0.11895
## 14 0.0028757 18 0.45639 0.59252 0.11873
## 15 0.0027046 19 0.45351 0.58486 0.10956
## 16 0.0014373 20 0.45081 0.58536 0.10935
## 17 0.0010135 21 0.44937 0.57882 0.10899
## 18 0.0010000 22 0.44836 0.57769 0.10896