1. Análisis descriptivo, ¿qué datos tenemos?
Carga de datos
datos <- read.csv("Transactions Caso Práctico.csv",
sep = ";", header = TRUE)
# Cambiar a formato Date el atributo orderdate
datos$orderdate <-as.Date(datos$orderdate,"%d/%m/%Y")
head(datos)
## orderId clientId product gender orderdate Quantity Price
## 1 1 255 g female 2017-01-03 3 5
## 2 1 255 a female 2017-01-03 3 14
## 3 1 255 b female 2017-01-03 3 22
## 4 1 255 a female 2017-01-03 1 14
## 5 2 145 h male 2017-01-05 1 26
## 6 2 145 h male 2017-01-05 1 26
tail(datos)
## orderId clientId product gender orderdate Quantity Price
## 4800 999 241 i female 2017-03-13 2 32
## 4801 1000 235 e female 2017-02-03 2 30
## 4802 1000 235 b female 2017-02-03 1 22
## 4803 1000 235 f female 2017-02-03 1 24
## 4804 1000 235 h female 2017-02-03 1 26
## 4805 1000 235 g female 2017-02-03 2 5
nrow(datos)
## [1] 4805
str(datos)
## 'data.frame': 4805 obs. of 7 variables:
## $ orderId : int 1 1 1 1 2 2 2 2 3 3 ...
## $ clientId : int 255 255 255 255 145 145 145 145 241 241 ...
## $ product : Factor w/ 9 levels "a","b","c","d",..: 7 1 2 1 8 8 1 8 4 7 ...
## $ gender : Factor w/ 2 levels "female","male": 1 1 1 1 2 2 2 2 1 1 ...
## $ orderdate: Date, format: "2017-01-03" "2017-01-03" ...
## $ Quantity : int 3 3 3 1 1 1 1 1 3 2 ...
## $ Price : int 5 14 22 14 26 26 14 26 12 5 ...
head(sort(unique(datos$orderId)))
## [1] 1 2 3 4 5 6
tail(sort(unique(datos$orderId)))
## [1] 995 996 997 998 999 1000
head(sort(unique(datos$clientId)))
## [1] 1 2 3 4 5 6
tail(sort(unique(datos$clientId)))
## [1] 295 296 297 298 299 300
NROW(sort(unique(datos$clientId))) # Cuántos clientes
## [1] 296
head(sort(unique(datos$product)))
## [1] a b c d e f
## Levels: a b c d e f g h i
tail(unique(datos$product))
## [1] h d i f c e
## Levels: a b c d e f g h i
sort(unique(datos$gender))
## [1] female male
## Levels: female male
head(sort(unique(datos$orderdate), decreasing = FALSE))
## [1] "2017-01-02" "2017-01-03" "2017-01-04" "2017-01-05" "2017-01-06"
## [6] "2017-01-07"
head(sort(unique(datos$orderdate), decreasing = TRUE))
## [1] "2017-04-11" "2017-04-10" "2017-04-09" "2017-04-08" "2017-04-07"
## [6] "2017-04-06"
sort(unique(datos$Quantity))
## [1] 1 2 3
sort(unique(datos$Price))
## [1] 5 9 12 14 22 24 26 30 32
Interpretación de los datos
El conjunto de datos Transactions Caso Práctico.csv es un archivo en formato CSV separado por el simbolo de ‘;’.
Tiene 1000 observaciones con un 7 variables las cuales son:
- OrderId: Que es un identificador de cada compra,
- clientID: Es el cliente que hace la comora
- product: El producto que se compra
- gender: El género del cliente
- orderdate: La fecha de compra
- Quantity: La fecha de comora y
- Price: El precio de compra
De acuerdo con la función str() de R, la estructura del conjunto de datos del archivo
- OrderId: Es un valor que identifica la compra,
- clientID: Es el cliente que hace la compra
- product: El producto que se compra
- gender: El género del cliente
- orderdate: La fecha de compra
- Quantity: La cantidad de productos que se adquieren y
- Price: El precio de compra
De acuerdo con la función str() que identifica la estructura del conjunto de datos del archivo, combinado con algunas funciones sort(), unique(), head() y tail() de R, se describen algunas características del conjunto de datos:
- OrderId: Las filas repiten lás órdenes de compra entendiéndose que por cada compra hay varios productos que se adquieren. De las 4805 observaciones hay 1000 registros en OrderId desde 1 hasta 1000
- clientID: Hay 296 clientes diferentes desde 1 hasta 300
- product: Hay 9 productos diferenes a, b, c, d, e, f, g, h, i
- gender: El género del cliente hay dos: female y male (Femenino y Masculino)
- orderdate: La primer fecha de compra registrada fué el 01/02/2017 (2 de enero del 2017) y la última fecha de compra fué realizada el dia 11/04/2017 (11 de abril del 2017). Es decir, hay 3 meses y casi medio de registros de compras. Enero, Febrero Marzo y 11 dias del mes de Abril
- Quantity: La cantidad de productos diferentes de cada compra varía entre 1 y 3 productos
- Price: El precio de los prodctos varía entre 5 y 32 (serán Euros, Pesos o Dólares ?)
Agregando dia, mes y agnio a los datos
library(lubridate) # Para tratar con fechas
##
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
##
## date
datos$dia <- day(datos$orderdate)
datos$mes <- month(datos$orderdate)
datos$agnio <- year(datos$orderdate)
library(dplyr) # Para tratar con filtros, proyecciones ordenamientos ...
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:lubridate':
##
## intersect, setdiff, union
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
head(arrange(datos, datos$mes, datos$dia)) # Ordenando datos
## orderId clientId product gender orderdate Quantity Price dia mes agnio
## 1 140 59 a female 2017-01-02 3 14 2 1 2017
## 2 140 59 h female 2017-01-02 1 26 2 1 2017
## 3 140 59 h female 2017-01-02 1 26 2 1 2017
## 4 140 59 a female 2017-01-02 3 14 2 1 2017
## 5 140 59 b female 2017-01-02 2 22 2 1 2017
## 6 140 59 f female 2017-01-02 2 24 2 1 2017
tail(arrange(datos, datos$mes, datos$dia)) # Ordenando datos
## orderId clientId product gender orderdate Quantity Price dia mes
## 4800 653 139 g male 2017-04-11 2 5 11 4
## 4801 653 139 h male 2017-04-11 2 26 11 4
## 4802 753 38 a female 2017-04-11 1 14 11 4
## 4803 753 38 d female 2017-04-11 3 12 11 4
## 4804 753 38 g female 2017-04-11 1 5 11 4
## 4805 753 38 e female 2017-04-11 1 30 11 4
## agnio
## 4800 2017
## 4801 2017
## 4802 2017
## 4803 2017
## 4804 2017
## 4805 2017
Visulizando datos
library(ggplot2)
library(scales)
ggplot(datos) +
geom_density(aes(Quantity * Price)) +
scale_x_continuous(labels = dollar)

