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 la clasificación

segmentos <- kmeans(df,grupos)
#segmentos

4. Revisar la asignación de grupos

asignacion <- cbind(df, cluster=segmentos$cluster)
#asignacion

5. Graficar resultados

library(ggplot2)
library(factoextra)

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

6. Optimizar 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 será el número de grupos de clusters optimo 

Actividad 4.1

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
ventas2 <- read.csv("ventas.csv")
summary(ventas2)
##     BillNo            Itemname            Quantity            Date          
##  Length:522064      Length:522064      Min.   :-9600.00   Length:522064     
##  Class :character   Class :character   1st Qu.:    1.00   Class :character  
##  Mode  :character   Mode  :character   Median :    3.00   Mode  :character  
##                                        Mean   :   10.09                     
##                                        3rd Qu.:   10.00                     
##                                        Max.   :80995.00                     
##                                                                             
##      Hour               Price              CustomerID       Country         
##  Length:522064      Min.   :-11062.060   Min.   :12346    Length:522064     
##  Class :character   1st Qu.:     1.250   1st Qu.:13950    Class :character  
##  Mode  :character   Median :     2.080   Median :15265    Mode  :character  
##                     Mean   :     3.827   Mean   :15317                      
##                     3rd Qu.:     4.130   3rd Qu.:16837                      
##                     Max.   : 13541.330   Max.   :18287                      
##                                          NA's   :134041                     
##      Total          
##  Min.   :-11062.06  
##  1st Qu.:     3.75  
##  Median :     9.78  
##  Mean   :    19.69  
##  3rd Qu.:    17.40  
##  Max.   :168469.60  
## 

Observaciones: 1. Tenemos cantidades, precios y totales negativos 2. Fecha y hora no tienen formatos 3. Tenemos NA’s en CustomerID

Limpieza de datos

