1. Resumen de tarea empresarial

Introducción y Contexto empresarial

Bellabeat es una empresa fabricante de productos de alta tecnología orientados a la salud de la mujer. Bellabeat es una empresa pequeña exitosa, pero tiene el potencial para convertirse en un actor más grande en el mercado global de dispositivos inteligentes.

1.1 Hipótesis inicial

Una de las principales cofundadoras de la empresa (Urška Sršen) tiene la hipótesis inicial que si se analizaran datos de la actividad física de los dispositivos inteligentes de podría desplegar nuevas oportunidades de negocio para la empresa.

1.2 Actores

  1. Urška Sršen: confundadora y directora creativa de Bellabeat
  2. Sando Mur: matemático, confundador y ejecutivo de la empresa
  3. Equipo de análisis computacional de datos de marketing de Bellabeat

1.3 Recursos tecnológicos disponibles

  1. App Bellabeat: aplicación que ayuda a los usuarios a comprender sus hábitos actuales para tomar decisiones salusables, esto se logra con la recopilación de datos sobre Actividad física, sueño,estrés,ciclo menstrual, hábitos de conciencia.Esta app está conectada a los gadgets.

  2. Leaf: gadget (pulsera,collar,clip) conectada a la app de bellabeat para recopilar datos sobre Actividad física, sueño, estrés.

  3. Time: smartwatch con el mismo propósito.

  4. Spring: botella de agua que recopila datos de que tanta agua se toma en el día para recopilar datos sobre tu hidratación.

  5. Membresía bellabeat: Acceso 24/7 sobre orientación personalizada sobre temas de nutrición, actividad física, sueño, salud, bellaza y mindfullnes.

1.4 Tarea Empresarial

CONSIGNA:

Analizar el uso de gadgets de usuarios que NO son de bellabeats para aplicar este conocimiento en la empresa y finalmente presentarlo.

Puntos clave:
    
    1. Encontrar la tendencias de uso de los gadgets de los usuarios de otras aplicaciones.
    
    2. Buscar la manera de usar estas tendencias para los usuarios de Bellabeat.
    
    3. Lograr que estas tendencias ayuden a influir en la estrategia de marketing de bellabeat

2. Preparación de datos

Justificación de uso del dataset

Primeramente se usarán datos públicos que exploren los hábitos cotidianos de los usuarios de dispositivos inteligentes, estos datos serán sacados de Kaggle, más específicamente del dataset FitBit Fitness Tracker Data.

Este conjunto de datos de Kaggle contiene el seguimiento de la actividad física personal en treinta usuarios de Fitbit. Treinta usuarios elegibles de Fitbit prestaron su consentimiento para el envío de datos personales de seguimiento que incluyen rendimiento de la actividad física en minutos, ritmo cardíaco y monitoreo del sueño. Incluye información sobre la actividad diaria, pasos y ritmo cardíaco que se puede usar para explorar los hábitos de los usuarios.

Del Dataset original, usaremos solamente las Base de datos que a primera vista parezcan que puedan ayudarnos a resolver nuestra tarea empresarial, los cuales son:

  1. dailyActivity_merged.csv para analizar el registro de actividad diaria

  2. hourlyCalories_merged.csv para observar cuál es momento del día donde se queman más calorias y podría estar relacionado con la actividad diaria.

  3. hourlyIntensities_merged.csv para observar cuál es momento del día donde el cuerpo tiene la mayor intensidad en sus movimientos, lo que podría estar relacionado con los puntos anteriores.

  4. sleepDay_merged.csv para analizar hábitos de sueño.

  5. weightLogInfo_merged.csv para analizar el seguimiento de peso de los usuarios.

Cargando las paqueterías para análisis de datos

library(ggplot2)
library(tidyr)
library(readr)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(skimr)
library(here)
## here() starts at /home/fabian/R/proyectos/analisis-bellabeat
library(janitor)
## 
## Attaching package: 'janitor'
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union

