Case Study: How Can a Wellness Technology Company Play It Smart?

Introducción

Bellabeat es una compañía en busca de crecimiento y nuevas oportunidades que desarrolla productos tecnológicos enfocados en la salud para mujeres. Cuentan con diferentes productos para el registro de actividad de salud, junto con una aplicación. El propósito de este case study es encontrar tendencias que permitan entregar recomendaciones para las estrategias de marketing, a través del análisis del uso de dispositivos tecnológicos enfocados en el bienestar.

Stakeholders
  • CCO de Bellabeat: Urska Srsen
  • Co-founder de Bellabeat: Sando Mur
  • Equipo analítico de marketing de Bellabeat
Producto de principal análisis

Time: Combina el aspecto de un reloj clásico con tecnología inteligente para rastrear al usuario conectándose mediante la app.

Preparación

Se analizará el dataset de Fitbit, que contiene la información de rastreo de 33 usuarios, compilando datos como pasos diarios, minutos de sueño y cantidad de calorías, categorizadas de forma diaria o por hora. Específicamente los archivos que se utilizarán son los siguientes

  • dailyActivity_merged.csv
  • sleepDay_merged.csv
  • hourlyCalories_merged.csv
  • hourlyIntensities_merged.csv
  • hourlySteps_merged.csv

Las herramientas que se utilizarán para llevar a cabo el análisis son

  • Microsoft Excel
  • RStudio

El análisis se dividirá principalmente en dos partes

  1. Análisis de datos diarios
  • Minutos dormido vs. Pasos diarios
  • Retraso al dormir vs Pasos diarios
  1. Análisis de datos por horas
  • Cantidad de pasos vs Hora del día

Limpieza de datos

Excel

En primer lugar se analizaron los datos de forma general en Excel. Los archivos hourlyCalories_merged, hourlyIntensities_merged y hourlySteps_merged fueron unidos en un solo documento llamado “Con_Datos_Hora.xlsx” ,la columna AtivityHour se separó en fecha.

RStudio

Instalación de paquetes

install.packages("tidyverse")
library(tidyverse)
install.packages("janitor")
library(janitor)
install.packages("readxl")
library(readxl)
install.packages("gridExtra")
library(gridExtra)

Lectura de datos

daily <- read_csv('dailyActivity_merged.csv',show_col_types = FALSE)
hourly <- read_excel("Con_Datos_Hora.xlsx", sheet = 1)
sleep <- read_csv('sleepDay_merged.csv',show_col_types = FALSE)

Verificacion y eliminación de duplicados

sum(duplicated(hourly)) 
## [1] 0
sum(duplicated(daily)) 
## [1] 0
sum(duplicated(sleep)) 
## [1] 3

Existen 3 duplicados por lo que serán eliminados

sleep <- sleep[!duplicated(sleep),]

Se comprueba que efectivamente fueron eliminados

sum(duplicated(sleep))
## [1] 0

Cambio de nombres de columnas y eliminación de NULLS

Se ajustan los nombres de las columnas para que cumplan con el estándar

daily <- clean_names(daily)  %>% 
  remove_empty(which = c("rows")) %>% 
  remove_empty(which = c("cols")) 

sleep <- clean_names(sleep) %>% 
  remove_empty(which = c("rows")) %>% 
  remove_empty(which = c("cols")) 

hourly <- clean_names(hourly)%>% 
  remove_empty(which = c("rows")) %>% 
  remove_empty(which = c("cols")) 

colnames(sleep)[2] <- "fecha"
colnames(daily)[2] <- "fecha"

Verificacion formato de datos

