Scenario

Since its founding in 2013, Bellabeat has rapidly grown into a tech-driven wellness company for women. The company offers five key products: Bellabeat App, Leaf, Time, Spring, and Bellabeat Membership. Bellabeat is a successful small company with the potential to become a significant player in the global smart device market. I have been tasked with analyzing smart device data to gain insights into consumer usage patterns. These insights will guide Bellabeat’s marketing strategy and help optimize product offerings to better serve the target audience.

Ask

Buisness Task:

Analyze Fitbit data to gain insight and help guide marketing strategy for Bellabeat to grow.

Questions for Analysis

The following three points are the questions needed to be answered by this analysis.

  1. What are some trends in smart device usage?

  2. How could these trends apply to Bellabeat customers?

  3. How could these trends help influence Bellabeat marketing strategy?

Stakeholders

Prepare

Data source used for case study is FitBit Fitness Tracker Data available from Kaggle. This dataset includes personal fitness tracker data from thirty Fitbit users, which tracks minute-level physical activity, heart rate, and sleep monitoring.

Data Credibility

Only 30 user data is available. This is not an accurate representation of the entire population but meets the central limit theorem general rule of n≥30. Therefore, the sample size is sufficient for analysis.

Importing Data Sets and Libraries

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2)
library(dplyr)
library(janitor)
## 
## Attaching package: 'janitor'
## 
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
library(lubridate)
library(tidyr)
library(readr)

Data Sets

The original data sets provided contain 18 CSV files, but I will only be using two of them: dailyActivty_Merged and sleepDay_merged. I will also be renaming the CSV files so they are easier to work with. “dailyActivity_merged has a majority of data we can use to perform the analysis: calories, total, step and the active minutes.

library(readr)
dailyActivity <- read_csv("dailyActivity.csv")
## Rows: 940 Columns: 15
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (1): ActivityDate
## dbl (14): Id, TotalSteps, TotalDistance, TrackerDistance, LoggedActivitiesDi...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
library(readr)
sleepDay <- read_csv("sleepDay.csv")
## Rows: 413 Columns: 5
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): SleepDay
## dbl (4): Id, TotalSleepRecords, TotalMinutesAsleep, TotalTimeInBed
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(dailyActivity)
## # A tibble: 6 × 15
##           Id ActivityDate TotalSteps TotalDistance TrackerDistance
##        <dbl> <chr>             <dbl>         <dbl>           <dbl>
## 1 1503960366 4/12/2016         13162          8.5             8.5 
## 2 1503960366 4/13/2016         10735          6.97            6.97
## 3 1503960366 4/14/2016         10460          6.74            6.74
## 4 1503960366 4/15/2016          9762          6.28            6.28
## 5 1503960366 4/16/2016         12669          8.16            8.16
## 6 1503960366 4/17/2016          9705          6.48            6.48
## # ℹ 10 more variables: LoggedActivitiesDistance <dbl>,
## #   VeryActiveDistance <dbl>, ModeratelyActiveDistance <dbl>,
## #   LightActiveDistance <dbl>, SedentaryActiveDistance <dbl>,
## #   VeryActiveMinutes <dbl>, FairlyActiveMinutes <dbl>,
## #   LightlyActiveMinutes <dbl>, SedentaryMinutes <dbl>, Calories <dbl>
head(sleepDay)
## # A tibble: 6 × 5
##           Id SleepDay        TotalSleepRecords TotalMinutesAsleep TotalTimeInBed
##        <dbl> <chr>                       <dbl>              <dbl>          <dbl>
## 1 1503960366 4/12/2016 12:0…                 1                327            346
## 2 1503960366 4/13/2016 12:0…                 2                384            407
## 3 1503960366 4/15/2016 12:0…                 1                412            442
## 4 1503960366 4/16/2016 12:0…                 2                340            367
## 5 1503960366 4/17/2016 12:0…                 1                700            712
## 6 1503960366 4/19/2016 12:0…                 1                304            320

Process

Next, checked for duplicate entries and ensured data cleanliness

Checking for Unique Id’s

n_distinct(dailyActivity$Id)
## [1] 33
n_distinct(sleepDay$Id)
## [1] 24

Identify and remove duplicates