Cargando las bases de datos correspondiantes

setwd("/home/fabian/R/proyectos/analisis-bellabeat/datasets")
act_diaria <- read.csv("dailyActivity_merged.csv")
calorias <- read.csv("hourlyCalories_merged.csv")
intensidad <- read.csv("hourlyIntensities_merged.csv")
tiempo_sueno <- read.csv ("sleepDay_merged.csv")
track_peso <- read.csv("weightLogInfo_merged.csv")

2.1 Pre-exploración de datos

Lo primero que haremos es visualizar el panorama general de los marcos de datos con los que estamos trabajando, los ordenaremos y filtraremos con el propósito de obtener un subconjunto de datos más manejable para nuestro análisis. Más adelante transforaremos datos para garantizar la integridad de los datos y proceder con el análisis.

glimpse(act_diaria)
## Rows: 940
## Columns: 15
## $ Id                       <dbl> 1503960366, 1503960366, 1503960366, 150396036…
## $ ActivityDate             <chr> "4/12/2016", "4/13/2016", "4/14/2016", "4/15/…
## $ TotalSteps               <int> 13162, 10735, 10460, 9762, 12669, 9705, 13019…
## $ TotalDistance            <dbl> 8.50, 6.97, 6.74, 6.28, 8.16, 6.48, 8.59, 9.8…
## $ TrackerDistance          <dbl> 8.50, 6.97, 6.74, 6.28, 8.16, 6.48, 8.59, 9.8…
## $ LoggedActivitiesDistance <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ VeryActiveDistance       <dbl> 1.88, 1.57, 2.44, 2.14, 2.71, 3.19, 3.25, 3.5…
## $ ModeratelyActiveDistance <dbl> 0.55, 0.69, 0.40, 1.26, 0.41, 0.78, 0.64, 1.3…
## $ LightActiveDistance      <dbl> 6.06, 4.71, 3.91, 2.83, 5.04, 2.51, 4.71, 5.0…
## $ SedentaryActiveDistance  <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ VeryActiveMinutes        <int> 25, 21, 30, 29, 36, 38, 42, 50, 28, 19, 66, 4…
## $ FairlyActiveMinutes      <int> 13, 19, 11, 34, 10, 20, 16, 31, 12, 8, 27, 21…
## $ LightlyActiveMinutes     <int> 328, 217, 181, 209, 221, 164, 233, 264, 205, …
## $ SedentaryMinutes         <int> 728, 776, 1218, 726, 773, 539, 1149, 775, 818…
## $ Calories                 <int> 1985, 1797, 1776, 1745, 1863, 1728, 1921, 203…
Sub_act_diaria <- act_diaria %>%
  mutate(day = mdy(ActivityDate)) %>%
  arrange(-Id,ActivityDate) %>%
  filter(TotalSteps != 0) %>%
  select(-LoggedActivitiesDistance)
head(Sub_act_diaria,50)
glimpse(calorias)
## Rows: 22,099
## Columns: 3
## $ Id           <dbl> 1503960366, 1503960366, 1503960366, 1503960366, 150396036…
## $ ActivityHour <chr> "4/12/2016 12:00:00 AM", "4/12/2016 1:00:00 AM", "4/12/20…
## $ Calories     <int> 81, 61, 59, 47, 48, 48, 48, 47, 68, 141, 99, 76, 73, 66, …
sub_calorias <- calorias %>%
  mutate(ActivityHour = mdy_hms(ActivityHour, tz = "UTC")) %>%
  mutate(hour = hour(ActivityHour)) %>%
  group_by(Id) %>%
  mutate(total_calories_per_month = sum(Calories), avg_month = mean(Calories), max_cal_burn = max(Calories), min_cal_burn = min(Calories))
head(sub_calorias)
sub_intensidad <- intensidad %>%
  mutate(ActivityHour = mdy_hms(ActivityHour, tz = "UTC"))
