Background BellaBeat is a tech manufacturer focused around health products for women. They are looking to potentially become a big player in the global smart device market. Our cofounder, Urška Sršen, wants to analyze smart device fitness data to gain insight on how to grow the BellaBeat company. We will focus on improving the BellaBeat Leaf which can be worn as a bracelet, necklace or clip on the consumer. This leaf tracks the users’ activity, sleep, and stress levels.
Our business task is: Identify the current trends of smart device usage and connect this to the marketing strategy for the company of Bellabeat
We will start with loading the necessary packages for our project
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.0 ✔ 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(readr)
library(ggplot2)
library(dbplyr)
##
## Attaching package: 'dbplyr'
##
## The following objects are masked from 'package:dplyr':
##
## ident, sql
library(lubridate)
library(janitor)
##
## Attaching package: 'janitor'
##
## The following objects are masked from 'package:stats':
##
## chisq.test, fisher.test
Next we will look to import our datasets using read_csv This will look different depending on where your files are located in the directory
dailyactivity <- read_csv("/Users/joebeadles/Desktop/BellaBeat Case Study/FitBit Fitness Tracker Data 04:16/files used/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.
dailycalories <- read_csv("/Users/joebeadles/Desktop/BellaBeat Case Study/FitBit Fitness Tracker Data 04:16/files used/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.
dailyintensities <- read_csv("/Users/joebeadles/Desktop/BellaBeat Case Study/FitBit Fitness Tracker Data 04:16/files used/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.
dailysteps <- read_csv("/Users/joebeadles/Desktop/BellaBeat Case Study/FitBit Fitness Tracker Data 04:16/files used/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.
minutesleep <- read.csv("/Users/joebeadles/Desktop/BellaBeat Case Study/FitBit Fitness Tracker Data 04:16/files used/minuteSleep_merged.csv")
sleepDay <- read.csv("/Users/joebeadles/Desktop/BellaBeat Case Study/FitBit Fitness Tracker Data 04:16/files used/sleepDay_merged.csv")
weightlog <- read.csv("/Users/joebeadles/Desktop/BellaBeat Case Study/FitBit Fitness Tracker Data 04:16/files used/weightLoginfo_merged.csv")
After analyzing the data, we want to get a good look at what our data looks like. You can use head(), glimpse(), or str(), but I chose to use head().
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(dailycalories)
## # 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
head(dailyintensities)
## # 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>
head(dailysteps)
## # 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
head(minutesleep)
## Id date value logId
## 1 1503960366 4/12/2016 2:47:30 AM 3 11380564589
## 2 1503960366 4/12/2016 2:48:30 AM 2 11380564589
## 3 1503960366 4/12/2016 2:49:30 AM 1 11380564589
## 4 1503960366 4/12/2016 2:50:30 AM 1 11380564589
## 5 1503960366 4/12/2016 2:51:30 AM 1 11380564589
## 6 1503960366 4/12/2016 2:52:30 AM 1 11380564589
head(sleepDay)
## Id SleepDay TotalSleepRecords TotalMinutesAsleep
## 1 1503960366 4/12/2016 12:00:00 AM 1 327
## 2 1503960366 4/13/2016 12:00:00 AM 2 384
## 3 1503960366 4/15/2016 12:00:00 AM 1 412
## 4 1503960366 4/16/2016 12:00:00 AM 2 340
## 5 1503960366 4/17/2016 12:00:00 AM 1 700
## 6 1503960366 4/19/2016 12:00:00 AM 1 304
## TotalTimeInBed
## 1 346
## 2 407
## 3 442
## 4 367
## 5 712
## 6 320
head(weightlog)
## Id Date WeightKg WeightPounds Fat BMI
## 1 1503960366 5/2/2016 11:59:59 PM 52.6 115.9631 22 22.65
## 2 1503960366 5/3/2016 11:59:59 PM 52.6 115.9631 NA 22.65
## 3 1927972279 4/13/2016 1:08:52 AM 133.5 294.3171 NA 47.54
## 4 2873212765 4/21/2016 11:59:59 PM 56.7 125.0021 NA 21.45
## 5 2873212765 5/12/2016 11:59:59 PM 57.3 126.3249 NA 21.69
## 6 4319703577 4/17/2016 11:59:59 PM 72.4 159.6147 25 27.45
## IsManualReport LogId
## 1 True 1.462234e+12
## 2 True 1.462320e+12
## 3 False 1.460510e+12
## 4 True 1.461283e+12
## 5 True 1.463098e+12
## 6 True 1.460938e+12
Before doing anything else, we want to make sure our data is clean for analysis
n_distinct(dailyactivity$Id)
## [1] 33
n_distinct(dailycalories$Id)
## [1] 33
n_distinct(dailyintensities$Id)
## [1] 33
n_distinct(dailysteps$Id)
## [1] 33
n_distinct(minutesleep$Id)
## [1] 24
n_distinct(sleepDay$Id)
## [1] 24
n_distinct(weightlog$Id)
## [1] 8
Here we decided to remove three datasets that would not help with answering our business task
remove("minutesleep")
remove("weightlog")
remove("dailyintensities")
Next, it’s essential to remove any duplicates that could interfere with our analysis
sum(duplicated(dailyactivity))
## [1] 0
sum(duplicated(dailycalories))
## [1] 0
sum(duplicated(dailysteps))
## [1] 0
sum(duplicated(sleepDay))
## [1] 3
dailyactivity <- dailyactivity %>%
distinct() %>%
drop_na()
dailycalories <- dailycalories %>%
distinct() %>%
drop_na()
dailysteps <- dailysteps %>%
distinct() %>%
drop_na()
sleepDay <- sleepDay %>%
distinct() %>%
drop_na()
sum(duplicated(dailyactivity))
## [1] 0
sum(duplicated(dailycalories))
## [1] 0
sum(duplicated(dailysteps))
## [1] 0
sum(duplicated(sleepDay))
## [1] 0
dailyactivity <- rename_with(dailyactivity, tolower)
dailycalories <- rename_with(dailycalories, tolower)
dailysteps <- rename_with(dailysteps, tolower)
sleepDay <- rename_with(sleepDay, tolower)
clean_names(dailyactivity)
## # A tibble: 940 × 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
## 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: loggedactivitiesdistance <dbl>,
## # veryactivedistance <dbl>, moderatelyactivedistance <dbl>,
## # lightactivedistance <dbl>, sedentaryactivedistance <dbl>,
## # veryactiveminutes <dbl>, fairlyactiveminutes <dbl>,
## # lightlyactiveminutes <dbl>, sedentaryminutes <dbl>, calories <dbl>
clean_names(dailycalories)
## # A tibble: 940 × 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
## 7 1503960366 4/18/2016 1921
## 8 1503960366 4/19/2016 2035
## 9 1503960366 4/20/2016 1786
## 10 1503960366 4/21/2016 1775
## # ℹ 930 more rows
clean_names(dailysteps)
## # A tibble: 940 × 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
## 7 1503960366 4/18/2016 13019
## 8 1503960366 4/19/2016 15506
## 9 1503960366 4/20/2016 10544
## 10 1503960366 4/21/2016 9819
## # ℹ 930 more rows
head(clean_names(sleepDay))
## id sleepday totalsleeprecords totalminutesasleep
## 1 1503960366 4/12/2016 12:00:00 AM 1 327
## 2 1503960366 4/13/2016 12:00:00 AM 2 384
## 3 1503960366 4/15/2016 12:00:00 AM 1 412
## 4 1503960366 4/16/2016 12:00:00 AM 2 340
## 5 1503960366 4/17/2016 12:00:00 AM 1 700
## 6 1503960366 4/19/2016 12:00:00 AM 1 304
## totaltimeinbed
## 1 346
## 2 407
## 3 442
## 4 367
## 5 712
## 6 320
Capital “Y” for year is important our else your dates will change
dailyactivity <- dailyactivity %>%
rename(date = activitydate) %>%
mutate(date = as_date(date, format = "%m/%d/%Y"))
dailycalories <- dailycalories %>%
rename(date = activityday) %>%
mutate(date = as_date(date, format = "%m/%d/%Y"))
dailysteps <- dailysteps %>%
rename(date = activityday) %>%
mutate(date = as_date(date, format = "%m/%d/%Y"))
Separating the date and time in our sleepDay data set
sleepDay[c('Date', 'Time')] <- str_split_fixed(sleepDay$sleepday, ' ', 2)
sleepDay <- sleepDay %>%
rename(date = Date) %>%
mutate(date = as_date(date, format = "%m/%d/%Y"))
sleepDay <- subset(sleepDay, select = -c(Time))
head(dailyactivity)
## # A tibble: 6 × 15
## id date totalsteps totaldistance trackerdistance
## <dbl> <date> <dbl> <dbl> <dbl>
## 1 1503960366 2016-04-12 13162 8.5 8.5
## 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
## # ℹ 10 more variables: loggedactivitiesdistance <dbl>,
## # veryactivedistance <dbl>, moderatelyactivedistance <dbl>,
## # lightactivedistance <dbl>, sedentaryactivedistance <dbl>,
## # veryactiveminutes <dbl>, fairlyactiveminutes <dbl>,
## # lightlyactiveminutes <dbl>, sedentaryminutes <dbl>, calories <dbl>
head(dailycalories)
## # A tibble: 6 × 3
## id date calories
## <dbl> <date> <dbl>
## 1 1503960366 2016-04-12 1985
## 2 1503960366 2016-04-13 1797
## 3 1503960366 2016-04-14 1776
## 4 1503960366 2016-04-15 1745
## 5 1503960366 2016-04-16 1863
## 6 1503960366 2016-04-17 1728
head(dailysteps)
## # A tibble: 6 × 3
## id date steptotal
## <dbl> <date> <dbl>
## 1 1503960366 2016-04-12 13162
## 2 1503960366 2016-04-13 10735
## 3 1503960366 2016-04-14 10460
## 4 1503960366 2016-04-15 9762
## 5 1503960366 2016-04-16 12669
## 6 1503960366 2016-04-17 9705
head(sleepDay)
## id sleepday totalsleeprecords totalminutesasleep
## 1 1503960366 4/12/2016 12:00:00 AM 1 327
## 2 1503960366 4/13/2016 12:00:00 AM 2 384
## 3 1503960366 4/15/2016 12:00:00 AM 1 412
## 4 1503960366 4/16/2016 12:00:00 AM 2 340
## 5 1503960366 4/17/2016 12:00:00 AM 1 700
## 6 1503960366 4/19/2016 12:00:00 AM 1 304
## totaltimeinbed date
## 1 346 2016-04-12
## 2 407 2016-04-13
## 3 442 2016-04-15
## 4 367 2016-04-16
## 5 712 2016-04-17
## 6 320 2016-04-19
dailyactivity %>%
select(totalsteps,
totaldistance,
calories,
sedentaryminutes) %>%
summary()
## totalsteps totaldistance calories sedentaryminutes
## Min. : 0 Min. : 0.000 Min. : 0 Min. : 0.0
## 1st Qu.: 3790 1st Qu.: 2.620 1st Qu.:1828 1st Qu.: 729.8
## Median : 7406 Median : 5.245 Median :2134 Median :1057.5
## Mean : 7638 Mean : 5.490 Mean :2304 Mean : 991.2
## 3rd Qu.:10727 3rd Qu.: 7.713 3rd Qu.:2793 3rd Qu.:1229.5
## Max. :36019 Max. :28.030 Max. :4900 Max. :1440.0
dailycalories %>%
select(calories) %>%
summary()
## calories
## Min. : 0
## 1st Qu.:1828
## Median :2134
## Mean :2304
## 3rd Qu.:2793
## Max. :4900
dailysteps %>%
select(steptotal) %>%
summary()
## steptotal
## Min. : 0
## 1st Qu.: 3790
## Median : 7406
## Mean : 7638
## 3rd Qu.:10727
## Max. :36019
sleepDay %>%
select(totalminutesasleep,
totaltimeinbed) %>%
summary()
## totalminutesasleep totaltimeinbed
## Min. : 58.0 Min. : 61.0
## 1st Qu.:361.0 1st Qu.:403.8
## Median :432.5 Median :463.0
## Mean :419.2 Mean :458.5
## 3rd Qu.:490.0 3rd Qu.:526.0
## Max. :796.0 Max. :961.0
minutesasleep = sleepDay$totalminutesasleep
timeinbed = sleepDay$totaltimeinbed
difference = mean(timeinbed-minutesasleep)
print(difference)
## [1] 39.30976
Now that we finished our summary analysis, lets dive into relationships between the variables
combined_sleep_activity <- merge(dailyactivity,
sleepDay,
by = "id",
all = TRUE)
ggplot(combined_sleep_activity)+
geom_point(mapping = aes(x = totalsteps, y = totalminutesasleep))
## Warning: Removed 227 rows containing missing values or values outside the scale range
## (`geom_point()`).
No meaningful connections or relationships can be made from this graph,
lets try another one
ggplot(combined_sleep_activity) +
geom_point(mapping = aes(x = totalsteps, y = sedentaryminutes)) +
geom_smooth(stat = 'smooth', method = 'gam', formula = y~x, aes(totalsteps, sedentaryminutes), color = 'blue') +
labs(title = "Total Steps vs. Sedentary Minutes",
subtitle = "Sleep Activity Data",
caption = "Results from 2016",
x = "Total Steps",
y = "Sedentary Minutes")
Negative correlation represented through more steps correlates to less sedentary minutes and vice versa
ggplot(combined_sleep_activity)+
geom_point(mapping = aes(x = totalminutesasleep, y = totaltimeinbed), colour = 'skyblue2')+
labs(title = "Time spent in bed vs. Time spent asleep", caption = "Data from 2016", x = "Minutes asleep", y = "Time in Bed")+
geom_smooth(stat = 'smooth', method = 'gam', formula = y~x, aes(totalminutesasleep, totaltimeinbed), color = 'skyblue4')
## Warning: Removed 227 rows containing non-finite outside the scale range
## (`stat_smooth()`).
## Warning: Removed 227 rows containing missing values or values outside the scale range
## (`geom_point()`).
No surprise we see a positive correlation between time spent in bed and time asleep
Next, let’s look at some correlations between daily steps and daily calories
combined_steps_calories <- merge(dailyactivity,
dailysteps,
by = "id",
all = TRUE)
ggplot(data=combined_steps_calories)+
geom_point(mapping = aes(x = totalsteps, y = calories))+
geom_smooth(stat = 'smooth', method = 'gam', formula = y~x, aes(totalsteps, calories))+
labs(title = "Total Steps vs. Calories", caption = "Data from 2016")
The more steps our participants took, the more calories they burned throughout their daily life
Finally, we will look at a distribution of sleep from our participants
sleepDay$avghours <- (sleepDay$totalminutesasleep)/60
ggplot(data = sleepDay)+
geom_histogram(aes(x = avghours), fill = 'skyblue3', color = 'white')+
labs(title = "Average hours of sleep",
subtitle = "Each individual had a month of their sleep data recorded",
caption = "Data from 2016", x = "Average hours of sleep", y = "Number of days")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Normal distribution