Bellabeat makes high-tech health products specifically for women. By tracking things like activity levels, sleep, stress, and reproductive health, Bellabeat gives women valuable insights into their own bodies and habits. They’re currently a successful smaller company, but they have the potential to grow significantly in the global smart device market. One of the founders, Urška Sršen, thinks that studying the fitness data from these devices could lead to new ways for the company to expand.The case study follows the six step data analysis process:
Ask
Prepare
Process
Analyze
Share
Act
The goal is to find ways for Bellabeat to grow and suggest improvements to their marketing by looking at current trends in how people use smart devices.
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?
For this analysis, we’re using publicly available fitness tracker data from Fitbit users who agreed to share it. This data will help us understand user habits. While the dataset includes information from 30 consenting users (meeting the minimum sample size), was collected over a month in 2016 (April 12th to May 12th), and includes a range of data points like activity levels, sleep, and steps, its origin is a third-party source (Amazon Mechanical Turk surveys), making it difficult to verify its accuracy and limiting our ability to cite its source.
After reviewing the dataset, the following points were noted:
# Load necessary 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.4 ✔ 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(tidyr)
library(lubridate)
library(readr)
library(gridExtra)
##
## Attaching package: 'gridExtra'
##
## The following object is masked from 'package:dplyr':
##
## combine
#Load datasets
daily_activity <- read_csv("Fitabase Data 4.12.16-5.12.16/dailyActivity_merged.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.
daily_calories <- read_csv("Fitabase Data 4.12.16-5.12.16/dailyCalories_merged.csv")
## Rows: 940 Columns: 3
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ActivityDay
## dbl (2): Id, Calories
##
## ℹ 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.
daily_intensities <- read_csv("Fitabase Data 4.12.16-5.12.16/dailyIntensities_merged.csv")
## Rows: 940 Columns: 10
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ActivityDay
## dbl (9): Id, SedentaryMinutes, LightlyActiveMinutes, FairlyActiveMinutes, Ve...
##
## ℹ 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.
daily_steps <- read_csv("Fitabase Data 4.12.16-5.12.16/dailySteps_merged.csv")
## Rows: 940 Columns: 3
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ActivityDay
## dbl (2): Id, StepTotal
##
## ℹ 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.
daily_sleep <- read_csv("Fitabase Data 4.12.16-5.12.16/sleepDay_merged.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.
weight_info <- read_csv("Fitabase Data 4.12.16-5.12.16/weightLogInfo_merged.csv")
## Rows: 67 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): Date
## dbl (6): Id, WeightKg, WeightPounds, Fat, BMI, LogId
## lgl (1): IsManualReport
##
## ℹ 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.
# data preview
head(daily_activity)
## # 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>
colnames(daily_activity)
## [1] "Id" "ActivityDate"
## [3] "TotalSteps" "TotalDistance"
## [5] "TrackerDistance" "LoggedActivitiesDistance"
## [7] "VeryActiveDistance" "ModeratelyActiveDistance"
## [9] "LightActiveDistance" "SedentaryActiveDistance"
## [11] "VeryActiveMinutes" "FairlyActiveMinutes"
## [13] "LightlyActiveMinutes" "SedentaryMinutes"
## [15] "Calories"
n_distinct(daily_activity$Id)
## [1] 33
head(daily_calories)
## # A tibble: 6 × 3
## Id ActivityDay Calories
## <dbl> <chr> <dbl>
## 1 1503960366 4/12/2016 1985
## 2 1503960366 4/13/2016 1797
## 3 1503960366 4/14/2016 1776
## 4 1503960366 4/15/2016 1745
## 5 1503960366 4/16/2016 1863
## 6 1503960366 4/17/2016 1728
colnames(daily_calories)
## [1] "Id" "ActivityDay" "Calories"
n_distinct(daily_calories$Id)
## [1] 33
head(daily_intensities)
## # A tibble: 6 × 10
## Id ActivityDay SedentaryMinutes LightlyActiveMinutes FairlyActiveMinutes
## <dbl> <chr> <dbl> <dbl> <dbl>
## 1 1.50e9 4/12/2016 728 328 13
## 2 1.50e9 4/13/2016 776 217 19
## 3 1.50e9 4/14/2016 1218 181 11
## 4 1.50e9 4/15/2016 726 209 34
## 5 1.50e9 4/16/2016 773 221 10
## 6 1.50e9 4/17/2016 539 164 20
## # ℹ 5 more variables: VeryActiveMinutes <dbl>, SedentaryActiveDistance <dbl>,
## # LightActiveDistance <dbl>, ModeratelyActiveDistance <dbl>,
## # VeryActiveDistance <dbl>
colnames(daily_intensities)
## [1] "Id" "ActivityDay"
## [3] "SedentaryMinutes" "LightlyActiveMinutes"
## [5] "FairlyActiveMinutes" "VeryActiveMinutes"
## [7] "SedentaryActiveDistance" "LightActiveDistance"
## [9] "ModeratelyActiveDistance" "VeryActiveDistance"
n_distinct(daily_intensities$Id)
## [1] 33
head(daily_steps)
## # A tibble: 6 × 3
## Id ActivityDay StepTotal
## <dbl> <chr> <dbl>
## 1 1503960366 4/12/2016 13162
## 2 1503960366 4/13/2016 10735
## 3 1503960366 4/14/2016 10460
## 4 1503960366 4/15/2016 9762
## 5 1503960366 4/16/2016 12669
## 6 1503960366 4/17/2016 9705
colnames(daily_steps)
## [1] "Id" "ActivityDay" "StepTotal"
n_distinct(daily_steps$Id)
## [1] 33
head(daily_sleep)
## # 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
colnames(daily_sleep)
## [1] "Id" "SleepDay" "TotalSleepRecords"
## [4] "TotalMinutesAsleep" "TotalTimeInBed"
n_distinct(daily_sleep$Id)
## [1] 24
head(weight_info)
## # A tibble: 6 × 8
## Id Date WeightKg WeightPounds Fat BMI IsManualReport LogId
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <lgl> <dbl>
## 1 1503960366 5/2/2016 … 52.6 116. 22 22.6 TRUE 1.46e12
## 2 1503960366 5/3/2016 … 52.6 116. NA 22.6 TRUE 1.46e12
## 3 1927972279 4/13/2016… 134. 294. NA 47.5 FALSE 1.46e12
## 4 2873212765 4/21/2016… 56.7 125. NA 21.5 TRUE 1.46e12
## 5 2873212765 5/12/2016… 57.3 126. NA 21.7 TRUE 1.46e12
## 6 4319703577 4/17/2016… 72.4 160. 25 27.5 TRUE 1.46e12
colnames(weight_info)
## [1] "Id" "Date" "WeightKg" "WeightPounds"
## [5] "Fat" "BMI" "IsManualReport" "LogId"
n_distinct(weight_info$Id)
## [1] 8
daily_activity %>%
select(TotalSteps, TotalDistance, VeryActiveMinutes) %>%
summary()
## TotalSteps TotalDistance VeryActiveMinutes
## Min. : 0 Min. : 0.000 Min. : 0.00
## 1st Qu.: 3790 1st Qu.: 2.620 1st Qu.: 0.00
## Median : 7406 Median : 5.245 Median : 4.00
## Mean : 7638 Mean : 5.490 Mean : 21.16
## 3rd Qu.:10727 3rd Qu.: 7.713 3rd Qu.: 32.00
## Max. :36019 Max. :28.030 Max. :210.00
# Remove duplicate rows
daily_activity <- daily_activity %>% distinct()
daily_calories <- daily_calories %>% distinct()
daily_steps <- daily_steps %>% distinct()
daily_sleep <- daily_sleep %>% distinct()
daily_intensities <- daily_intensities %>% distinct()
weight_info <- weight_info %>% distinct()
# Format date columns
daily_activity <- daily_activity %>%
mutate(ActivityDate = mdy(ActivityDate))
daily_calories <- daily_calories %>%
mutate(ActivityDay = mdy(ActivityDay))
daily_steps <- daily_steps %>%
mutate(ActivityDay = mdy(ActivityDay))
daily_sleep <- daily_sleep %>%
mutate(SleepDay = mdy_hms(SleepDay))
daily_intensities <- daily_intensities %>%
mutate(ActivityDay = mdy(ActivityDay))
weight_info <- weight_info %>%
mutate(Date = mdy_hms(Date))
# Validate the cleaned datasets
glimpse(daily_activity)
## Rows: 940
## Columns: 15
## $ Id <dbl> 1503960366, 1503960366, 1503960366, 150396036…
## $ ActivityDate <date> 2016-04-12, 2016-04-13, 2016-04-14, 2016-04-…
## $ TotalSteps <dbl> 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 <dbl> 25, 21, 30, 29, 36, 38, 42, 50, 28, 19, 66, 4…
## $ FairlyActiveMinutes <dbl> 13, 19, 11, 34, 10, 20, 16, 31, 12, 8, 27, 21…
## $ LightlyActiveMinutes <dbl> 328, 217, 181, 209, 221, 164, 233, 264, 205, …
## $ SedentaryMinutes <dbl> 728, 776, 1218, 726, 773, 539, 1149, 775, 818…
## $ Calories <dbl> 1985, 1797, 1776, 1745, 1863, 1728, 1921, 203…
glimpse(daily_calories)
## Rows: 940
## Columns: 3
## $ Id <dbl> 1503960366, 1503960366, 1503960366, 1503960366, 1503960366…
## $ ActivityDay <date> 2016-04-12, 2016-04-13, 2016-04-14, 2016-04-15, 2016-04-1…
## $ Calories <dbl> 1985, 1797, 1776, 1745, 1863, 1728, 1921, 2035, 1786, 1775…
glimpse(daily_steps)
## Rows: 940
## Columns: 3
## $ Id <dbl> 1503960366, 1503960366, 1503960366, 1503960366, 1503960366…
## $ ActivityDay <date> 2016-04-12, 2016-04-13, 2016-04-14, 2016-04-15, 2016-04-1…
## $ StepTotal <dbl> 13162, 10735, 10460, 9762, 12669, 9705, 13019, 15506, 1054…
glimpse(daily_sleep)
## Rows: 410
## Columns: 5
## $ Id <dbl> 1503960366, 1503960366, 1503960366, 1503960366, 150…
## $ SleepDay <dttm> 2016-04-12, 2016-04-13, 2016-04-15, 2016-04-16, 20…
## $ TotalSleepRecords <dbl> 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ TotalMinutesAsleep <dbl> 327, 384, 412, 340, 700, 304, 360, 325, 361, 430, 2…
## $ TotalTimeInBed <dbl> 346, 407, 442, 367, 712, 320, 377, 364, 384, 449, 3…
glimpse(daily_intensities)
## Rows: 940
## Columns: 10
## $ Id <dbl> 1503960366, 1503960366, 1503960366, 150396036…
## $ ActivityDay <date> 2016-04-12, 2016-04-13, 2016-04-14, 2016-04-…
## $ SedentaryMinutes <dbl> 728, 776, 1218, 726, 773, 539, 1149, 775, 818…
## $ LightlyActiveMinutes <dbl> 328, 217, 181, 209, 221, 164, 233, 264, 205, …
## $ FairlyActiveMinutes <dbl> 13, 19, 11, 34, 10, 20, 16, 31, 12, 8, 27, 21…
## $ VeryActiveMinutes <dbl> 25, 21, 30, 29, 36, 38, 42, 50, 28, 19, 66, 4…
## $ SedentaryActiveDistance <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ LightActiveDistance <dbl> 6.06, 4.71, 3.91, 2.83, 5.04, 2.51, 4.71, 5.0…
## $ ModeratelyActiveDistance <dbl> 0.55, 0.69, 0.40, 1.26, 0.41, 0.78, 0.64, 1.3…
## $ VeryActiveDistance <dbl> 1.88, 1.57, 2.44, 2.14, 2.71, 3.19, 3.25, 3.5…
glimpse(weight_info)
## Rows: 67
## Columns: 8
## $ Id <dbl> 1503960366, 1503960366, 1927972279, 2873212765, 2873212…
## $ Date <dttm> 2016-05-02 23:59:59, 2016-05-03 23:59:59, 2016-04-13 0…
## $ WeightKg <dbl> 52.6, 52.6, 133.5, 56.7, 57.3, 72.4, 72.3, 69.7, 70.3, …
## $ WeightPounds <dbl> 115.9631, 115.9631, 294.3171, 125.0021, 126.3249, 159.6…
## $ Fat <dbl> 22, NA, NA, NA, NA, 25, NA, NA, NA, NA, NA, NA, NA, NA,…
## $ BMI <dbl> 22.65, 22.65, 47.54, 21.45, 21.69, 27.45, 27.38, 27.25,…
## $ IsManualReport <lgl> TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, …
## $ LogId <dbl> 1.462234e+12, 1.462320e+12, 1.460510e+12, 1.461283e+12,…
#Define the number of unique rows by Id column
n_distinct(daily_activity$Id)
## [1] 33
n_distinct(daily_sleep$Id)
## [1] 24
n_distinct(weight_info$Id)
## [1] 8
Users will be categorized based on their activity levels using quartile-based segmentation.
The following steps were taken:
user_avg_info <-
daily_activity %>%
group_by(Id) %>%
drop_na() %>%
summarise( avg_step = mean(TotalSteps),
avg_distance = mean(TotalDistance),
avg_very_active_min = mean(VeryActiveMinutes)
)
p75_step <- quantile(daily_activity$TotalSteps, probs =0.75)
p75_distance <- quantile(daily_activity$TotalDistance, probs =0.75)
p75_very_active_min <- quantile (daily_activity$VeryActiveMinutes, probs = 0.75)
p25_step <- quantile(daily_activity$TotalSteps, probs =0.25)
p25_distance <- quantile(daily_activity$TotalDistance, probs =0.25)
p25_very_active_min <- quantile (daily_activity$VeryActiveMinutes, probs = 0.25)
High Active: Users whose average steps, average distance, and average very active minutes were all at or above the 75th percentile for their respective metrics.
Moderate Active: Users whose average steps, average distance, and average very active minutes were all between the 25th and 75th percentiles for their respective metrics.
Low Active: Users whose average steps, average distance, and average very active minutes were all at or below the 25th percentile for their respective metrics.
# categorize customer in 3 groups
customer_category<- daily_activity %>%
group_by(Id) %>%
summarise(avg_step = mean(TotalSteps),
avg_distance = mean(TotalDistance),
avg_very_active_min = mean(VeryActiveMinutes)) %>%
mutate(CustomerType = case_when(
avg_step >= p75_step &
avg_distance >= p75_distance &
avg_very_active_min >= p75_very_active_min ~ 'High Active',
avg_step <= p25_step &
avg_distance <= p25_distance &
avg_very_active_min <= p25_very_active_min ~ 'Low Active',
TRUE ~ 'Moderate Active'
))
user_avg_info <- merge(user_avg_info, customer_category, by = "Id")
user_avg_info_new <- user_avg_info %>%
select(Id, avg_step.x, avg_distance.x, avg_very_active_min.x, 'CustomerType' )
# count users by types
user_avg_info_new %>%
group_by(CustomerType) %>%
count()
## # A tibble: 2 × 2
## # Groups: CustomerType [2]
## CustomerType n
## <chr> <int>
## 1 High Active 4
## 2 Moderate Active 29
The results of the segmentation process showed 4 users classified as High Active and 29 as Moderate Active. No users were classified as Low Active according to the defined criteria.
The ID and Activity Date columns were combined to create a new, unique identifier column called ‘NewId’. Additionally, the ‘daily_activity’ and ‘daily_sleep’ tables were joined for further analysis.
# create new column
daily_activity_new <- daily_activity %>%
unite('NewId', Id, ActivityDate, sep=' ')
head(daily_activity_new)
## # A tibble: 6 × 14
## NewId TotalSteps TotalDistance TrackerDistance LoggedActivitiesDist…¹
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 1503960366 20… 13162 8.5 8.5 0
## 2 1503960366 20… 10735 6.97 6.97 0
## 3 1503960366 20… 10460 6.74 6.74 0
## 4 1503960366 20… 9762 6.28 6.28 0
## 5 1503960366 20… 12669 8.16 8.16 0
## 6 1503960366 20… 9705 6.48 6.48 0
## # ℹ abbreviated name: ¹LoggedActivitiesDistance
## # ℹ 9 more variables: VeryActiveDistance <dbl>, ModeratelyActiveDistance <dbl>,
## # LightActiveDistance <dbl>, SedentaryActiveDistance <dbl>,
## # VeryActiveMinutes <dbl>, FairlyActiveMinutes <dbl>,
## # LightlyActiveMinutes <dbl>, SedentaryMinutes <dbl>, Calories <dbl>
daily_sleep_new <- daily_sleep %>%
unite('NewId', Id, SleepDay, sep=' ')
head(daily_sleep_new)
## # A tibble: 6 × 4
## NewId TotalSleepRecords TotalMinutesAsleep TotalTimeInBed
## <chr> <dbl> <dbl> <dbl>
## 1 1503960366 2016-04-12 1 327 346
## 2 1503960366 2016-04-13 2 384 407
## 3 1503960366 2016-04-15 1 412 442
## 4 1503960366 2016-04-16 2 340 367
## 5 1503960366 2016-04-17 1 700 712
## 6 1503960366 2016-04-19 1 304 320
# merge daily_active table with daily_sleep table
merge_act_sleep <- merge(daily_activity_new, daily_sleep_new, by = 'NewId', all=TRUE )
head(merge_act_sleep)
## NewId TotalSteps TotalDistance TrackerDistance
## 1 1503960366 2016-04-12 13162 8.50 8.50
## 2 1503960366 2016-04-13 10735 6.97 6.97
## 3 1503960366 2016-04-14 10460 6.74 6.74
## 4 1503960366 2016-04-15 9762 6.28 6.28
## 5 1503960366 2016-04-16 12669 8.16 8.16
## 6 1503960366 2016-04-17 9705 6.48 6.48
## LoggedActivitiesDistance VeryActiveDistance ModeratelyActiveDistance
## 1 0 1.88 0.55
## 2 0 1.57 0.69
## 3 0 2.44 0.40
## 4 0 2.14 1.26
## 5 0 2.71 0.41
## 6 0 3.19 0.78
## LightActiveDistance SedentaryActiveDistance VeryActiveMinutes
## 1 6.06 0 25
## 2 4.71 0 21
## 3 3.91 0 30
## 4 2.83 0 29
## 5 5.04 0 36
## 6 2.51 0 38
## FairlyActiveMinutes LightlyActiveMinutes SedentaryMinutes Calories
## 1 13 328 728 1985
## 2 19 217 776 1797
## 3 11 181 1218 1776
## 4 34 209 726 1745
## 5 10 221 773 1863
## 6 20 164 539 1728
## TotalSleepRecords TotalMinutesAsleep TotalTimeInBed
## 1 1 327 346
## 2 2 384 407
## 3 NA NA NA
## 4 1 412 442
## 5 2 340 367
## 6 1 700 712
n_distinct(merge_act_sleep$NewId)
## [1] 940
A preliminary look at the user groups identified earlier reveals some interesting trends. The data suggests that High Active users burn more calories, but tend to sleep less than Moderate Active users.
merge_cal_act_type <- merge(user_avg_info_new, daily_calories, by='Id') %>%
group_by(CustomerType) %>% summarise(AvgCal= mean(Calories))
print(merge_cal_act_type)
## # A tibble: 2 × 2
## CustomerType AvgCal
## <chr> <dbl>
## 1 High Active 2673.
## 2 Moderate Active 2247.
merge_sleep_act_type <- merge(user_avg_info_new, daily_sleep, by='Id') %>%
group_by(CustomerType) %>% summarise(AvgSleepHr= mean((TotalMinutesAsleep/60)))
print(merge_sleep_act_type)
## # A tibble: 2 × 2
## CustomerType AvgSleepHr
## <chr> <dbl>
## 1 High Active 5.89
## 2 Moderate Active 7.07
Rather than immediately analyzing the data, I prefer to first develop several hypotheses and then use the data to test their validity.
Hypotheses 1: Is there a relationship between sleep duration and the number of hours spent sitting?
Conclusion: The results suggest a negative correlation between sitting time and sleep duration; as sitting time increases, sleep time tends to decrease.
plot_sleep_vs_sedebtary <-
ggplot(data = drop_na(merge_act_sleep), aes(x=SedentaryMinutes/60, y=TotalMinutesAsleep/60))+
geom_point(color="#C4961A")+
geom_smooth(size=0.5, color="#D16103")+
labs(title = ' Asleep Hour by Sedentary Hour ', x= 'Sendentary Hour', y='Asleep Hour')+
theme(text = element_text(family='Calibri'))
plot(plot_sleep_vs_sedebtary)
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Hypotheses 2: Is sleep latency (time in bed minus time asleep) correlated with sitting duration?
Conclusion: No correlation was found between sleep latency (time to fall asleep) and sitting time.
plot_sleeplatency <-
ggplot(data = drop_na(merge_act_sleep),
aes(x=SedentaryMinutes/60, y= (TotalTimeInBed - TotalMinutesAsleep)/60))+
geom_point(color="#C4961A")+
geom_smooth(size=0.5, color="#D16103")+
labs(title = 'Sleep Latency Hour by Sedentary Hour', x= 'Sedentary Hour', y = 'Sleep Latency Hour')+
theme(text = element_text(family = 'Calibri'))
print(plot_sleeplatency)
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Hypotheses 3: Is there a relationship between calories burned and the duration of physical activity?
Conclusion: The data shows a positive correlation between very active hours and calories burned. However, there’s little to no correlation between calories burned and either fairly active or lightly active hours.
plot_cal_va <-
ggplot(data = drop_na(merge_act_sleep), aes(x=Calories, y=VeryActiveMinutes/60))+
geom_point(color="#52854C")+
geom_smooth(size=0.5, color="#D16103")+
labs(title = 'Very Active Hour by Calories', x= 'Calories', y= 'Active Hour')+
theme(text = element_text(family = 'Calibri', size = 8))
plot_cal_fa <-
ggplot(data = drop_na(merge_act_sleep), aes(x=Calories, y=FairlyActiveMinutes/60))+
geom_point(color="#009E73")+
geom_smooth(size=0.5, color="#D16103")+
labs(title = 'Fairly Active Hour by Calories', x= 'Calories', y='Active Hour' )+
theme(text = element_text(family = 'Calibri', size = 8))
plot_cal_la <-
ggplot(data = drop_na(merge_act_sleep), aes(x=Calories, y=LightlyActiveMinutes/60))+
geom_point(color="#C3D7A4")+
geom_smooth(size=0.5, color="#D16103")+
labs(title = 'Lightly Active Hour by Calories', x= 'Calories', y ='Active Hour')+
theme(text = element_text(family = 'Calibri', size=8))
combined_plots_cal_act_type <-grid.arrange(plot_cal_va, plot_cal_fa, plot_cal_la, nrow=1, ncol=3)
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Hypotheses 4: What is the relationship between calories burned, steps taken, and distance walked?
Conclusion: Steps taken, calories burned, and distance traveled are all positively correlated.
plot_cal_step <-
ggplot((data=merge_act_sleep), aes(x=Calories, y=TotalSteps, color=TotalDistance)) +
geom_point()+
geom_smooth(size=0.5, color="#D16103")+
scale_color_gradient(low="#C3D7A4", high = "darkblue" )+
labs(title = 'Step Count by Calories ', x= 'Calories', y= 'Step Count', color= 'Distance')+
theme(text = element_text(family = 'Calibri'))
print(plot_cal_step)
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Hypotheses 5: How do daily step counts vary across the days of the week?
Conclusion: Step counts tend to be lowest on Sundays.
custom_order <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
merge_act_sleep_new <- merge_act_sleep %>%
separate(NewId, c("Id", "Date"), sep = " ")
merge_act_sleep_new$Date <- as.Date(merge_act_sleep_new$Date , format = "%Y-%m-%d")
merge_act_sleep_new$DayOfWeek <- weekdays(merge_act_sleep_new$Date)
merge_act_sleep_new <- merge_act_sleep_new %>%
drop_na() %>%
mutate(DayOfWeek = reorder(DayOfWeek, match(DayOfWeek, custom_order))) %>%
group_by(DayOfWeek) %>%
group_by(DayOfWeek) %>%
summarise(StepDow=sum(TotalSteps))
plot_step_dow<-
ggplot(data=merge_act_sleep_new, aes(x = DayOfWeek, y = StepDow)) +
geom_bar(stat = "identity", fill = "#4E84C4")+
labs(title = "Total Steps by Day of Week", x = "Day of Week", y = "Total Steps")+
scale_y_continuous(labels = scales::comma)+
annotate('text', x='Sunday', y=480000, label='people tend \nto walk \nless on sunday', size=2.5, color="#D16103", fontface='bold', angle=15)+
theme(text = element_text(family = 'Calibri'))
print(plot_step_dow)
plots <- list(
plot_sleeplatency,
plot_sleep_vs_sedebtary,
combined_plots_cal_act_type,
plot_cal_step,
plot_step_dow
)
plot_names <- c("plot_sleeplatency", "plot_sleep_vs_sedebtary", "combined_plots_cal_act_type", "plot_cal_step", "plot_step_dow")
for (i in seq_along(plots)) {
ggsave(paste0(plot_names[i], '.png'), plot =plots[[i]], width = 6, height=4, dpi=300)
}