Teoría

# 1. Crear base de datos
df <- data.frame(x=c(2,2,8,5,7,6,1,4),
                 y=c(10,5,4,8,5,4,2,9))

# 2. Determinar el número de grupos
grupos <- 3

# 3. Realizar clasificación
segmentos <- kmeans(df,grupos)
#segmentos

# 4. Revisar la asignación de grupos
asignacion <-  cbind(df, cluster=segmentos$cluster)
#asignacion

# 5. Graficar resultados
# install.packages("factoextra")
library(ggplot2)
library(factoextra)

fviz_cluster(segmentos, data=df,
             palette=c("red", "blue", "darkgreen"),
             ellipse.type="euclid",
             star.plot= T,
             repel= T,
             ggtheme= theme()
             )

# 6. Optimizar cantidad de grupos
library(cluster)
library(data.table)
set.seed(123)
optimizacion <- clusGap(df, FUN= kmeans, nstart= 1, K.max= 7)
plot(optimizacion, xlab="Número de clusters K")

# El punto más alto de la gráfica indica la cantidad de grupos óptimo.

1. Importar la base de datos

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:data.table':
## 
##     between, first, last
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(readr)
library(readr)
bd <- read.csv("/Users/roygomez/Desktop/ventas.csv")
#View(bd)

#Conocer la blase de datos
#summary(bd)

#conocer la cantidad de las varibales
#count(bd,BillNo,sort = TRUE)
#count(bd,Itemname,sort = TRUE)
#count(bd,Date,sort = TRUE)
#count(bd,Hour,sort = TRUE)
#count(bd,Country,sort = TRUE)

Observaciones:
1. Tenemos cantidades, precios y totales negativos. 2. Fecha y hora no tienen formato adecuado. 3. Tenemos NA en Costumer ID.

2. Limpieza

# ¿Cuántos NA tengo en la base de datos?
sum(is.na(bd))
## [1] 134041
# ¿Cuántos NA tengo por variable?
sapply(bd, function(x) sum(is.na(x)))
##     BillNo   Itemname   Quantity       Date       Hour      Price CustomerID 
##          0          0          0          0          0          0     134041 
##    Country      Total 
##          0          0
# Eliminar NA
bd <- na.omit(bd)

# Eliminar Totales negativos
bd <- bd[bd$Total > 0, ]

# Identificar outliers
boxplot(bd$Total, horizontal = TRUE)

Observaciones:
4. Tenemos outliers en Total.

# Obtener cantidades de visitas por cliente
visitas <- group_by(bd, CustomerID) %>% summarise(Visitas = n_distinct(BillNo))

# Obtener el total por ticket
ticket_prom <- aggregate(Total ~ CustomerID + BillNo, data=bd, sum)

#View(ticket_prom)

# Obtener el ticket promedio
ticket_prom <- aggregate(Total ~ CustomerID, data=ticket_prom, mean)

# Juntar las tablas vistas y ticket promedio
objetos <- merge(visitas, ticket_prom, by="CustomerID")

# Llamar a los renglones como CustomerID
rownames(objetos) <- objetos$CustomerID

# Eliminar columna de CustomerID
objetos <- subset(objetos, select=-c(CustomerID))

# Eliminar datos fuera de lo normal

# Los datos fuera de lo normal están fuera de los siguientes límites:
# Límite inferior = Q1 - 1.5*IQR
# Límite superior = Q3 + 1.5*IQR
# IQR = Rango Intercuartil

# Columna visitas
IQR_V <- IQR(objetos$Visitas)
#IQR_V
summary(objetos)
##     Visitas            Total         
##  Min.   :  1.000   Min.   :    3.45  
##  1st Qu.:  1.000   1st Qu.:  178.30  
##  Median :  2.000   Median :  292.00  
##  Mean   :  4.227   Mean   :  415.62  
##  3rd Qu.:  5.000   3rd Qu.:  426.63  
##  Max.   :209.000   Max.   :84236.25
LI_V <- 1-1.5*IQR_V
#LI_V
LS_V <-1+1.5*IQR_V
#LS_V
objetos <- objetos[objetos$Visitas <=11,]

# Columna ticket promedio
colnames(objetos) <- c("Visitas", "TicketPromedio")
IQR_TP <- IQR(objetos$Total)
#IQR_TP
LI_TP <- 178.30 - 1.5*IQR_TP
#LI_TP
LS_TP <- 426.63 + 1.5*IQR_TP
#LS_TP
objetos <- objetos[objetos$TicketPromedio <= 791.69,]
summary(objetos)
##     Visitas      TicketPromedio  
##  Min.   : 1.00   Min.   :  3.45  
##  1st Qu.: 1.00   1st Qu.:168.62  
##  Median : 2.00   Median :267.00  
##  Mean   : 2.97   Mean   :293.32  
##  3rd Qu.: 4.00   3rd Qu.:383.98  
##  Max.   :11.00   Max.   :789.56