str(hourly)
## tibble [22,099 × 9] (S3: tbl_df/tbl/data.frame)
##  $ id               : num [1:22099] 1.5e+09 1.5e+09 1.5e+09 1.5e+09 1.5e+09 ...
##  $ fecha            : POSIXct[1:22099], format: "2016-04-12" "2016-04-12" ...
##  $ hora12           : chr [1:22099] "12:00:00 AM" "01:00:00 AM" "02:00:00 AM" "03:00:00 AM" ...
##  $ hora24           : chr [1:22099] "00:00:00" "01:00:00" "02:00:00" "03:00:00" ...
##  $ step_total       : num [1:22099] 373 160 151 0 0 ...
##  $ calories         : num [1:22099] 81 61 59 47 48 48 48 47 68 141 ...
##  $ total_intensity  : num [1:22099] 20 8 7 0 0 0 0 0 13 30 ...
##  $ average_intensity: num [1:22099] 333333 133333 116667 0 0 ...
##  $ activity_hour    : chr [1:22099] "4/12/2016 12:00:00 AM" "4/12/2016 1:00:00 AM" "4/12/2016 2:00:00 AM" "4/12/2016 3:00:00 AM" ...
str(daily)
## tibble [940 × 15] (S3: tbl_df/tbl/data.frame)
##  $ id                        : num [1:940] 1.5e+09 1.5e+09 1.5e+09 1.5e+09 1.5e+09 ...
##  $ fecha                     : chr [1:940] "4/12/2016" "4/13/2016" "4/14/2016" "4/15/2016" ...
##  $ total_steps               : num [1:940] 13162 10735 10460 9762 12669 ...
##  $ total_distance            : num [1:940] 8.5 6.97 6.74 6.28 8.16 ...
##  $ tracker_distance          : num [1:940] 8.5 6.97 6.74 6.28 8.16 ...
##  $ logged_activities_distance: num [1:940] 0 0 0 0 0 0 0 0 0 0 ...
##  $ very_active_distance      : num [1:940] 1.88 1.57 2.44 2.14 2.71 ...
##  $ moderately_active_distance: num [1:940] 0.55 0.69 0.4 1.26 0.41 ...
##  $ light_active_distance     : num [1:940] 6.06 4.71 3.91 2.83 5.04 ...
##  $ sedentary_active_distance : num [1:940] 0 0 0 0 0 0 0 0 0 0 ...
##  $ very_active_minutes       : num [1:940] 25 21 30 29 36 38 42 50 28 19 ...
##  $ fairly_active_minutes     : num [1:940] 13 19 11 34 10 20 16 31 12 8 ...
##  $ lightly_active_minutes    : num [1:940] 328 217 181 209 221 164 233 264 205 211 ...
##  $ sedentary_minutes         : num [1:940] 728 776 1218 726 773 ...
##  $ calories                  : num [1:940] 1985 1797 1776 1745 1863 ...
str(sleep)
## tibble [410 × 5] (S3: tbl_df/tbl/data.frame)
##  $ id                  : num [1:410] 1.5e+09 1.5e+09 1.5e+09 1.5e+09 1.5e+09 ...
##  $ fecha               : chr [1:410] "4/12/2016 12:00:00 AM" "4/13/2016 12:00:00 AM" "4/15/2016 12:00:00 AM" "4/16/2016 12:00:00 AM" ...
##  $ total_sleep_records : num [1:410] 1 2 1 2 1 1 1 1 1 1 ...
##  $ total_minutes_asleep: num [1:410] 327 384 412 340 700 304 360 325 361 430 ...
##  $ total_time_in_bed   : num [1:410] 346 407 442 367 712 320 377 364 384 449 ...

Cambio de formato

daily$fecha <- as.Date(daily$fecha,"%m/%d/%Y")
sleep$fecha <- as.Date(sleep$fecha,"%m/%d/%Y")

Análisis

1.Análisis de datos diarios

Minutos dormido vs. Pasos diarios

Primero se combinarán los datos diarios (daily) con los datos de los habitos del sueño (sleep)

combined_daily_sleep <- merge(daily,sleep,
                              by= c("id","fecha"))

Para apreciar mejor la relación limitaremos el margen de valores usando el método del rango intercuartílico (IQR), permitiendo incrementar el grado de confianza al eliminar los datos atípicos.

Q1_steps <- quantile(combined_daily_sleep$total_steps, 0.25)
Q3_steps <- quantile(combined_daily_sleep$total_steps, 0.75)
Q1_sleep <- quantile(combined_daily_sleep$total_minutes_asleep, 0.25)
Q3_sleep <- quantile(combined_daily_sleep$total_minutes_asleep, 0.75)
IQR_steps <- Q3_steps - Q1_steps
IQR_sleep <- Q3_sleep - Q1_sleep
lim_sup_steps <- Q3_steps + 1.5*IQR_steps
lim_inf_sleep <- Q1_sleep - 1.5*IQR_sleep
lim_sup_sleep <- Q3_sleep + 1.5*IQR_sleep

Ahora graficaremos en torno a los limites obtenidos, además se destacará el rango más saludable de minutos diarios por dormir de acuerdo a la OMS, correspondientes a entre 7 a 8 horas, y se encontrará el porcentaje de días que cumplen con esta condición

dias_oms <- combined_daily_sleep %>% 
  filter(total_minutes_asleep >= 420 & total_minutes_asleep <= 480) 
pct_dias_oms <-count(dias_oms)*100/count(combined_daily_sleep)
count(dias_oms)
##     n
## 1 115
round(pct_dias_oms)
##    n
## 1 28
promedio_pasos_oms <- combined_daily_sleep %>% 
  filter(total_minutes_asleep >= 420 & total_minutes_asleep <= 480) %>% 
  summarize(promedio_pasos_oms = mean(total_steps))