sum(duplicated(dailyActivity))
## [1] 0
sum(duplicated(sleepDay))
## [1] 3
sleepDay <- sleepDay %>%
  distinct() %>%
  drop_na()

Confirm that duplicates have been removed

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

Cleaning

Cleaned the column names for consistency

clean_names(dailyActivity)
## # A tibble: 940 × 15
##            id activity_date total_steps total_distance tracker_distance
##         <dbl> <chr>               <dbl>          <dbl>            <dbl>
##  1 1503960366 4/12/2016           13162           8.5              8.5 
##  2 1503960366 4/13/2016           10735           6.97             6.97
##  3 1503960366 4/14/2016           10460           6.74             6.74
##  4 1503960366 4/15/2016            9762           6.28             6.28
##  5 1503960366 4/16/2016           12669           8.16             8.16
##  6 1503960366 4/17/2016            9705           6.48             6.48
##  7 1503960366 4/18/2016           13019           8.59             8.59
##  8 1503960366 4/19/2016           15506           9.88             9.88
##  9 1503960366 4/20/2016           10544           6.68             6.68
## 10 1503960366 4/21/2016            9819           6.34             6.34
## # ℹ 930 more rows
## # ℹ 10 more variables: logged_activities_distance <dbl>,
## #   very_active_distance <dbl>, moderately_active_distance <dbl>,
## #   light_active_distance <dbl>, sedentary_active_distance <dbl>,
## #   very_active_minutes <dbl>, fairly_active_minutes <dbl>,
## #   lightly_active_minutes <dbl>, sedentary_minutes <dbl>, calories <dbl>
clean_names(sleepDay)
## # A tibble: 410 × 5
##          id sleep_day total_sleep_records total_minutes_asleep total_time_in_bed
##       <dbl> <chr>                   <dbl>                <dbl>             <dbl>
##  1   1.50e9 4/12/201…                   1                  327               346
##  2   1.50e9 4/13/201…                   2                  384               407
##  3   1.50e9 4/15/201…                   1                  412               442
##  4   1.50e9 4/16/201…                   2                  340               367
##  5   1.50e9 4/17/201…                   1                  700               712
##  6   1.50e9 4/19/201…                   1                  304               320
##  7   1.50e9 4/20/201…                   1                  360               377
##  8   1.50e9 4/21/201…                   1                  325               364
##  9   1.50e9 4/23/201…                   1                  361               384
## 10   1.50e9 4/24/201…                   1                  430               449
## # ℹ 400 more rows

Data Format

Converted the date formats for proper analysis

str(dailyActivity)
## spc_tbl_ [940 × 15] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ Id                      : num [1:940] 1.5e+09 1.5e+09 1.5e+09 1.5e+09 1.5e+09 ...
##  $ ActivityDate            : chr [1:940] "4/12/2016" "4/13/2016" "4/14/2016" "4/15/2016" ...
##  $ TotalSteps              : num [1:940] 13162 10735 10460 9762 12669 ...
##  $ TotalDistance           : num [1:940] 8.5 6.97 6.74 6.28 8.16 ...
##  $ TrackerDistance         : num [1:940] 8.5 6.97 6.74 6.28 8.16 ...
##  $ LoggedActivitiesDistance: num [1:940] 0 0 0 0 0 0 0 0 0 0 ...
##  $ VeryActiveDistance      : num [1:940] 1.88 1.57 2.44 2.14 2.71 ...
##  $ ModeratelyActiveDistance: num [1:940] 0.55 0.69 0.4 1.26 0.41 ...
##  $ LightActiveDistance     : num [1:940] 6.06 4.71 3.91 2.83 5.04 ...
##  $ SedentaryActiveDistance : num [1:940] 0 0 0 0 0 0 0 0 0 0 ...
##  $ VeryActiveMinutes       : num [1:940] 25 21 30 29 36 38 42 50 28 19 ...
##  $ FairlyActiveMinutes     : num [1:940] 13 19 11 34 10 20 16 31 12 8 ...
##  $ LightlyActiveMinutes    : num [1:940] 328 217 181 209 221 164 233 264 205 211 ...
##  $ SedentaryMinutes        : num [1:940] 728 776 1218 726 773 ...
##  $ Calories                : num [1:940] 1985 1797 1776 1745 1863 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   Id = col_double(),
##   ..   ActivityDate = col_character(),
##   ..   TotalSteps = col_double(),
##   ..   TotalDistance = col_double(),
##   ..   TrackerDistance = col_double(),
##   ..   LoggedActivitiesDistance = col_double(),
##   ..   VeryActiveDistance = col_double(),
##   ..   ModeratelyActiveDistance = col_double(),
##   ..   LightActiveDistance = col_double(),
##   ..   SedentaryActiveDistance = col_double(),
##   ..   VeryActiveMinutes = col_double(),
##   ..   FairlyActiveMinutes = col_double(),
##   ..   LightlyActiveMinutes = col_double(),
##   ..   SedentaryMinutes = col_double(),
##   ..   Calories = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>
str(sleepDay)
## 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 ...
##  $ SleepDay          : 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" ...
##  $ TotalSleepRecords : num [1:410] 1 2 1 2 1 1 1 1 1 1 ...
##  $ TotalMinutesAsleep: num [1:410] 327 384 412 340 700 304 360 325 361 430 ...
##  $ TotalTimeInBed    : num [1:410] 346 407 442 367 712 320 377 364 384 449 ...