3. Asignación de grupos (k-NN)

# 1. Crear base de datos
df <- objetos

# 2. Determinar el número de grupos
grupos <- 4

# 3. Realizar clasificación
segmentos <- kmeans(df,grupos)
#segmentos

# 4. Revisar la asignación de grupos
asignacion <-  cbind(df, cluster=segmentos$cluster)
#asignacion

# 5. Graficar resultados
# install.packages("factoextra")
library(ggplot2)
library(factoextra)

#fviz_cluster(segmentos, data=df,
 #            palette=c("red", "blue", "darkgreen", "yellow"),
  #           ellipse.type="euclid",
    #         star.plot= T,
     #        repel= T,
      #       ggtheme= theme()
       3
## [1] 3
       #)

# 6. Optimizar cantidad de grupos
library(cluster)
library(data.table)
set.seed(123)
optimizacion <- clusGap(df, FUN= kmeans, nstart= 1, K.max= 7)
#plot(optimizacion, xlab="Número de clusters K")

# El punto más alto de la gráfica indica la cantidad de grupos óptimo.
LS0tCnRpdGxlOiAiQWN0aXZpZGFkIDQuMSIKYXV0aG9yOiAiUm9nZWxpbyBHb21leiIKZGF0ZTogIjIwMjMtMDktMTgiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYWQ6IFRSVUUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKICAgIHRoZW1lOiAieWV0aSIKICAgIGhpZ2hsaWdodDogInRhbmdvIgotLS0KCiFbXSgvVXNlcnMvcm95Z29tZXovRGVza3RvcC9pa2VhLmdpZikKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlRlb3LDrWE8L3NwYW4+CmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgMS4gQ3JlYXIgYmFzZSBkZSBkYXRvcwpkZiA8LSBkYXRhLmZyYW1lKHg9YygyLDIsOCw1LDcsNiwxLDQpLAogICAgICAgICAgICAgICAgIHk9YygxMCw1LDQsOCw1LDQsMiw5KSkKCiMgMi4gRGV0ZXJtaW5hciBlbCBuw7ptZXJvIGRlIGdydXBvcwpncnVwb3MgPC0gMwoKIyAzLiBSZWFsaXphciBjbGFzaWZpY2FjacOzbgpzZWdtZW50b3MgPC0ga21lYW5zKGRmLGdydXBvcykKI3NlZ21lbnRvcwoKIyA0LiBSZXZpc2FyIGxhIGFzaWduYWNpw7NuIGRlIGdydXBvcwphc2lnbmFjaW9uIDwtICBjYmluZChkZiwgY2x1c3Rlcj1zZWdtZW50b3MkY2x1c3RlcikKI2FzaWduYWNpb24KCiMgNS4gR3JhZmljYXIgcmVzdWx0YWRvcwojIGluc3RhbGwucGFja2FnZXMoImZhY3RvZXh0cmEiKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZmFjdG9leHRyYSkKCmZ2aXpfY2x1c3RlcihzZWdtZW50b3MsIGRhdGE9ZGYsCiAgICAgICAgICAgICBwYWxldHRlPWMoInJlZCIsICJibHVlIiwgImRhcmtncmVlbiIpLAogICAgICAgICAgICAgZWxsaXBzZS50eXBlPSJldWNsaWQiLAogICAgICAgICAgICAgc3Rhci5wbG90PSBULAogICAgICAgICAgICAgcmVwZWw9IFQsCiAgICAgICAgICAgICBnZ3RoZW1lPSB0aGVtZSgpCiAgICAgICAgICAgICApCgojIDYuIE9wdGltaXphciBjYW50aWRhZCBkZSBncnVwb3MKbGlicmFyeShjbHVzdGVyKQpsaWJyYXJ5KGRhdGEudGFibGUpCnNldC5zZWVkKDEyMykKb3B0aW1pemFjaW9uIDwtIGNsdXNHYXAoZGYsIEZVTj0ga21lYW5zLCBuc3RhcnQ9IDEsIEsubWF4PSA3KQpwbG90KG9wdGltaXphY2lvbiwgeGxhYj0iTsO6bWVybyBkZSBjbHVzdGVycyBLIikKCiMgRWwgcHVudG8gbcOhcyBhbHRvIGRlIGxhIGdyw6FmaWNhIGluZGljYSBsYSBjYW50aWRhZCBkZSBncnVwb3Mgw7NwdGltby4KCmBgYAoKIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjEuIEltcG9ydGFyIGxhIGJhc2UgZGUgZGF0b3M8L3NwYW4+CgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKbGlicmFyeShyZWFkcikKYmQgPC0gcmVhZC5jc3YoIi9Vc2Vycy9yb3lnb21lei9EZXNrdG9wL3ZlbnRhcy5jc3YiKQojVmlldyhiZCkKCiNDb25vY2VyIGxhIGJsYXNlIGRlIGRhdG9zCiNzdW1tYXJ5KGJkKQoKI2Nvbm9jZXIgbGEgY2FudGlkYWQgZGUgbGFzIHZhcmliYWxlcwojY291bnQoYmQsQmlsbE5vLHNvcnQgPSBUUlVFKQojY291bnQoYmQsSXRlbW5hbWUsc29ydCA9IFRSVUUpCiNjb3VudChiZCxEYXRlLHNvcnQgPSBUUlVFKQojY291bnQoYmQsSG91cixzb3J0ID0gVFJVRSkKI2NvdW50KGJkLENvdW50cnksc29ydCA9IFRSVUUpCmBgYAoKT2JzZXJ2YWNpb25lczogIAoxLiBUZW5lbW9zIGNhbnRpZGFkZXMsIHByZWNpb3MgeSB0b3RhbGVzIG5lZ2F0aXZvcy4KMi4gRmVjaGEgeSBob3JhIG5vIHRpZW5lbiBmb3JtYXRvIGFkZWN1YWRvLgozLiBUZW5lbW9zIE5BIGVuIENvc3R1bWVyIElELgoKIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjIuIExpbXBpZXphPC9zcGFuPgpgYGB7cn0KIyDCv0N1w6FudG9zIE5BIHRlbmdvIGVuIGxhIGJhc2UgZGUgZGF0b3M/CnN1bShpcy5uYShiZCkpCgojIMK/Q3XDoW50b3MgTkEgdGVuZ28gcG9yIHZhcmlhYmxlPwpzYXBwbHkoYmQsIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpCgojIEVsaW1pbmFyIE5BCmJkIDwtIG5hLm9taXQoYmQpCgojIEVsaW1pbmFyIFRvdGFsZXMgbmVnYXRpdm9zCmJkIDwtIGJkW2JkJFRvdGFsID4gMCwgXQoKIyBJZGVudGlmaWNhciBvdXRsaWVycwpib3hwbG90KGJkJFRvdGFsLCBob3Jpem9udGFsID0gVFJVRSkKCmBgYAoKT2JzZXJ2YWNpb25lczogIAo0LiBUZW5lbW9zIG91dGxpZXJzIGVuIFRvdGFsLgoKYGBge3J9CiMgT2J0ZW5lciBjYW50aWRhZGVzIGRlIHZpc2l0YXMgcG9yIGNsaWVudGUKdmlzaXRhcyA8LSBncm91cF9ieShiZCwgQ3VzdG9tZXJJRCkgJT4lIHN1bW1hcmlzZShWaXNpdGFzID0gbl9kaXN0aW5jdChCaWxsTm8pKQoKIyBPYnRlbmVyIGVsIHRvdGFsIHBvciB0aWNrZXQKdGlja2V0X3Byb20gPC0gYWdncmVnYXRlKFRvdGFsIH4gQ3VzdG9tZXJJRCArIEJpbGxObywgZGF0YT1iZCwgc3VtKQoKI1ZpZXcodGlja2V0X3Byb20pCgojIE9idGVuZXIgZWwgdGlja2V0IHByb21lZGlvCnRpY2tldF9wcm9tIDwtIGFnZ3JlZ2F0ZShUb3RhbCB+IEN1c3RvbWVySUQsIGRhdGE9dGlja2V0X3Byb20sIG1lYW4pCgojIEp1bnRhciBsYXMgdGFibGFzIHZpc3RhcyB5IHRpY2tldCBwcm9tZWRpbwpvYmpldG9zIDwtIG1lcmdlKHZpc2l0YXMsIHRpY2tldF9wcm9tLCBieT0iQ3VzdG9tZXJJRCIpCgojIExsYW1hciBhIGxvcyByZW5nbG9uZXMgY29tbyBDdXN0b21lcklECnJvd25hbWVzKG9iamV0b3MpIDwtIG9iamV0b3MkQ3VzdG9tZXJJRAoKIyBFbGltaW5hciBjb2x1bW5hIGRlIEN1c3RvbWVySUQKb2JqZXRvcyA8LSBzdWJzZXQob2JqZXRvcywgc2VsZWN0PS1jKEN1c3RvbWVySUQpKQoKIyBFbGltaW5hciBkYXRvcyBmdWVyYSBkZSBsbyBub3JtYWwKCiMgTG9zIGRhdG9zIGZ1ZXJhIGRlIGxvIG5vcm1hbCBlc3TDoW4gZnVlcmEgZGUgbG9zIHNpZ3VpZW50ZXMgbMOtbWl0ZXM6CiMgTMOtbWl0ZSBpbmZlcmlvciA9IFExIC0gMS41KklRUgojIEzDrW1pdGUgc3VwZXJpb3IgPSBRMyArIDEuNSpJUVIKIyBJUVIgPSBSYW5nbyBJbnRlcmN1YXJ0aWwKCiMgQ29sdW1uYSB2aXNpdGFzCklRUl9WIDwtIElRUihvYmpldG9zJFZpc2l0YXMpCiNJUVJfVgpzdW1tYXJ5KG9iamV0b3MpCkxJX1YgPC0gMS0xLjUqSVFSX1YKI0xJX1YKTFNfViA8LTErMS41KklRUl9WCiNMU19WCm9iamV0b3MgPC0gb2JqZXRvc1tvYmpldG9zJFZpc2l0YXMgPD0xMSxdCgojIENvbHVtbmEgdGlja2V0IHByb21lZGlvCmNvbG5hbWVzKG9iamV0b3MpIDwtIGMoIlZpc2l0YXMiLCAiVGlja2V0UHJvbWVkaW8iKQpJUVJfVFAgPC0gSVFSKG9iamV0b3MkVG90YWwpCiNJUVJfVFAKTElfVFAgPC0gMTc4LjMwIC0gMS41KklRUl9UUAojTElfVFAKTFNfVFAgPC0gNDI2LjYzICsgMS41KklRUl9UUAojTFNfVFAKb2JqZXRvcyA8LSBvYmpldG9zW29iamV0b3MkVGlja2V0UHJvbWVkaW8gPD0gNzkxLjY5LF0Kc3VtbWFyeShvYmpldG9zKQoKYGBgCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+My4gQXNpZ25hY2nDs24gZGUgZ3J1cG9zIChrLU5OKTwvc3Bhbj4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgMS4gQ3JlYXIgYmFzZSBkZSBkYXRvcwpkZiA8LSBvYmpldG9zCgojIDIuIERldGVybWluYXIgZWwgbsO6bWVybyBkZSBncnVwb3MKZ3J1cG9zIDwtIDQKCiMgMy4gUmVhbGl6YXIgY2xhc2lmaWNhY2nDs24Kc2VnbWVudG9zIDwtIGttZWFucyhkZixncnVwb3MpCiNzZWdtZW50b3MKCiMgNC4gUmV2aXNhciBsYSBhc2lnbmFjacOzbiBkZSBncnVwb3MKYXNpZ25hY2lvbiA8LSAgY2JpbmQoZGYsIGNsdXN0ZXI9c2VnbWVudG9zJGNsdXN0ZXIpCiNhc2lnbmFjaW9uCgojIDUuIEdyYWZpY2FyIHJlc3VsdGFkb3MKIyBpbnN0YWxsLnBhY2thZ2VzKCJmYWN0b2V4dHJhIikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGZhY3RvZXh0cmEpCgojZnZpel9jbHVzdGVyKHNlZ21lbnRvcywgZGF0YT1kZiwKICMgICAgICAgICAgICBwYWxldHRlPWMoInJlZCIsICJibHVlIiwgImRhcmtncmVlbiIsICJ5ZWxsb3ciKSwKICAjICAgICAgICAgICBlbGxpcHNlLnR5cGU9ImV1Y2xpZCIsCiAgICAjICAgICAgICAgc3Rhci5wbG90PSBULAogICAgICMgICAgICAgIHJlcGVsPSBULAogICAgICAjICAgICAgIGdndGhlbWU9IHRoZW1lKCkKICAgICAgIDMKICAgICAgICMpCgojIDYuIE9wdGltaXphciBjYW50aWRhZCBkZSBncnVwb3MKbGlicmFyeShjbHVzdGVyKQpsaWJyYXJ5KGRhdGEudGFibGUpCnNldC5zZWVkKDEyMykKb3B0aW1pemFjaW9uIDwtIGNsdXNHYXAoZGYsIEZVTj0ga21lYW5zLCBuc3RhcnQ9IDEsIEsubWF4PSA3KQojcGxvdChvcHRpbWl6YWNpb24sIHhsYWI9Ik7Dum1lcm8gZGUgY2x1c3RlcnMgSyIpCgojIEVsIHB1bnRvIG3DoXMgYWx0byBkZSBsYSBncsOhZmljYSBpbmRpY2EgbGEgY2FudGlkYWQgZGUgZ3J1cG9zIMOzcHRpbW8uCgpgYGAKCgoKCg==