round(promedio_pasos_oms)
##   promedio_pasos_oms
## 1               8493

Grafica

combined_daily_sleep%>% 
  filter(total_steps < lim_sup_steps) %>% 
  filter(total_minutes_asleep >lim_inf_sleep & total_minutes_asleep  < lim_sup_sleep) %>% 
  ggplot(aes(x=total_minutes_asleep ,y=total_steps) ) +
  geom_smooth()+
  geom_point()+ 
  annotate("rect", xmin=420, xmax = 480,ymin=0, ymax=18000,
           alpha= .2, fill="green")+
  annotate("text", x = 450, y = 18500, 
           label = "Recomendación OMS", hjust = "center", size = 3)+
  labs(x= "Minutos dormido",y= "Pasos totales")+
  ggtitle("Relación entre pasos totales y minutos dormido")

Parece haber una relación negativa entre los pasos totales. Mientras más pasos dieron, menos minutos durmieron. Solo el 28% de los días (115) están dentro del rango saludable de horas diarias por dormir de acuerdo a las recomendaciones de la OMS. Entre estos la cantidad de pasos por día en promedio fue de 8493.

Retraso al dormir vs Pasos diarios

Definiremos el retraso al dormir como la cantidad de minutos que pasa el usuario en la cama sin dormir. Añadiremos una columna que muestre la diferencia entre los minutos que el usuario pasa en la cama y los minutos que pasa durmiendo

combined_daily_sleep<- mutate(combined_daily_sleep, 
                                        min_despierto = total_time_in_bed - total_minutes_asleep)

Ahora calcularemos el tiempo promedio de retraso al dormir de los usuarios

mean(sleep$total_time_in_bed-sleep$total_minutes_asleep)
## [1] 39.30976

Para graficarlo, al igual que en el paso anterior, usaremos el método del IQR

Q1_min_desp <- quantile(combined_daily_sleep$min_despierto, 0.25)
Q3_min_desp <- quantile(combined_daily_sleep$min_despierto, 0.75)
IQR_min_desp <- Q3_min_desp - Q1_min_desp
lim_sup_min_desp <- Q3_min_desp + 1.5*IQR_min_desp

Ahora graficamos

combined_daily_sleep%>% 
  filter(total_steps < lim_sup_steps) %>% 
  filter(min_despierto  < lim_sup_min_desp) %>%
  ggplot(aes(x=min_despierto ,y=total_steps) ) +
  geom_smooth()+
  geom_point()+
  labs(x= "Retraso al dormir (Min despierto)",y= "Pasos totales")+
  ggtitle("Relacion entre pasos totales y retraso al dormir")

No se genera una linea de tendencia clara. Al parecer no existe una correlación directa entre la cantidad de pasos diarios y los minutos de retraso de los usuarios para dormir.

Ahora se analizará la cantidad de pasos promedio de los días en los que personas tuvieron un mayor retraso al dormir, considerando aquellos que sean superiores al límite superior calculado mediante el IQR:

dias_retraso_max <- combined_daily_sleep %>% 
  filter(min_despierto>lim_sup_min_desp)
count(dias_retraso_max)
##    n
## 1 37
promedio_pasos_retraso <- combined_daily_sleep %>% 
  filter(min_despierto>lim_sup_min_desp) %>% 
  summarize(promedio_pasos_retraso = mean(total_steps))
round(promedio_pasos_retraso)
##   promedio_pasos_retraso
## 1                   9558
lim_sup_min_desp
##  75% 
## 74.5
cuenta <- combined_daily_sleep %>%
  mutate(steps_group = cut(total_steps, breaks = c(0, 5500, 11000, 16500, 22000),
                           labels = c("0-5500", "5500-11000", "11000-16500", "16500-22000"))) %>%
  group_by(steps_group) %>%
  summarize(mayor_al_lim = sum(min_despierto > lim_sup_min_desp))
cuenta <- setNames(cuenta, c("Pasos", "Cantidad de dias"))
cuenta <- cuenta %>% 
  slice(-5)
ggplot(cuenta, aes(x = "", y = `Cantidad de dias`, fill = Pasos)) + 
  geom_col(width = 1) +
  coord_polar(theta = "y") +
  scale_fill_manual(values = c("#B0D1B1", "#47944E", "#24693D", "#C1D5D2")) +
  labs(x = NULL, y = NULL, fill = "Pasos") +
  geom_text(aes(label = `Cantidad de dias`), position = position_stack(vjust = 0.3)) +
  ggtitle("Cantidad de pasos dados en días críticos") +
  theme_void()