ggplot(datos) +
geom_histogram(aes(x=Quantity * Price), binwidth = 7, fill="gray")

- Se observa en la gráfica de densidad, que hay mayormente una cantidad de ventas que estan entre $25 y $27 en total de venta (cantidad * precio).
- En el histogrma, tabién se muestra que hay muchas ventas que fluctuan entre $25 y $27 en total de venta, es decir cantidad * precio.
Análisis descriptivo de los datos con la función summary()
summary(datos)
## orderId clientId product gender
## Min. : 1.0 Min. : 1.0 a :879 female:2665
## 1st Qu.: 261.0 1st Qu.: 72.0 g :747 male :2140
## Median : 510.0 Median :143.0 h :684
## Mean : 504.6 Mean :148.7 d :677
## 3rd Qu.: 750.0 3rd Qu.:224.0 e :536
## Max. :1000.0 Max. :300.0 f :429
## (Other):853
## orderdate Quantity Price dia
## Min. :2017-01-02 Min. :1.000 Min. : 5.0 Min. : 1.00
## 1st Qu.:2017-01-27 1st Qu.:1.000 1st Qu.:12.0 1st Qu.: 7.00
## Median :2017-02-21 Median :2.000 Median :14.0 Median :14.00
## Mean :2017-02-21 Mean :1.977 Mean :18.2 Mean :14.96
## 3rd Qu.:2017-03-20 3rd Qu.:3.000 3rd Qu.:26.0 3rd Qu.:23.00
## Max. :2017-04-11 Max. :3.000 Max. :32.0 Max. :31.00
##
## mes agnio
## Min. :1.000 Min. :2017
## 1st Qu.:1.000 1st Qu.:2017
## Median :2.000 Median :2017
## Mean :2.261 Mean :2017
## 3rd Qu.:3.000 3rd Qu.:2017
## Max. :4.000 Max. :2017
##
Algunos análisis específicos
Cliente que MÁS compra
mascompra <- head(datos %>%
group_by(clientId) %>%
summarise(frecuencia = n(),
total = sum(Quantity * Price)) %>%
arrange(desc(frecuencia), desc(total)), 10)
mascompra
## # A tibble: 10 x 3
## clientId frecuencia total
## <int> <int> <int>
## 1 219 53 1957
## 2 273 52 1960
## 3 127 43 1778
## 4 33 38 1294
## 5 73 37 1477
## 6 198 37 1475
## 7 171 36 1542
## 8 195 36 1397
## 9 87 36 937
## 10 2 35 1229
p1 <-ggplot(data=mascompra, aes(x=clientId, y=frecuencia)) +
geom_bar(stat="identity", fill="steelblue", width=25) +
geom_text(aes(label=clientId), vjust=1.6, color="white",
position = position_dodge(0.9), size=3.5)+
theme_minimal()
p1
## Warning: position_stack requires non-overlapping x intervals