Converting ActivityDate and SleepDay to date format is a crucial step for accurate data manipulation and analysis.

dailyActivity <- dailyActivity %>%
  rename(Date = ActivityDate) %>%
  mutate(Date = as.Date(Date, format = "%m/%d/%Y"))
sleepDay <- sleepDay %>%
rename(Date = SleepDay) %>%
mutate(Date = as.POSIXct(Date,format ="%m/%d/%Y %I:%M:%S %p",tz=Sys.timezone()))

Analyze

Summarized key aspects of the data to understand the general patterns

dailyActivity %>%
  select(TotalSteps, TotalDistance, Calories) %>%
  summary()
##    TotalSteps    TotalDistance       Calories   
##  Min.   :    0   Min.   : 0.000   Min.   :   0  
##  1st Qu.: 3790   1st Qu.: 2.620   1st Qu.:1828  
##  Median : 7406   Median : 5.245   Median :2134  
##  Mean   : 7638   Mean   : 5.490   Mean   :2304  
##  3rd Qu.:10727   3rd Qu.: 7.713   3rd Qu.:2793  
##  Max.   :36019   Max.   :28.030   Max.   :4900

Summary of Daily Activity and Sleep Data

  • Average steps per day: 7,638

  • Average calories burned per day: 2,304

The CDC recommends an average of 10,000 steps per day. However, recent studies indicate that there are still benefits to walking fewer than 10,000 steps per day.

sleepDay %>%
  select(TotalSleepRecords, TotalTimeInBed, TotalMinutesAsleep) %>%
  summary()
##  TotalSleepRecords TotalTimeInBed  TotalMinutesAsleep
##  Min.   :1.00      Min.   : 61.0   Min.   : 58.0     
##  1st Qu.:1.00      1st Qu.:403.8   1st Qu.:361.0     
##  Median :1.00      Median :463.0   Median :432.5     
##  Mean   :1.12      Mean   :458.5   Mean   :419.2     
##  3rd Qu.:1.00      3rd Qu.:526.0   3rd Qu.:490.0     
##  Max.   :3.00      Max.   :961.0   Max.   :796.0

####Summary of Sleep Data

  • Average time in bed: 7.6 hours

  • Average sleep duration: 7 hours (rounded)

The CDC recommends 7 or more hours of sleep on average per night

dailyActivity %>%
  select(VeryActiveMinutes,LightlyActiveMinutes,FairlyActiveMinutes,SedentaryActiveDistance) %>%
  summary()
##  VeryActiveMinutes LightlyActiveMinutes FairlyActiveMinutes
##  Min.   :  0.00    Min.   :  0.0        Min.   :  0.00     
##  1st Qu.:  0.00    1st Qu.:127.0        1st Qu.:  0.00     
##  Median :  4.00    Median :199.0        Median :  6.00     
##  Mean   : 21.16    Mean   :192.8        Mean   : 13.56     
##  3rd Qu.: 32.00    3rd Qu.:264.0        3rd Qu.: 19.00     
##  Max.   :210.00    Max.   :518.0        Max.   :143.00     
##  SedentaryActiveDistance
##  Min.   :0.000000       
##  1st Qu.:0.000000       
##  Median :0.000000       
##  Mean   :0.001606       
##  3rd Qu.:0.000000       
##  Max.   :0.110000