Hubieron 37 días en los que alguna persona sobrepasó el limite superior de los minutos de retraso al dormir típicos de la muestra (74,5 minutos). En promedio, la cantidad de pasos dada durante esos dias es de 9558, y en la mayoria de estos dias se caminaron entre 11000 y 16500 pasos.

Por ultimo relacionaremos mediante una grafica los días de la semana (De domingo a lunes) con los minutos de retraso al dormir y los pasos dados.

dormir_pasos_combinado <- mutate(combined_daily_sleep, 
                                        dia = wday(fecha, label = TRUE))
resumen_dormir <- dormir_pasos_combinado %>% 
  group_by(dia) %>% 
  summarise(pasos_diarios_promedio = mean(total_steps),
            min_despierto_promedio = mean(min_despierto))
g1<-  ggplot(data=resumen_dormir, mapping=aes(x=dia,y=min_despierto_promedio))+
  geom_col(fill="#80CBC4")+ labs(title="Cantidad diaria promedio de minutos despierto en la cama",
                                 x="Día",y="Minutos despierto en la cama")
g2 <- ggplot(data=resumen_dormir, mapping=aes(x=dia,y=pasos_diarios_promedio))+
  geom_col(fill="#00796B")+ labs(title="Cantidad diaria promedio de pasos",
                                 x="Día",y="Pasos diarios")
grid.arrange(g1, g2, ncol = 1)

resumen_dormir 
## # A tibble: 7 × 3
##   dia      pasos_diarios_promedio min_despierto_promedio
##   <ord>                     <dbl>                  <dbl>
## 1 "dom\\."                  7298.                   50.8
## 2 "lun\\."                  9273.                   37.8
## 3 "mar\\."                  9183.                   38.8
## 4 "mié\\."                  8023.                   35.3
## 5 "jue\\."                  8184.                   33.6
## 6 "vie\\."                  7901.                   39.6
## 7 "sáb\\."                  9871.                   40.8

El día en el que menos pasos se dan en promedio (7298) es el domingo, coincidentemente, es en el que existe un mayor retraso a la hora de dormir (50,8 minutos)

2.Análisis de datos por hora

Cantidad de pasos vs Hora del dia

Primero se graficará la relación entre la hora del día y la cantidad de pasos dados:

hourly$hora_corta <- substr(hourly$hora24, 1, 5)
ggplot(data=hourly) +
  geom_point(mapping = aes(x = hora_corta, y = step_total), color = "#2F6790") +
  labs(title = "Relación entre la cantidad de pasos y la hora", x = "Hora", y = "Cantidad de pasos") + 
  xlab("Hora del día") + ylab("Cantidad de pasos")+
  theme(axis.text.x = element_text(angle = 45))

Podemos notar que la mayor cantidad de pasos se concentra entre las 08:00hrs. y 19:00hrs. Para un mejor análisis promediaremos los pasos y los relacionaremos a la hora del día en el que se dieron:

pasos_prom_hora <- hourly %>%
  group_by(hora_corta) %>%
  summarize(pasos_prom = mean(step_total))
pasos_prom_hora
## # A tibble: 24 × 2
##    hora_corta pasos_prom
##    <chr>           <dbl>
##  1 00:00           42.2 
##  2 01:00           23.1 
##  3 02:00           17.1 
##  4 03:00            6.43
##  5 04:00           12.7 
##  6 05:00           43.9 
##  7 06:00          179.  
##  8 07:00          306.  
##  9 08:00          428.  
## 10 09:00          433.  
## # … with 14 more rows

Mediante un grafico los datos se aprecian de la siguiente manera:

ggplot(pasos_prom_hora, aes(hora_corta, pasos_prom, group=1)) +
  geom_line(linewidth=0.8) +
  labs(title = "Relación entre la cantidad de pasos promedio y la hora", x = "Hora", y = "Pasos promedio") + 
  xlab("Hora del día") + ylab("Cantidad de pasos promedio")+
  theme(axis.text.x = element_text(angle = 90)) +
  annotate("rect", xmin = "00:00", xmax = "07:00", 
           fill = "orange",ymin = 0, ymax = 700, alpha = .1) +
  annotate("rect", xmin = "07:00", xmax = "13:00", 
           fill = "yellow",ymin = 0, ymax = 700, alpha = .1) +
  annotate("rect", xmin = "13:00", xmax = "19:00", 
           fill = "purple",ymin = 0, ymax = 700, alpha = .1) +
  annotate("rect", xmin = "19:00", xmax = "23:00", 
           fill = "blue",ymin = 0, ymax = 700, alpha = .1) +
  annotate("text", x = 19.5, y = 640, 
           label = "Max≈ 600 pasos", hjust = "center", size = 3)+
  annotate("text", x = 3.5, y = 100, 
           label = "Min≈ 6 pasos", hjust = "center", size = 3)+
  annotate("text", x = 04, y = 740, 
           label = "Madrugada", hjust = "center", size = 4)+
  annotate("text", x = 11, y = 740, 
           label = "Día", hjust = "center", size = 4)+
  annotate("text", x = 17, y = 740, 
           label = "Tarde", hjust = "center", size = 4)+
  annotate("text", x = 22, y = 740, 
           label = "Noche", hjust = "center", size = 4)

