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.
Analyze Fitbit data to gain insight and help guide marketing strategy for Bellabeat to grow.
The following three points are the questions needed to be answered by this analysis.
What are some trends in smart device usage?
How could these trends apply to Bellabeat customers?
How could these trends help influence Bellabeat marketing strategy?
Primary stakeholders: Urška Sršen and Sando Mur, executive team members.
Secondary stakeholders: Bellabeat marketing analytics team.
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.
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.
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)
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
Next, checked for duplicate entries and ensured data cleanliness
n_distinct(dailyActivity$Id)
## [1] 33
n_distinct(sleepDay$Id)
## [1] 24
sum(duplicated(dailyActivity))
## [1] 0
sum(duplicated(sleepDay))
## [1] 3
sleepDay <- sleepDay %>%
distinct() %>%
drop_na()
sum(duplicated(sleepDay))
## [1] 0
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
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()))
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
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
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
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.
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.
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)
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.
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.