- El cliente que MÁS ha comprado es el número 219 con 53 compras y un total de $ 1957
Cliente que MENOS compra
menoscompra <- tail(datos %>%
group_by(clientId) %>%
summarise(frecuencia = n(),
total = sum(Quantity * Price)) %>%
arrange(desc(frecuencia), desc(total)), 10)
menoscompra
## # A tibble: 10 x 3
## clientId frecuencia total
## <int> <int> <int>
## 1 34 4 75
## 2 188 4 68
## 3 95 3 194
## 4 7 3 160
## 5 257 3 160
## 6 155 3 112
## 7 19 2 45
## 8 90 1 52
## 9 61 1 15
## 10 80 1 5
p1 <-ggplot(data=menoscompra, aes(x=clientId, y=frecuencia)) +
geom_bar(stat="identity", fill="steelblue", width=25) +
geom_text(aes(label=clientId), vjust=1.6, color="white",
position = position_dodge(0.9), size=3.5)+
theme_minimal()
p1
## Warning: position_stack requires non-overlapping x intervals

- El cliente que MENOS ha comprado es el número 80 con 1 compras y un total de $ 5
Fecha o dia en que se hicieron más compras
mascompras <- head(datos %>%
group_by(orderdate) %>%
summarise(frecuencia = n(),
total = sum(Quantity * Price)) %>%
arrange(desc(frecuencia), desc(total)), 5)
mascompras
## # A tibble: 5 x 3
## orderdate frecuencia total
## <date> <int> <int>
## 1 2017-02-14 90 3340
## 2 2017-03-10 88 3139
## 3 2017-01-29 86 2915
## 4 2017-03-27 84 3238
## 5 2017-01-16 79 3137
p1 <-ggplot(data=mascompras, aes(x=orderdate, y=frecuencia)) +
geom_bar(stat="identity", fill="steelblue", width=10) +
geom_text(aes(label=orderdate), vjust=1.6, color="white",
position = position_dodge(0.9), size=3.5)+
theme_minimal()
p1

- El 14 de Febrero se hicieron más compras con frecuencia de 90 y total de $ 3,340
Fecha o dia en que se hicieron menos compras
menoscompras <- tail(datos %>%
group_by(orderdate) %>%
summarise(frecuencia = n(),
total = sum(Quantity * Price)) %>%
arrange(desc(frecuencia), desc(total)), 5)
menoscompras
## # A tibble: 5 x 3
## orderdate frecuencia total
## <date> <int> <int>
## 1 2017-02-10 20 751
## 2 2017-01-23 19 512
## 3 2017-03-04 17 600
## 4 2017-01-04 17 500
## 5 2017-02-04 15 499
p1 <-ggplot(data=menoscompras, aes(x=orderdate, y=frecuencia)) +
geom_bar(stat="identity", fill="steelblue", width=10) +
geom_text(aes(label=orderdate), vjust=1.6, color="white",
position = position_dodge(0.9), size=3.5)+
theme_minimal()
p1
## Warning: position_stack requires non-overlapping x intervals