head(sub_intensidad)
sub_tiempo_sueno <- tiempo_sueno %>%
  mutate(day = mdy_hms(SleepDay, tz = "UTC")) %>%
  arrange(Id) %>%
  mutate(Difsueno_min = TotalTimeInBed - TotalMinutesAsleep, TotalMinutesAsleepHr = TotalMinutesAsleep/60, TotalTimeInBedHr = TotalTimeInBed/60)
head(sub_tiempo_sueno,150)
sub_track_peso <- track_peso %>%
  mutate(IsManualReport = as.logical(toupper(IsManualReport))) %>%
  mutate(Date = mdy_hms(Date, tz = "UTC")) %>%
  arrange(Id) %>%
  select(-Fat,-LogId)
head(sub_track_peso)

Con esto finalizamos la preparación de datos. La siguiente fase se tratará de garantizar que los datos esten limpios, integros y listos para analizar.

3. Limpieza de datos

Tareas específicas a realizar en nuestra limpieza:

1. Verificar si hay errores en los datos.
2. Transformar los datos para trabajar con ellos eficazmente.
3. Documentación de todas las limpiezas y manipulaciones de datos
#para Actividad diaria
act_diaria_limp <- Sub_act_diaria %>%
  rename_with(tolower) %>%
  clean_names() %>%
  mutate(distanciatotal = veryactivedistance +  moderatelyactivedistance + lightactivedistance +sedentaryactivedistance, comparar = distanciatotal == totaldistance, error_absoluto = abs(totaldistance - distanciatotal), minutosactivos = veryactiveminutes + fairlyactiveminutes + lightlyactiveminutes + sedentaryminutes)
#Error Absoluto Promedio
mae <- mean(act_diaria_limp$error_absoluto)
print(mae)
## [1] 0.08564317
head(act_diaria_limp,200)
 #%>%
  #filter(comparar == TRUE)
conteo_errores <- act_diaria_limp %>%
  summarise(conteo_errores = sum(comparar == FALSE))
show(conteo_errores)
##   conteo_errores
## 1            636

Haré una pequeña pausa para explicar lo que está ocurriendo en la limpieza de la Actividad física diaria.

#calorias
calorias_limp <- sub_calorias %>%
  rename_with(tolower) %>%
  clean_names() %>%
  rename(calories_per_hour = calories) %>%
  mutate (cal_per_day = total_calories_per_month/31)
head(calorias_limp)
#Intensidad
intensidad_limp <- sub_intensidad %>%
  rename_with(tolower) %>%
  clean_names() 

#Sueno
 tiempo_sueno_limp <- sub_tiempo_sueno  %>%
  rename_with(tolower) %>%
  clean_names()
 #peso
track_peso_limp <- sub_track_peso %>%
  rename_with(tolower) %>%
  clean_names()

4. Análisis de datos

Ahora que los datos están almacenados adecuadamente y listos para el análisis, empiezaremos a ponerlos en funcionamiento.

Tareas específicas a realizar en nuestro análisis:

1. Realiza cálculos.
2. Identifica tendencias y relaciones, así como insights de alto valor.
3. Logra que estos conocimientos para respondan a la pregunta empresarial.
#actividad diaria
act_diaria_limp %>%
  select(-id,-activitydate, -trackerdistance,-distanciatotal,-comparar,-error_absoluto) %>%
  summary()