Activity Levels Breakdown

Our users’ activity levels can be categorized into four groups:

  • Very active average: 21.26 minutes

  • Fairly active average: 13.56 minutes

  • Lightly active average: 192.8 minutes

  • Sedentary average: 991.2 minutes

Observations

Light Activity: Users spend the majority of their “active time” on light activities such as light walking or housework. Sedentary Time: Users spend a significant portion of their day (approximately 16.5 hours) being sedentary.

Implications

  • Inactive Time: After subtracting an average of 7 hours of sleep, users spend around 9.5 hours inactive. This prolonged inactivity can increase the risk of cardiovascular disease and cancer (Mayo Clinic).

  • To mitigate the risks associated with prolonged inactivity, we can implement friendly reminders throughout the day. These reminders can encourage users to stand up or engage in light activity for 5 minutes.

Merging Data

To analyze the relationship between activity and sleep data, I merged the datasets and I then created visualizations.

merged_data <- merge(dailyActivity,sleepDay, by=c("Id", "Date"), all=TRUE)

Share

Total Minutes Asleep vs Total Time in Bed

ggplot(data = sleepDay, aes(x = TotalMinutesAsleep, y = TotalTimeInBed)) + 
  geom_line(color = "blue", linewidth = 1) +
  geom_point(color = "red", size = 3) + 
  labs(title = "Total Time Asleep vs Total Time in Bed",
       x = "Total Minutes Asleep",
       y = "Total Time in Bed (minutes)")

Insights on Sleep Patterns

We observe that a significant number of users spend more time awake in bed than sleeping. On average, users get 7 hours of sleep per night, which aligns with the CDC’s recommendation of 7 or more hours of sleep.

Recommendations

To enhance the quality of sleep, the app can:

1.Set a Sleep Schedule: Encourage users to establish a consistent sleep schedule.

2.Wind Down Notifications: Send reminders to users to start winding down and turn off electronics 30 minutes before bedtime. This can help improve sleep quality (Sleep Foundation).

Total Steps vs. Calories

ggplot(dailyActivity, aes(x = TotalSteps, y = Calories)) +
  geom_point(color = "blue") +
  geom_smooth(color = "red") +
  labs(title = "Total Steps vs. Calories") 
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

There is a positive correlation between the amount of steps taken and the calories burned, indicating that increased movement results in more calories burned.

To promote activity, we can encourage users to take 5-10 minute breaks throughout the day for activities like walking, jogging in place, jumping jacks, or yoga.

Average Minutes per Activity Level

averages <- data.frame(
      dailyActivity = c("Very Active", "Fairly Active", "Lightly Active", "Sedentary"),
      AverageMinutes = c(21.2, 13.6, 193, 991))
ggplot(data = averages, aes(x = reorder(dailyActivity, AverageMinutes), y = AverageMinutes)) +
  geom_col(fill = c("VeryActive" = "red", "FairlyActive" = "orange", "LightlyActive" = "yellow", "Sedentary" = "blue")) +
  labs(title = "Average Minutes per Activity Level",
       x = "Activity Level",
       y = "Average Minutes")

majority of users spend time on light activity or none at all (sedentary).

Act

Insights and Recommendations

Based on the analysis, I identified several trends in smart device usage:

1.Users who are more active tend to burn more calories, which suggests that promoting features that encourage higher activity levels could be beneficial.

2.There is a significant relationship between total minutes asleep and total time in bed, indicating that users who spend more time in bed generally get more sleep.

3.The majority of users spend a substantial amount of time in sedentary activities, which could be a focus for marketing strategies promoting active lifestyles and Bellabeat products.

To promote healthier sleep habits, I recommend enabling users to create a sleep schedule through the app and sending “Bedtime Reminders” that encourage winding down and turning off electronics before bed.

Additionally, to increase daily activity levels, users can receive hourly or semi-hourly reminders to engage in 5-10 minutes of activity throughout the day. They can choose from light, moderate, or intense exercise options based on their preferences.

Conclusion

There are numerous ways to enhance users’ lives through daily activities, starting with the cultivation of realistic and sustainable healthy habits. My recommendations aim to translate these ideals into tangible strategies.

Thank You