- Por el contrario, el día 4 de Febrero se hicieron menos compras con frecuencia de 15 y total de $499
Productos que más y menos se venden
masymenosprods <- datos %>%
group_by(product) %>%
summarise(frecuencia = n()) %>%
arrange(desc(frecuencia))
masymenosprods
## # A tibble: 9 x 2
## product frecuencia
## <fct> <int>
## 1 a 879
## 2 g 747
## 3 h 684
## 4 d 677
## 5 e 536
## 6 f 429
## 7 b 383
## 8 i 282
## 9 c 188
p1 <-ggplot(data=masymenosprods, aes(x=product, y=frecuencia, fill=product)) +
geom_bar(stat="identity") +
geom_text(aes(label=product), vjust=1.6, color="white",
position = position_dodge(0.9), size=3.5)+
theme_minimal()
p1

- El producto que más se vende es: a con 879
- El producto que menos se vende es: c con 188
Cantidad de compras por género Femenino y Masculinao
frecgenero <- datos %>%
group_by(gender) %>%
summarise(frecuencia = n()) %>%
arrange(desc(frecuencia))
frecgenero
## # A tibble: 2 x 2
## gender frecuencia
## <fct> <int>
## 1 female 2665
## 2 male 2140
p1 <-ggplot(data=frecgenero, aes(x=gender, y=frecuencia, fill=gender)) +
geom_bar(stat="identity") +
geom_text(aes(label=gender), vjust=1.6, color="white",
position = position_dodge(0.9), size=3.5)+
theme_minimal()
p1

- El género Femenino es el que ha comprado más con 2665
- El género Masculino es el que h acomprado menos con 2140
Cantidad de compras por producto y por género Femenino y Masculinao
frecgeneroprod <- datos %>%
group_by(gender, product) %>%
summarise(frecuencia = n()) %>%
arrange(desc(frecuencia))
frecgeneroprod
## # A tibble: 18 x 3
## # Groups: gender [2]
## gender product frecuencia
## <fct> <fct> <int>
## 1 female a 494
## 2 female h 407
## 3 female d 389
## 4 male a 385
## 5 female g 381
## 6 male g 366
## 7 male d 288
## 8 female e 287
## 9 male h 277
## 10 male e 249
## 11 female f 239
## 12 female b 213
## 13 male f 190
## 14 male b 170
## 15 female i 153
## 16 male i 129
## 17 female c 102
## 18 male c 86
ggplot(data=frecgeneroprod, aes(x=product, y=frecuencia, fill=gender)) +
geom_bar(stat="identity")