##    totalsteps    totaldistance   veryactivedistance moderatelyactivedistance
##  Min.   :    4   Min.   : 0.00   Min.   : 0.000     Min.   :0.0000          
##  1st Qu.: 4923   1st Qu.: 3.37   1st Qu.: 0.000     1st Qu.:0.0000          
##  Median : 8053   Median : 5.59   Median : 0.410     Median :0.3100          
##  Mean   : 8319   Mean   : 5.98   Mean   : 1.637     Mean   :0.6182          
##  3rd Qu.:11092   3rd Qu.: 7.90   3rd Qu.: 2.275     3rd Qu.:0.8650          
##  Max.   :36019   Max.   :28.03   Max.   :21.920     Max.   :6.4800          
##  lightactivedistance sedentaryactivedistance veryactiveminutes
##  Min.   : 0.000      Min.   :0.00000         Min.   :  0.00   
##  1st Qu.: 2.345      1st Qu.:0.00000         1st Qu.:  0.00   
##  Median : 3.580      Median :0.00000         Median :  7.00   
##  Mean   : 3.639      Mean   :0.00175         Mean   : 23.02   
##  3rd Qu.: 4.895      3rd Qu.:0.00000         3rd Qu.: 35.00   
##  Max.   :10.710      Max.   :0.11000         Max.   :210.00   
##  fairlyactiveminutes lightlyactiveminutes sedentaryminutes    calories   
##  Min.   :  0.00      Min.   :  0.0        Min.   :   0.0   Min.   :  52  
##  1st Qu.:  0.00      1st Qu.:146.5        1st Qu.: 721.5   1st Qu.:1856  
##  Median :  8.00      Median :208.0        Median :1021.0   Median :2220  
##  Mean   : 14.78      Mean   :210.0        Mean   : 955.8   Mean   :2361  
##  3rd Qu.: 21.00      3rd Qu.:272.0        3rd Qu.:1189.0   3rd Qu.:2832  
##  Max.   :143.00      Max.   :518.0        Max.   :1440.0   Max.   :4900  
##       day             minutosactivos  
##  Min.   :2016-04-12   Min.   :   2.0  
##  1st Qu.:2016-04-18   1st Qu.: 983.5  
##  Median :2016-04-26   Median :1353.0  
##  Mean   :2016-04-26   Mean   :1203.6  
##  3rd Qu.:2016-05-03   3rd Qu.:1440.0  
##  Max.   :2016-05-12   Max.   :1440.0
#calorias
calorias_limp %>%
  summary()
##        id             activityhour                    calories_per_hour
##  Min.   :1.504e+09   Min.   :2016-04-12 00:00:00.00   Min.   : 42.00   
##  1st Qu.:2.320e+09   1st Qu.:2016-04-19 01:00:00.00   1st Qu.: 63.00   
##  Median :4.445e+09   Median :2016-04-26 06:00:00.00   Median : 83.00   
##  Mean   :4.848e+09   Mean   :2016-04-26 11:46:42.58   Mean   : 97.39   
##  3rd Qu.:6.962e+09   3rd Qu.:2016-05-03 19:00:00.00   3rd Qu.:108.00   
##  Max.   :8.878e+09   Max.   :2016-05-12 15:00:00.00   Max.   :948.00   
##       hour       total_calories_per_month   avg_month       max_cal_burn  
##  Min.   : 0.00   Min.   :  7849           Min.   : 62.47   Min.   :161.0  
##  1st Qu.: 5.00   1st Qu.: 55551           1st Qu.: 80.24   1st Qu.:279.0  
##  Median :11.00   Median : 63046           Median : 91.50   Median :386.0  
##  Mean   :11.42   Mean   : 68079           Mean   : 97.39   Mean   :419.6  
##  3rd Qu.:17.00   3rd Qu.: 79402           3rd Qu.:113.35   3rd Qu.:531.0  
##  Max.   :23.00   Max.   :106427           Max.   :144.80   Max.   :948.0  
##   min_cal_burn    cal_per_day    
##  Min.   :42.00   Min.   : 253.2  
##  1st Qu.:55.00   1st Qu.:1792.0  
##  Median :65.00   Median :2033.7  
##  Mean   :66.35   Mean   :2196.1  
##  3rd Qu.:78.00   3rd Qu.:2561.4  
##  Max.   :90.00   Max.   :3433.1

Revisando el comportamiento de las calorías durante las horas del día

sub_calorias_horas <- calorias %>%
  mutate(ActivityHour = mdy_hms(ActivityHour, tz = "UTC")) %>%
  mutate(hour = hour(ActivityHour)) 