pasos_prom_hora %>% 
  filter(pasos_prom == max(pasos_prom))
## # A tibble: 1 × 2
##   hora_corta pasos_prom
##   <chr>           <dbl>
## 1 18:00            599.
pasos_prom_hora %>% 
  filter(pasos_prom == min(pasos_prom))
## # A tibble: 1 × 2
##   hora_corta pasos_prom
##   <chr>           <dbl>
## 1 03:00            6.43

La hora en la que se dan más pasos promedios (599) es a las 6pm, y la donde se dan menos pasos promedio (6) es a las 3AM. El momento del dia durante el cual se dan en promedio mas pasos es la tarde y donde menos se dan es en la madrugada.

Para finalizar el análisis graficaremos la relación entre la cantidad de pasos promedio diarios con el día de la semana

hourly <- hourly %>%
  mutate(momento = case_when(
    hora24 %in% c("00:00:00", "01:00:00", "02:00:00","03:00:00","04:00:00","05:00:00","06:00:00") ~ "Madrugada",
    hora24 %in% c("07:00:00", "08:00:00", "09:00:00","10:00:00","11:00:00","12:00:00") ~ "Dia",
    hora24 %in% c("13:00:00", "14:00:00", "15:00:00","16:00:00","17:00:00","18:00:00") ~ "Tarde",
    hora24 %in% c("19:00:00", "20:00:00", "21:00:00","22:00:00","23:00:00") ~ "Noche",
    TRUE ~ "otros"))
dia <- hourly  %>%
  mutate(fecha,
         dia = wday(fecha, label = TRUE))
promedios <- aggregate(step_total ~ dia + momento, data=dia, FUN=mean)
promedios$momento <- factor(promedios$momento, 
                            levels = c("Noche", "Tarde", "Dia", "Madrugada"), 
                            ordered = TRUE)

ggplot(promedios, aes(x = dia, y = step_total, fill = momento)) +
  geom_bar(stat = "identity", position = "stack") +
  scale_fill_manual(values = c("#325F8C", "#8E6189", "#F4D166","#F6A245"))+
  labs(x = "Día de la semana", y = "Cantidad de pasos", fill = "Momento del día") 

Visualmente podemos notar que la cantidad de pasos en relacion al momento del día se mantiene bastante constante, en todos los dias de la semana el momento en el que menos se camina es en la madrugada, y en el que mas se camina en la tarde.

Conclusiones

  • En general, se encontró una relación negativa entre pasos dados y minutos dormidos.
  • El domingo es el día en el que en promedio se dan menos pasos, y en contraste, el día en el que más retraso tienen los usuarios antes de dormir.
  • El sábado es el día en el que los usuarios dan más pasos.
  • El momento del día en que los usuarios caminan más es en la tarde. La cantidad de pasos que dan por momento del día en cada día de la semana se mantiene proporcionalmente constante.

Recomendaciones

-Promover e informar a los usuarios la importancia del equilibrio entre la actividad física y el descanso. Aunque caminar y mantenerse activo es esencial para la salud, también es fundamental dormir lo suficiente para permitir que el cuerpo se recupere y se repare. Se debe fomentar un enfoque equilibrado para la actividad física y el sueño.

-Se podria promover la actividad física en los domingos, ya que es el día en el que se dan menos pasos. Por ejemplo, podrían crear desafíos o incentivos para animar a los usuarios a moverse más y ver además si esto tiene un impacto positivo en disminuir el mayor retraso al dormir que tuvieron los usuarios en este día.

-Dado que el análisis muestra que los usuarios caminan más en la tarde, se podría incentivar a los usuarios a ser más activos en otros momentos del día. Por ejemplo, podrían ofrecer recordatorios o desafíos para animar a los usuarios a caminar más por la mañana o después de el almuerzo.