# Número de NA's en ventas
sum(is.na(ventas2))
## [1] 134041
# Cuantos NA's por variable
sapply(ventas2, 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's de CustomerID
ventas2 <- na.omit(ventas2)

# Eliminar totales negativos
ventas2 <- ventas2[ventas2$Total>0,]

# Identificar Outliers
boxplot(ventas2$Total, horizontal=TRUE)

Observaciones: 4. Hay outliers en “Total”

Cantidad de visitas por cliente, ticket promedio y union de ambas tablas

# Cantidad de visitas
visitas3 <- group_by(ventas2, CustomerID) %>% summarize(Visitas = n_distinct(BillNo))

# Obtener total por ticket
ticket_promedio <- aggregate(Total ~ CustomerID + BillNo, data= ventas2, FUN= sum)
ticket_promedio <- aggregate(Total ~ CustomerID , data= ticket_promedio, FUN= mean)
#ticket_promedio

# Juntar ambas tablas
objetos <- merge(visitas3, ticket_promedio, by= "CustomerID")
row.names(objetos) <- (objetos$CustomerID)
objetos$CustomerID <- NULL
#objetos

# Eliminar datos fuera de lo normal
# Limites de los datos fuera de lo normal
# Limite inferior= Q1 - 1.5*IQR (interquartil)
# Limite superior= Q3 + 1.5*IQR (interquartil)

#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<- 5+1.5*IQR_V
#LS_V

objetos<- objetos[objetos$Visitas<=11,]

# Columna ticket promedio
colnames(objetos) <- c("Visitas", "TicketPromedio")
IQR_TP <- IQR(objetos$TicketPromedio)
#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

Asignación de grupos

# Asignando numero de grupos de clusters
grupos3<- 4
df <- objetos 

# Clsaificación
segmentos3 <- kmeans(df, grupos3)
#segmentos3

# Revisar la asignación de grupos
asignacion3 <- cbind(df, cluster=segmentos3$cluster)
#asignacion3

# Grafica
fviz_cluster(segmentos3, data=df, 
             palette=c("red", "blue", "green", "orange"), 
             ellipse.type="euclid", 
             star.plot= T, 
             repel= T, 
             ggtheme = theme()
             )

# Optimizar grupos
set.seed(123)

optimizacion <- clusGap(df, FUN=kmeans, nstart=1, K.max=7)
## Warning: Quick-TRANSfer stage steps exceeded maximum (= 188200)
plot(optimizacion, 
     xlab= "Número de clusters k")

LS0tDQp0aXRsZTogIkFjdGl2aWRhZCA0LjEiDQphdXRob3I6ICJKb3JnZSBDYW5pemFsZXoiDQpkYXRlOiAiMjAyMy0wOS0xOCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIHRoZW1lOiAieWV0aSINCiAgICBoaWdobGlnaHQ6ICJ0YW5nbyINCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQohW10oQzoiQzpcVXNlcnNcYWRyaWFcRG9jdW1lbnRzXFNlbWVzdHJlIDdcTW9kdWxvIDRcYW5hbGlzaXMuZ2lmIikNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5UZW9yw61hPC9zcGFuPg0KDQojIyAxLiBDcmVhciBiYXNlIGRlIGRhdG9zDQpgYGB7cn0NCmRmIDwtICBkYXRhLmZyYW1lKHg9YygyLDIsOCw1LDcsNiwxLDQpLCB5PWMoMTAsNSw0LDgsNSw0LDIsOSkpDQpgYGANCg0KIyMgMi4gRGV0ZXJtaW5hciBlbCBuw7ptZXJvIGRlIGdydXBvcw0KYGBge3J9DQpncnVwb3MgPC0gMw0KYGBgDQoNCiMjIDMuIFJlYWxpemFyIGxhIGNsYXNpZmljYWNpw7NuDQpgYGB7cn0NCnNlZ21lbnRvcyA8LSBrbWVhbnMoZGYsZ3J1cG9zKQ0KI3NlZ21lbnRvcw0KYGBgDQoNCiMjIDQuIFJldmlzYXIgbGEgYXNpZ25hY2nDs24gZGUgZ3J1cG9zDQpgYGB7cn0NCmFzaWduYWNpb24gPC0gY2JpbmQoZGYsIGNsdXN0ZXI9c2VnbWVudG9zJGNsdXN0ZXIpDQojYXNpZ25hY2lvbg0KYGBgDQoNCiMjIDUuIEdyYWZpY2FyIHJlc3VsdGFkb3MNCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQoNCmZ2aXpfY2x1c3RlcihzZWdtZW50b3MsIGRhdGE9ZGYsIA0KICAgICAgICAgICAgIHBhbGV0dGU9YygicmVkIiwgImJsdWUiLCAiZ3JlZW4iKSwgDQogICAgICAgICAgICAgZWxsaXBzZS50eXBlPSJldWNsaWQiLCANCiAgICAgICAgICAgICBzdGFyLnBsb3Q9IFQsIA0KICAgICAgICAgICAgIHJlcGVsPSBULCANCiAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWUoKQ0KICAgICAgICAgICAgICkNCmBgYA0KDQojIyA2LiBPcHRpbWl6YXIgZ3J1cG9zDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShjbHVzdGVyKQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0KDQpzZXQuc2VlZCgxMjMpDQoNCm9wdGltaXphY2lvbiA8LSBjbHVzR2FwKGRmLCBGVU49a21lYW5zLCBuc3RhcnQ9MSwgSy5tYXg9NykNCnBsb3Qob3B0aW1pemFjaW9uLCANCiAgICAgeGxhYj0gIk7Dum1lcm8gZGUgY2x1c3RlcnMgayIpDQoNCiMgRWwgcHVudG8gbcOhcyBhbHRvIGRlIGxhIGdyw6FmaWNhIHNlcsOhIGVsIG7Dum1lcm8gZGUgZ3J1cG9zIGRlIGNsdXN0ZXJzIG9wdGltbyANCmBgYA0KDQojIEFjdGl2aWRhZCA0LjENCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCnZlbnRhczIgPC0gcmVhZC5jc3YoInZlbnRhcy5jc3YiKQ0KYGBgDQoNCg0KYGBge3J9DQpzdW1tYXJ5KHZlbnRhczIpDQpgYGANCg0KT2JzZXJ2YWNpb25lczogDQoxLiBUZW5lbW9zIGNhbnRpZGFkZXMsIHByZWNpb3MgeSB0b3RhbGVzIG5lZ2F0aXZvcw0KMi4gRmVjaGEgeSBob3JhIG5vIHRpZW5lbiBmb3JtYXRvcw0KMy4gVGVuZW1vcyBOQSdzIGVuIEN1c3RvbWVySUQNCg0KIyMgTGltcGllemEgZGUgZGF0b3MNCmBgYHtyfQ0KIyBOw7ptZXJvIGRlIE5BJ3MgZW4gdmVudGFzDQpzdW0oaXMubmEodmVudGFzMikpDQoNCiMgQ3VhbnRvcyBOQSdzIHBvciB2YXJpYWJsZQ0Kc2FwcGx5KHZlbnRhczIsIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpDQoNCiMgRWxpbWluYXIgTkEncyBkZSBDdXN0b21lcklEDQp2ZW50YXMyIDwtIG5hLm9taXQodmVudGFzMikNCg0KIyBFbGltaW5hciB0b3RhbGVzIG5lZ2F0aXZvcw0KdmVudGFzMiA8LSB2ZW50YXMyW3ZlbnRhczIkVG90YWw+MCxdDQoNCiMgSWRlbnRpZmljYXIgT3V0bGllcnMNCmJveHBsb3QodmVudGFzMiRUb3RhbCwgaG9yaXpvbnRhbD1UUlVFKQ0KYGBgDQogT2JzZXJ2YWNpb25lczogDQogNC4gSGF5IG91dGxpZXJzIGVuICJUb3RhbCINCiANCiMjIENhbnRpZGFkIGRlIHZpc2l0YXMgcG9yIGNsaWVudGUsIHRpY2tldCBwcm9tZWRpbyB5IHVuaW9uIGRlIGFtYmFzIHRhYmxhcw0KYGBge3J9DQojIENhbnRpZGFkIGRlIHZpc2l0YXMNCnZpc2l0YXMzIDwtIGdyb3VwX2J5KHZlbnRhczIsIEN1c3RvbWVySUQpICU+JSBzdW1tYXJpemUoVmlzaXRhcyA9IG5fZGlzdGluY3QoQmlsbE5vKSkNCg0KIyBPYnRlbmVyIHRvdGFsIHBvciB0aWNrZXQNCnRpY2tldF9wcm9tZWRpbyA8LSBhZ2dyZWdhdGUoVG90YWwgfiBDdXN0b21lcklEICsgQmlsbE5vLCBkYXRhPSB2ZW50YXMyLCBGVU49IHN1bSkNCnRpY2tldF9wcm9tZWRpbyA8LSBhZ2dyZWdhdGUoVG90YWwgfiBDdXN0b21lcklEICwgZGF0YT0gdGlja2V0X3Byb21lZGlvLCBGVU49IG1lYW4pDQojdGlja2V0X3Byb21lZGlvDQoNCiMgSnVudGFyIGFtYmFzIHRhYmxhcw0Kb2JqZXRvcyA8LSBtZXJnZSh2aXNpdGFzMywgdGlja2V0X3Byb21lZGlvLCBieT0gIkN1c3RvbWVySUQiKQ0Kcm93Lm5hbWVzKG9iamV0b3MpIDwtIChvYmpldG9zJEN1c3RvbWVySUQpDQpvYmpldG9zJEN1c3RvbWVySUQgPC0gTlVMTA0KI29iamV0b3MNCg0KIyBFbGltaW5hciBkYXRvcyBmdWVyYSBkZSBsbyBub3JtYWwNCiMgTGltaXRlcyBkZSBsb3MgZGF0b3MgZnVlcmEgZGUgbG8gbm9ybWFsDQojIExpbWl0ZSBpbmZlcmlvcj0gUTEgLSAxLjUqSVFSIChpbnRlcnF1YXJ0aWwpDQojIExpbWl0ZSBzdXBlcmlvcj0gUTMgKyAxLjUqSVFSIChpbnRlcnF1YXJ0aWwpDQoNCiNDb2x1bW5hIHZpc2l0YXMNCklRUl9WIDwtIElRUihvYmpldG9zJFZpc2l0YXMpDQojSVFSX1YNCnN1bW1hcnkob2JqZXRvcykNCkxJX1YgPC0gMS0xLjUqSVFSX1YNCiNMSV9WDQoNCkxTX1Y8LSA1KzEuNSpJUVJfVg0KI0xTX1YNCg0Kb2JqZXRvczwtIG9iamV0b3Nbb2JqZXRvcyRWaXNpdGFzPD0xMSxdDQoNCiMgQ29sdW1uYSB0aWNrZXQgcHJvbWVkaW8NCmNvbG5hbWVzKG9iamV0b3MpIDwtIGMoIlZpc2l0YXMiLCAiVGlja2V0UHJvbWVkaW8iKQ0KSVFSX1RQIDwtIElRUihvYmpldG9zJFRpY2tldFByb21lZGlvKQ0KI0lRUl9UUA0KDQpMSV9UUDwtIDE3OC4zMCAtMS41KklRUl9UUA0KI0xJX1RQDQoNCkxTX1RQIDwtIDQyNi42MyArIDEuNSpJUVJfVFANCiNMU19UUA0KDQpvYmpldG9zIDwtIG9iamV0b3Nbb2JqZXRvcyRUaWNrZXRQcm9tZWRpbzw9IDc5MS42OSxdDQpzdW1tYXJ5KG9iamV0b3MpDQpgYGANCiANCiMjIEFzaWduYWNpw7NuIGRlIGdydXBvcw0KYGBge3J9DQojIEFzaWduYW5kbyBudW1lcm8gZGUgZ3J1cG9zIGRlIGNsdXN0ZXJzDQpncnVwb3MzPC0gNA0KZGYgPC0gb2JqZXRvcyANCg0KIyBDbHNhaWZpY2FjacOzbg0Kc2VnbWVudG9zMyA8LSBrbWVhbnMoZGYsIGdydXBvczMpDQojc2VnbWVudG9zMw0KDQojIFJldmlzYXIgbGEgYXNpZ25hY2nDs24gZGUgZ3J1cG9zDQphc2lnbmFjaW9uMyA8LSBjYmluZChkZiwgY2x1c3Rlcj1zZWdtZW50b3MzJGNsdXN0ZXIpDQojYXNpZ25hY2lvbjMNCg0KIyBHcmFmaWNhDQpmdml6X2NsdXN0ZXIoc2VnbWVudG9zMywgZGF0YT1kZiwgDQogICAgICAgICAgICAgcGFsZXR0ZT1jKCJyZWQiLCAiYmx1ZSIsICJncmVlbiIsICJvcmFuZ2UiKSwgDQogICAgICAgICAgICAgZWxsaXBzZS50eXBlPSJldWNsaWQiLCANCiAgICAgICAgICAgICBzdGFyLnBsb3Q9IFQsIA0KICAgICAgICAgICAgIHJlcGVsPSBULCANCiAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWUoKQ0KICAgICAgICAgICAgICkNCiMgT3B0aW1pemFyIGdydXBvcw0Kc2V0LnNlZWQoMTIzKQ0KDQpvcHRpbWl6YWNpb24gPC0gY2x1c0dhcChkZiwgRlVOPWttZWFucywgbnN0YXJ0PTEsIEsubWF4PTcpDQpwbG90KG9wdGltaXphY2lvbiwgDQogICAgIHhsYWI9ICJOw7ptZXJvIGRlIGNsdXN0ZXJzIGsiKQ0KDQpgYGANCg0K