resumen <- sub_calorias_horas %>%
  group_by(hour) %>%
  summarise(promedio_calorias = mean(Calories, na.rm = TRUE))
ggplot(data = resumen, aes(x = hour, y = promedio_calorias)) + 
  geom_col(stat = "identity", fill = 'darkblue') + 
  theme(axis.text.x = element_text(angle = 90)) +
  labs(title = "Promedio de Calorías Quemadas por Hora",
       x = "Hora del Día",
       y = "Calorías Quemadas")
## Warning in geom_col(stat = "identity", fill = "darkblue"): Ignoring unknown
## parameters: `stat`

  • Al agrupar nuestro conjunto de datos en términos de las horas del día podemos observar que los usuarios queman más calorías entre las 17:00 a 19:00
intensidad_horas <- intensidad_limp %>%
  mutate(hour = hour(activityhour))

resumen_int <- intensidad_horas %>%
  group_by(hour)
head(resumen_int,150)
ggplot(data = resumen_int, aes(x = hour, y = averageintensity)) + 
  geom_col(stat = "identity", fill = 'darkblue') + 
  theme(axis.text.x = element_text(angle = 90)) +
  labs(title = "Promedio de intensidad por Hora",
       x = "Hora del Día",
       y = "Promedio de intensidad")
## Warning in geom_col(stat = "identity", fill = "darkblue"): Ignoring unknown
## parameters: `stat`

  • En este gráfico podemos observar como los promedios de intensidad de actividad física están relacionados con las horas del día en las que los usuarios queman más calorías.

  • El siguiente paso para la visualización de nuestros datos será fusionar las variables en un único marco de datos para entender mejor como es que ambas variables están relacionadas con ayuda de un gráfico de dispersión.

track_peso_limp %>%
  select(-id,-date,-ismanualreport ) %>%
  summary()
##     weightkg       weightpounds        bmi       
##  Min.   : 52.60   Min.   :116.0   Min.   :21.45  
##  1st Qu.: 61.40   1st Qu.:135.4   1st Qu.:23.96  
##  Median : 62.50   Median :137.8   Median :24.39  
##  Mean   : 72.04   Mean   :158.8   Mean   :25.19  
##  3rd Qu.: 85.05   3rd Qu.:187.5   3rd Qu.:25.56  
##  Max.   :133.50   Max.   :294.3   Max.   :47.54
graf <- track_peso_limp %>%
  select(-date,-ismanualreport) %>%
  group_by(bmi)

ggplot(graf, mapping = aes(x = bmi)) +
  geom_histogram( fill = "blue", color = "black") +
  labs(title = "Distribución del IMC de los usuarios",
       x = "IMC",
       y = "Frecuencia") +
  theme_minimal()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

  • Algunas conclusiones clave que podemos obtener de este marco de datos para entender mejor a nuestra población es que según la Clasificación de índice de masa corporal ofrecida por el gobierno de México el promedio del índice de masa corporal de nuestra población es de 25.19, lo cuál indica que existe un ligero sobre peso por parte de nuestra población.

  • Cabe resalta que como IMC máximo tenemos datos de 47.54, lo cuál se considera obesidad mórbida según la clasificación en la que nos estamos basando y como IMC mínimo es de 21.45, lo cuál cae en la categría de IMC ideal.

tiempo_sueno_limp %>%
  select(-id,-sleepday)
