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
##
## 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==