- El género Femenino tiene más preferencias por los productos a con 494, h con 407 y d con 389 comparado contra el género masculino.
- Se observa que el producto c no es tan preferido
2. Segmentación de los clientes con la frecuencia, la recencia y el total de compra de cada cliente
- Se hace una nuevo data frame con los cliente únicos con las columnas clientes, resencia y frecuencia
- Hay 296 clientes diferentes,
- Se agrega una nueva columna conforme regla siguiente:
#segmentaClientes <- data.frame(cbind(cliente = sort(unique(datos$clientId))))
#nrow(segmentaClientes)
# Resumen de datos min y max
summarise(datos, minfecha = min(orderdate),
maxfecha = max(orderdate))
## minfecha maxfecha
## 1 2017-01-02 2017-04-11
# Agrupando datos
segmentaClientes <- datos %>%
group_by(clientId) %>%
summarise(minfecha = min(orderdate),
maxfecha = max(orderdate),
frecuencia = n(),
total = sum(Quantity * Price))
# Cuantos productos diferentes por cliente
productosDifXCliente <- count(datos, clientId, product) %>%
group_by(clientId) %>%
summarise(proddif = n())
# productosDifXCliente
segmentaClientes$prodDifXcliente <- productosDifXCliente$proddif
nrow(segmentaClientes)
## [1] 296
laultimacompra <- max(datos$orderdate)
segmentaClientes$recenciaDias = round(difftime(laultimacompra,
segmentaClientes$maxfecha, units = c("days")), 0)
segmentaClientes$recenciaSemanas = round(difftime(laultimacompra,
segmentaClientes$maxfecha, units = c("weeks")), 0)
# Haciendo la segmentación de clientes por las semanas de resencia
segmentaClientes$resenciaClase <- ordered(ifelse(segmentaClientes$recenciaSemanas < 2, '0-1 Semana',
ifelse(segmentaClientes$recenciaSemanas <= 3, '2-3 Semanas',
ifelse(segmentaClientes$recenciaSemanas <= 6, '4-6 Semanas',
ifelse(segmentaClientes$recenciaSemanas <=12, '7-12 Semanas','+12 Semanas')))),
levels = c('0-1 Semana', '2-3 Semanas', '4-6 Semanas','7-12 Semanas','+12 Semanas' ))
# Haciendo la segmentación de clientes por total de compra
segmentaClientes$totalClase <- ordered(ifelse(segmentaClientes$total <= 50, '0-50',
ifelse(segmentaClientes$total <= 100, '51-100',
ifelse(segmentaClientes$total <= 200, '101-200',
ifelse(segmentaClientes$total <=400, '201-400','+401')))),
levels = c('0-50', '51-100', '101-200','201-400','+401' ))
# Visualizar columnas de segmentaclientes
# head(segmentaClientes[,1:6])
# head(segmentaClientes[,c(1,7,8,9,10)])
summary(segmentaClientes)
## clientId minfecha maxfecha
## Min. : 1.00 Min. :2017-01-02 Min. :2017-01-03
## 1st Qu.: 74.75 1st Qu.:2017-01-10 1st Qu.:2017-03-03
## Median :149.50 Median :2017-01-21 Median :2017-03-23
## Mean :150.01 Mean :2017-01-29 Mean :2017-03-16
## 3rd Qu.:225.25 3rd Qu.:2017-02-12 3rd Qu.:2017-04-03
## Max. :300.00 Max. :2017-04-11 Max. :2017-04-11
## frecuencia total prodDifXcliente recenciaDias
## Min. : 1.00 Min. : 5.0 Min. :1.000 Length:296
## 1st Qu.:10.00 1st Qu.: 320.0 1st Qu.:6.000 Class :difftime
## Median :16.00 Median : 560.0 Median :7.000 Mode :numeric
## Mean :16.23 Mean : 582.6 Mean :6.608
## 3rd Qu.:22.00 3rd Qu.: 771.2 3rd Qu.:8.000
## Max. :53.00 Max. :1960.0 Max. :9.000
## recenciaSemanas resenciaClase totalClase
## Length:296 0-1 Semana :97 0-50 : 3
## Class :difftime 2-3 Semanas :82 51-100 : 5
## Mode :numeric 4-6 Semanas :59 101-200: 27
## 7-12 Semanas:54 201-400: 66
## +12 Semanas : 4 +401 :195
##
Visualizando Recencia X Frecuencia
RXF <- segmentaClientes %>%
group_by(resenciaClase) %>%
summarise(Freq = n())
RXF
## # A tibble: 5 x 2
## resenciaClase Freq
## <ord> <int>
## 1 0-1 Semana 97
## 2 2-3 Semanas 82
## 3 4-6 Semanas 59
## 4 7-12 Semanas 54
## 5 +12 Semanas 4
ggplot(data=RXF, aes(x=resenciaClase, y=Freq, fill=resenciaClase)) +
geom_bar(stat="identity") +
geom_text(aes(label=Freq), vjust=1.6, color="white",
position = position_dodge(0.9), size=3.5)+
theme_minimal()