summary(tiempo_sueno_limp)
##        id              sleepday         totalsleeprecords totalminutesasleep
##  Min.   :1.504e+09   Length:413         Min.   :1.000     Min.   : 58.0     
##  1st Qu.:3.977e+09   Class :character   1st Qu.:1.000     1st Qu.:361.0     
##  Median :4.703e+09   Mode  :character   Median :1.000     Median :433.0     
##  Mean   :5.001e+09                      Mean   :1.119     Mean   :419.5     
##  3rd Qu.:6.962e+09                      3rd Qu.:1.000     3rd Qu.:490.0     
##  Max.   :8.792e+09                      Max.   :3.000     Max.   :796.0     
##  totaltimeinbed       day                          difsueno_min   
##  Min.   : 61.0   Min.   :2016-04-12 00:00:00.00   Min.   :  0.00  
##  1st Qu.:403.0   1st Qu.:2016-04-19 00:00:00.00   1st Qu.: 17.00  
##  Median :463.0   Median :2016-04-27 00:00:00.00   Median : 25.00  
##  Mean   :458.6   Mean   :2016-04-26 12:40:05.80   Mean   : 39.17  
##  3rd Qu.:526.0   3rd Qu.:2016-05-04 00:00:00.00   3rd Qu.: 40.00  
##  Max.   :961.0   Max.   :2016-05-12 00:00:00.00   Max.   :371.00  
##  totalminutesasleephr totaltimeinbedhr
##  Min.   : 0.9667      Min.   : 1.017  
##  1st Qu.: 6.0167      1st Qu.: 6.717  
##  Median : 7.2167      Median : 7.717  
##  Mean   : 6.9911      Mean   : 7.644  
##  3rd Qu.: 8.1667      3rd Qu.: 8.767  
##  Max.   :13.2667      Max.   :16.017
ggplot(data = tiempo_sueno_limp, mapping = aes( x = totaltimeinbedhr)) + geom_bar(color = "blue" , size = 1) 
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

  • Podemos observar que la gran mayoría de las personas solamente duerme una vez en un lapso de 24 horas.

  • La horas de sueño promedio que las personas invierten en su descanso es e 419.5 minutos (6.98 horas), de las cuales pasan en 458.6 minutos (7.64 horas) en promedio acostadas en cama y tardan también en promedio 39.17 minutos en conciliar el sueño.

  • Con la gráfica podemos observar rápidamente que el tiempo que pasa en cama sigue una distribución normal en dónde la media es 7.64 horas.

4.1 Fusionando datos

Antes de comenzar con las visualizaciones finales de datos, necesito fusionar dos data sets, los cuales son act_limp y tiempo_sueno_limp por medio de los vectores id y fecha.

merged_data <- merge(tiempo_sueno_limp, act_diaria_limp, by=c('id', 'day'))
head(merged_data)

5. Visualizaciones

Una vez completado el análisis, crearemos algunas visualizaciones de datos. Las visualizaciones deben comunicar claramente las conclusiones y recomendaciones de alto nivel junto con los hallazgos clave.

ggplot(data=merged_data, aes(x=totalminutesasleep, y=sedentaryminutes)) + 
geom_point(color='darkblue') + geom_smooth() +
  labs(title="Minutos durmiendo vs. Minutos sedentarios")
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

ggplot(data= act_diaria_limp, aes(x=totalsteps, y=calories)) + 
  geom_point() + geom_smooth() + labs(title="Pasos totales vs. calorias")
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

6. Recomensaciones empresariales

Ahora que terminamos de crear las visualizaciones, podemos actuar en función de los hallazgos. Estas son las conclusiones de alto nivel más importantes basadas en el análisis:

Tras analizar los datos del Fitbit Fitness Tracker, encontré algunos insights clave que podrían influir en la estrategia de marketing de Bellabeat:

  1. Público objetivo:
  1. Mensaje Clave para la Campaña Online de Bellabeat La aplicación de Bellabeat no es solo otra app de fitness. Es una guía que ayuda a las mujeres a equilibrar su vida personal y profesional con hábitos saludables. A través de recomendaciones diarias, la app educa y motiva a sus usuarias para mejorar su bienestar.

  2. Ideas para Mejorar la App de Bellabeat

7. Agradecimientos.

Agradezco el tiempo y la disposición de leer completo mi primer análisis de datos. Este es un caso práctico propuesto por la última fase del curso de Análisis de datos de Google impartido por Coursera.