En este notebook voy a realizar un caso de análisis multivariante con kmeans para agrupar las actividades con diferentes características o perfile

Recordemos que estamos trabajando sobre un dataset de actividades de carrera de un atleta

Cargo el dataset limpio del notebook https://rpubs.com/cperaltap/actividad_1_limpieza
act_data <- read.csv('act_data.csv')
# Selecciono todas las variables menos las relacionadas con la fecha
act_data_case <- act_data %>% select(Distancia, Calorias, Tiempo, FCMedia, Zancada, Ascenso, Velocidad)
act_data_case
Normalización de datos para que no tengan un peso diferente
act_data_norm <- scale(act_data_case)
# Vemos un resumen de como han quedado ahora los datos
head(act_data_norm)
##       Distancia     Calorias     Tiempo    FCMedia    Zancada     Ascenso  Velocidad
## [1,] -0.1996620 -0.008104384 -0.4183274  1.0842880  0.8535718 -0.75400942  0.8270334
## [2,] -2.1415920 -1.337813429 -1.7713653  1.9640520 -2.8125135 -1.37390028 -2.9672049
## [3,] -0.8753007 -0.518129771 -0.7357067  1.6441378 -0.5659213  0.13539921 -0.6322890
## [4,] -0.8625528 -1.732475931 -0.9027484 -0.2753473  0.1397577 -0.91572008  0.1946604
## [5,] -0.4503707 -0.645636118 -0.5040271  0.1245454  0.1916324  0.08149565  0.1946604
## [6,] -0.4503707 -0.451340732 -0.6507333  0.8443523  0.8630125  0.29710987  0.8464911
Ahora realizamos el modelo con kmeans
# Fijo semilla dada la aleatoriedad de kmeans
set.seed(123)

# Lanzo para un centroide
act_data_km <- (kmeans(act_data_norm, centers = 1)$betweenss)/
  (kmeans(act_data_norm, centers = 1)$totss)

# Itero para más centroides y poder ver la curva de progreso y valorar
for(i in 2:10) act_data_km[i] <- 
  (kmeans(act_data_norm, centers = i)$betweenss)/(kmeans(act_data_norm, centers = 1)$totss)

# Grafico la curva
plot(1:10, act_data_km, type="b", xlab = "número de clusters",
     ylab = "% de varianza explicada")

Vemos que con la gráfica del porcentaje de la varianza explicada, no vemos ningún “codo” o cambio de inclinación reseñable que nos haga decidirnos de forma relativamente objetiva sobre el número de clusters a usar, por lo que opto por hacerlo subjetivamente analizando bajo mi criterio los resultados de la tabla y de una gráfica que muestro.

# Pongo semilla de nuevo
set.seed(123)

# Calculo 4 clusters
act_data_km_4 <- kmeans(act_data_norm, centers = 4)

# Creo los grupos agrupados por la media y los muestro
grupos <- aggregate(act_data_case, by = list(act_data_km_4$cluster), mean)
kable(grupos, col.names = c("cluster","Distancia","Calorias","Tiempo","FCMedia","Zancada","Ascenso","Velocidad"))
cluster Distancia Calorias Tiempo FCMedia Zancada Ascenso Velocidad
1 4.436622 259.2838 28.33608 133.3919 0.9308382 35.56757 9.428649
2 10.586750 683.2625 60.80087 152.5125 1.0259838 110.43750 10.510375
3 7.113102 459.9572 42.69107 146.9465 0.9809167 70.25668 10.012086
4 6.294672 387.3443 32.76344 149.6066 1.1398865 48.70492 11.586967
Creo además un gráfico de puntos con los cluters del modelo apoyándome en la libreria factoextra
fviz_cluster(act_data_km_4, data = act_data_case,
  palette = "Set2",
  geom = "point",
  ellipse.type = "convex",
  ggtheme = theme_bw()
  )

Tras evaluarlo y decidir entre 3 y 4 clusters, me decido por 4 ya que se crean perfiles de carrera bien remarcados. 3 clusteres también habría sido una opción correcta.

Clasificos los resultados: - Custer 1: Distancias cortas con media menor de 5k, de menos de 30 minutos de carreta con un consumo bajo de calorias, poco ascenso (posible llanos) y velocidad cercana a 9.5 kmh. Frecuencia media baja, sobre 130. Podrían ser actividades de calentamiento o entrenamientos en época de lesiones para probar. - Cluster 2: Distancias largas, con la media por encima de 10Km, con alto consumo de calorias, casi 700. Duración aproximada de 1 hora por sesión, con una zancada de un metro y ascenso total por encima de 100m. La velocidad ronda los 10.5 kmh. Entrenos más serios, incluso alguna carrera. - Clústeres 3 y 4: Los comparo porque comparten distancias similares, entre 6 y 7, pero con distintas características. En el cluster 4 la velocidad y zancada es mayor y el ascenso y el tiempo menor, lo que hace indicar que son tipos de actividades similares. Pero el cluster 3, más “tranquilo”, pueden ser entrenos, y en el 4 se agrupen entrenos más exigentes, con terreno más llano, y revisando la velocidad, incluso competitivas.

Terminado el análisis puede ser intersante ver si hay outliers y cuantos son
# Calculo los centroides
centroides <- fitted(act_data_km_4)
# Calculo las distancias 
distancias <- sqrt(rowSums((act_data_case - centroides)^2))
# Cuento los outliers
length(boxplot.stats(distancias)$out)
## [1] 12
# Los muestro en un diagrama de caja
boxplot(distancias)

# Calculo porcentaje de outliers
round(length(boxplot.stats(distancias)$out) / nrow(act_data_case), 3)
## [1] 0.026

Nos aparecen 12 outliers, que suponen un 2.6% de los registros, lo cual puedo considerar totalmente asumible en el modelo.