- Hay 97 clientes clientes que tardan de 0 a 1 semana en volver a realizar una compra
- Hay 82 clientes clientes que tardan de 2 a 3 semanas en volver a realizar una compra
- Hay 4 clientes que tardan mas de 12 semanas en volver a realizar compras
Visualizando Recencia X Total
RXM <- segmentaClientes %>%
group_by(totalClase) %>%
summarise(Freq = n())
RXM
## # A tibble: 5 x 2
## totalClase Freq
## <ord> <int>
## 1 0-50 3
## 2 51-100 5
## 3 101-200 27
## 4 201-400 66
## 5 +401 195
ggplot(data=RXM, aes(x=totalClase, y=Freq, fill=totalClase)) +
geom_bar(stat="identity") +
geom_text(aes(label=Freq), vjust=1.6, color="white",
position = position_dodge(0.9), size=3.5)+
theme_minimal()

- Existen 3 clientes que compran de $ 0 a $ 50 (euros, pesos..)
- Existen 195 clientes que realizan compras mayores a $ 401 (euros, pesos..)
3. Dendograma de la tipología de productos por el total gasto de cada cliente (cantidad por precio)
Se hace conforme al video 4
Nuevamente se visualiZa head y tail de los datos originales
Se hace la agrUpación por prodUcto y su cantidad
head(datos)
## orderId clientId product gender orderdate Quantity Price dia mes agnio
## 1 1 255 g female 2017-01-03 3 5 3 1 2017
## 2 1 255 a female 2017-01-03 3 14 3 1 2017
## 3 1 255 b female 2017-01-03 3 22 3 1 2017
## 4 1 255 a female 2017-01-03 1 14 3 1 2017
## 5 2 145 h male 2017-01-05 1 26 5 1 2017
## 6 2 145 h male 2017-01-05 1 26 5 1 2017
tail(datos)
## orderId clientId product gender orderdate Quantity Price dia mes
## 4800 999 241 i female 2017-03-13 2 32 13 3
## 4801 1000 235 e female 2017-02-03 2 30 3 2
## 4802 1000 235 b female 2017-02-03 1 22 3 2
## 4803 1000 235 f female 2017-02-03 1 24 3 2
## 4804 1000 235 h female 2017-02-03 1 26 3 2
## 4805 1000 235 g female 2017-02-03 2 5 3 2
## agnio
## 4800 2017
## 4801 2017
## 4802 2017
## 4803 2017
## 4804 2017
## 4805 2017
ProdTotal <- datos %>%
group_by(product) %>%
summarise(total = sum(Quantity * Price))
ProdTotal
## # A tibble: 9 x 2
## product total
## <fct> <int>
## 1 a 23982
## 2 b 16566
## 3 c 3420
## 4 d 15984
## 5 e 31710
## 6 f 20856
## 7 g 7520
## 8 h 34996
## 9 i 17408
ggplot(data=ProdTotal, aes(x=product, y=total, fill=product)) +
geom_bar(stat="identity") +
geom_text(aes(label=total), vjust=1.6, color="white",
position = position_dodge(0.9), size=3.5)+
theme_minimal()

- El producto que mas se vende es el h, e y a
- El producto que menos se vende es el c y g
Haciendo el dendograma
# Determinando ka distancia
d <- dist(ProdTotal$total, method = "euclidean")
d
## 1 2 3 4 5 6 7 8
## 2 7416
## 3 20562 13146
## 4 7998 582 12564
## 5 7728 15144 28290 15726
## 6 3126 4290 17436 4872 10854
## 7 16462 9046 4100 8464 24190 13336
## 8 11014 18430 31576 19012 3286 14140 27476
## 9 6574 842 13988 1424 14302 3448 9888 17588
pfit <- hclust(d, method = "ward.D")
plot(pfit, labels=ProdTotal$product,
main = "Dendograma de la tipología de productos por el Gastos total de cada Cte.", xlab = "Productos")
rect.hclust(pfit, k = 4)

- El primer cluster se indentifica por los prouctos e y h.
- Un segundo cluster lo identifican los productos c y g
- Un tercer cluster lo identifican los productos i, b y d
- Un cuarto cluster lo determinan los productos a y f
- Estos gruos significa que los clientes cuando compran uno de ellos, seguramente también adquieren productos del mismo cluster.