2024-04-27Bellabeat is a high-tech company that manufactures health-focused smart products. Found by Urška Sršen and Sando Mur in 2013, with a line of products that collects data on activity, sleep, stress, and reproductive health to empower women with knowledge about their own health and habits.
Provide stakeholders (Urška Sršen, Sando Mur & Bellabeat marketing analytics team) with analysis on how non-Bellabeat smart devices are used to be able to better market Bellabeat products.
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(lubridate)
library(dplyr)
library(ggplot2)
library(tidyr)
Data is from a Kaggle dataset that contains personal fitness tracker from thirty fitbit users. These users consented to the submission of personal tracker data, including minute-level output for physical activity, heart rate, and sleep monitoring. It includes information about daily activity, steps, and heart rate that can be used to explore users’ habits.
daily_activity_3 <- read.csv("dailyActivity_merged_3-4.csv")
daily_activity_4 <- read.csv("dailyActivity_merged_4-5.csv")
weight_log_info_3 <- read.csv("weightLogInfo_merged_3-4.csv")
weight_log_info_4 <- read.csv("weightLogInfo_merged_4-5.csv")
hourly_calories_3 <- read_csv("hourlyCalories_merged_3-4.csv")
## Rows: 24084 Columns: 3
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ActivityHour
## 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.
hourly_calories_4 <- read_csv("hourlyCalories_merged_4-5.csv")
## Rows: 22099 Columns: 3
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ActivityHour
## 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.
hourly_intensities_3 <- read_csv("hourlyIntensities_merged_3-4.csv")
## Rows: 24084 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ActivityHour
## dbl (3): Id, TotalIntensity, AverageIntensity
##
## ℹ 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.
hourly_intensities_4 <- read_csv("hourlyIntensities_merged_4-5.csv")
## Rows: 22099 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ActivityHour
## dbl (3): Id, TotalIntensity, AverageIntensity
##
## ℹ 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.
minute_sleep_3 <- read_csv("minuteSleep_merged_3-4.csv")
## Rows: 198559 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): date
## dbl (3): Id, value, logId
##
## ℹ 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.
minute_sleep_4 <- read_csv("minuteSleep_merged_4-5.csv")
## Rows: 188521 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): date
## dbl (3): Id, value, logId
##
## ℹ 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.
Explored a few of the key tables and made sure column names were same for data from 03.12.2016-04.11.2016 tables and 04.12.2016-05.12.2016. Also to help see names to merge data later for further analysis.
head(daily_activity_3)
## Id ActivityDate TotalSteps TotalDistance TrackerDistance
## 1 1503960366 3/25/2016 11004 7.11 7.11
## 2 1503960366 3/26/2016 17609 11.55 11.55
## 3 1503960366 3/27/2016 12736 8.53 8.53
## 4 1503960366 3/28/2016 13231 8.93 8.93
## 5 1503960366 3/29/2016 12041 7.85 7.85
## 6 1503960366 3/30/2016 10970 7.16 7.16
## LoggedActivitiesDistance VeryActiveDistance ModeratelyActiveDistance
## 1 0 2.57 0.46
## 2 0 6.92 0.73
## 3 0 4.66 0.16
## 4 0 3.19 0.79
## 5 0 2.16 1.09
## 6 0 2.36 0.51
## LightActiveDistance SedentaryActiveDistance VeryActiveMinutes
## 1 4.07 0 33
## 2 3.91 0 89
## 3 3.71 0 56
## 4 4.95 0 39
## 5 4.61 0 28
## 6 4.29 0 30
## FairlyActiveMinutes LightlyActiveMinutes SedentaryMinutes Calories
## 1 12 205 804 1819
## 2 17 274 588 2154
## 3 5 268 605 1944
## 4 20 224 1080 1932
## 5 28 243 763 1886
## 6 13 223 1174 1820
head(daily_activity_4)
## Id ActivityDate TotalSteps TotalDistance TrackerDistance
## 1 1503960366 4/12/2016 13162 8.50 8.50
## 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
## 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
colnames(daily_activity_3)
## [1] "Id" "ActivityDate"
## [3] "TotalSteps" "TotalDistance"
## [5] "TrackerDistance" "LoggedActivitiesDistance"
## [7] "VeryActiveDistance" "ModeratelyActiveDistance"
## [9] "LightActiveDistance" "SedentaryActiveDistance"
## [11] "VeryActiveMinutes" "FairlyActiveMinutes"
## [13] "LightlyActiveMinutes" "SedentaryMinutes"
## [15] "Calories"
colnames(daily_activity_4)
## [1] "Id" "ActivityDate"
## [3] "TotalSteps" "TotalDistance"
## [5] "TrackerDistance" "LoggedActivitiesDistance"
## [7] "VeryActiveDistance" "ModeratelyActiveDistance"
## [9] "LightActiveDistance" "SedentaryActiveDistance"
## [11] "VeryActiveMinutes" "FairlyActiveMinutes"
## [13] "LightlyActiveMinutes" "SedentaryMinutes"
## [15] "Calories"
head(minute_sleep_3)
## # A tibble: 6 Ă— 4
## Id date value logId
## <dbl> <chr> <dbl> <dbl>
## 1 1503960366 3/13/2016 2:39:30 AM 1 11114919637
## 2 1503960366 3/13/2016 2:40:30 AM 1 11114919637
## 3 1503960366 3/13/2016 2:41:30 AM 1 11114919637
## 4 1503960366 3/13/2016 2:42:30 AM 1 11114919637
## 5 1503960366 3/13/2016 2:43:30 AM 1 11114919637
## 6 1503960366 3/13/2016 2:44:30 AM 1 11114919637
head(minute_sleep_4)
## # A tibble: 6 Ă— 4
## Id date value logId
## <dbl> <chr> <dbl> <dbl>
## 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
colnames(minute_sleep_3)
## [1] "Id" "date" "value" "logId"
colnames(minute_sleep_4)
## [1] "Id" "date" "value" "logId"
How many unique participants are there in each dataframe?
n_distinct(daily_activity_3$Id)
## [1] 35
n_distinct(daily_activity_4$Id)
## [1] 33
n_distinct(weight_log_info_3$Id)
## [1] 11
n_distinct(weight_log_info_4$Id)
## [1] 8
n_distinct(hourly_calories_3$Id)
## [1] 34
n_distinct(hourly_calories_4$Id)
## [1] 33
n_distinct(hourly_intensities_3$Id)
## [1] 34
n_distinct(hourly_intensities_4$Id)
## [1] 33
n_distinct(minute_sleep_3$Id)
## [1] 23
n_distinct(minute_sleep_4$Id)
## [1] 24
For 03.12.2016-04.11.2016 the number of participants for daily activity is 35, weight log is 11, hourly calories is 34, hourly intensities is 34 and minutes sleep is 23. For 04.12.2016-05.12.2016 the number of participants for daily activity is 33, weight log is 8, hourly calories is 33, hourly intensities is 33 and minutes sleep is 24. No conclusions will be able to be drawn from the weight log data due to the small sample size. Also not all participants participated in the minutes sleep data.
How many observations are there in each dataframe?
nrow(daily_activity_3)
## [1] 457
nrow(daily_activity_4)
## [1] 940
nrow(weight_log_info_3)
## [1] 33
nrow(weight_log_info_4)
## [1] 67
nrow(hourly_calories_3)
## [1] 24084
nrow(hourly_calories_4)
## [1] 22099
nrow(hourly_intensities_3)
## [1] 24084
nrow(hourly_intensities_4)
## [1] 22099
nrow(minute_sleep_3)
## [1] 198559
nrow(minute_sleep_4)
## [1] 188521
457, 940, 33, 67, 24084, 22099, 24084, 22099, 198559, 188521
What are some quick summary statistics we’d want to know about each data frame?
daily_activity_3%>%
select(TotalSteps,
TotalDistance,
SedentaryMinutes) %>%
summary()
## TotalSteps TotalDistance SedentaryMinutes
## Min. : 0 Min. : 0.000 Min. : 32.0
## 1st Qu.: 1988 1st Qu.: 1.410 1st Qu.: 728.0
## Median : 5986 Median : 4.090 Median :1057.0
## Mean : 6547 Mean : 4.664 Mean : 995.3
## 3rd Qu.:10198 3rd Qu.: 7.160 3rd Qu.:1285.0
## Max. :28497 Max. :27.530 Max. :1440.0
daily_activity_4%>%
select(TotalSteps,
TotalDistance,
SedentaryMinutes) %>%
summary()
## TotalSteps TotalDistance SedentaryMinutes
## Min. : 0 Min. : 0.000 Min. : 0.0
## 1st Qu.: 3790 1st Qu.: 2.620 1st Qu.: 729.8
## Median : 7406 Median : 5.245 Median :1057.5
## Mean : 7638 Mean : 5.490 Mean : 991.2
## 3rd Qu.:10727 3rd Qu.: 7.713 3rd Qu.:1229.5
## Max. :36019 Max. :28.030 Max. :1440.0
hourly_calories_3%>%
select(Calories) %>%
summary()
## Calories
## Min. : 42.00
## 1st Qu.: 61.00
## Median : 77.00
## Mean : 94.27
## 3rd Qu.:104.00
## Max. :933.00
hourly_calories_4%>%
select(Calories) %>%
summary()
## Calories
## Min. : 42.00
## 1st Qu.: 63.00
## Median : 83.00
## Mean : 97.39
## 3rd Qu.:108.00
## Max. :948.00
hourly_intensities_3%>%
select(TotalIntensity,
AverageIntensity) %>%
summary()
## TotalIntensity AverageIntensity
## Min. : 0.00 Min. :0.00000
## 1st Qu.: 0.00 1st Qu.:0.00000
## Median : 1.00 Median :0.01667
## Mean : 10.83 Mean :0.18044
## 3rd Qu.: 14.00 3rd Qu.:0.23333
## Max. :180.00 Max. :3.00000
hourly_intensities_4%>%
select(TotalIntensity,
AverageIntensity) %>%
summary()
## TotalIntensity AverageIntensity
## Min. : 0.00 Min. :0.0000
## 1st Qu.: 0.00 1st Qu.:0.0000
## Median : 3.00 Median :0.0500
## Mean : 12.04 Mean :0.2006
## 3rd Qu.: 16.00 3rd Qu.:0.2667
## Max. :180.00 Max. :3.0000
minute_sleep_3 %>%
select(value) %>%
summary()
## value
## Min. :1.000
## 1st Qu.:1.000
## Median :1.000
## Mean :1.086
## 3rd Qu.:1.000
## Max. :3.000
minute_sleep_4 %>%
select(value) %>%
summary()
## value
## Min. :1.000
## 1st Qu.:1.000
## Median :1.000
## Mean :1.096
## 3rd Qu.:1.000
## Max. :3.000
Counting number of times Sedentary Minutes = 1440 minutes which is a whole day
count(daily_activity_3, SedentaryMinutes == 1440)
## SedentaryMinutes == 1440 n
## 1 FALSE 394
## 2 TRUE 63
count(daily_activity_4, SedentaryMinutes == 1440)
## SedentaryMinutes == 1440 n
## 1 FALSE 861
## 2 TRUE 79
For March-April daily activity data there are 63 days that sedentary minutes is equal to 1440 so the whole day and 79 days for April-May. This would lead me to believe the person didn’t wear their fitness tracker for the day which could skew some of the data and results.
Getting idea of how often fitness trackers were worn excluding data points where sedentary minutes was equal to 1440
minutes_3 <- select(daily_activity_3,"VeryActiveMinutes", "FairlyActiveMinutes", "LightlyActiveMinutes","SedentaryMinutes")
minutes_3$total_minutes <- rowSums(minutes_3,na.rm =TRUE)
count(minutes_3, total_minutes == 1440)
## total_minutes == 1440 n
## 1 FALSE 224
## 2 TRUE 233
count(minutes_3, total_minutes > 1080)
## total_minutes > 1080 n
## 1 FALSE 183
## 2 TRUE 274
minutes_4 <- select(daily_activity_4,"VeryActiveMinutes", "FairlyActiveMinutes", "LightlyActiveMinutes","SedentaryMinutes")
minutes_4$total_minutes <- rowSums(minutes_4,na.rm =TRUE)
count(minutes_4, total_minutes == 1440)
## total_minutes == 1440 n
## 1 FALSE 462
## 2 TRUE 478
count(minutes_4, total_minutes > 1080)
## total_minutes > 1080 n
## 1 FALSE 372
## 2 TRUE 568
For March-April the whole day was tracked 170 times(43.1%) and for April-May 394 times(46.3%). More than 2/3rds of the day or 1080 minutes was tracked 211 times(53.6%) for March-April and 489 times(56.8%) for April-May.
Some interesting finds
The mean of the total steps for the first month is 6547 and the second is 7638. Evne though the total steps increased in the second month it is still below the daily recommended number of steps per day of 10,000.
The max for sedentary minutes in both months is 1440 minutes which equals 24 hours so going to look into this more since unlikely person didn’t move once in whole day.
The body averages to burn about 1,300 to more than 2,000 calories without any activity.The mean of the average calories times 24 (to equal a full day) for the first month is 2262.48 and second month is 2337.36.
The hourly intensities for both months have a wide range from 0 to 180 while the mean for the first month is only 10.83 and the second is 12.04.
The min, max, median and mean for the minute sleep were very similar in both months.
Relationship between total steps and calories
ggplot(data=daily_activity_3, aes(x=TotalSteps, y= Calories))+
geom_point(color ="green")+
geom_smooth(method = "loess") +
ggtitle("Total Steps vs Calories (March-April)") +
theme(plot.title = element_text(hjust = 0.5))
## `geom_smooth()` using formula = 'y ~ x'
ggplot(data=daily_activity_4, aes(x=TotalSteps, y= Calories))+
geom_point(color="red")+
geom_smooth(method = "loess") +
ggtitle("Total Steps vs Calories (April-May)") +
theme(plot.title = element_text(hjust = 0.5))
## `geom_smooth()` using formula = 'y ~ x'
As would be expected in both graphs the more steps taken equals more
calories burned.
Relationship between time and calories First need to separate the time and date for visualization purposes
hourly_calories_3$ActivityHour=as.POSIXct(hourly_calories_3$ActivityHour, format="%m/%d/%Y %I:%M:%S %p", tz=Sys.timezone())
hourly_calories_3$time <- format(hourly_calories_3$ActivityHour, format = "%H:%M:%S")
hourly_calories_3$date <- format(hourly_calories_3$ActivityHour, format = "%m/%d/%y")
hourly_calories_4$ActivityHour=as.POSIXct(hourly_calories_4$ActivityHour, format="%m/%d/%Y %I:%M:%S %p", tz=Sys.timezone())
hourly_calories_4$time <- format(hourly_calories_4$ActivityHour, format = "%H:%M:%S")
hourly_calories_4$date <- format(hourly_calories_4$ActivityHour, format = "%m/%d/%y")
calories_3 <- hourly_calories_3 %>%
group_by(time) %>%
drop_na() %>%
summarise(mean_calories_3 = mean(Calories))
ggplot(data=calories_3) +
geom_histogram(aes(x=time, y=mean_calories_3), fill="green", stat="identity")+
theme(axis.text.x = element_text(angle=90))+
ggtitle("Calories vs Time (March-April)") +
theme(plot.title = element_text(hjust = 0.5))
## Warning in geom_histogram(aes(x = time, y = mean_calories_3), fill = "green", :
## Ignoring unknown parameters: `binwidth`, `bins`, and `pad`
calories_4 <- hourly_calories_4 %>%
group_by(time) %>%
drop_na() %>%
summarise(mean_calories_4 = mean(Calories))
ggplot(data=calories_4) +
geom_histogram(aes(x=time, y=mean_calories_4), fill="red", stat="identity")+
theme(axis.text.x = element_text(angle=90))+
ggtitle("Calories vs Time (April-May)") +
theme(plot.title = element_text(hjust = 0.5))
## Warning in geom_histogram(aes(x = time, y = mean_calories_4), fill = "red", :
## Ignoring unknown parameters: `binwidth`, `bins`, and `pad`
Both graphs are very similar in shape. We can see that most calories are
burned from 7 am to 9 pm which makes sense since this is when people are
normally awake. The most calories are burned at 7 pm in March to April
and at 6 pm in April to May so similar times.
Merging calories and intensities First we must make the data formats match for the datasets
hourly_intensities_3$ActivityHour=as.POSIXct(hourly_intensities_3$ActivityHour, format="%m/%d/%Y %I:%M:%S %p", tz=Sys.timezone())
hourly_intensities_3$time <- format(hourly_intensities_3$ActivityHour, format = "%H:%M:%S")
hourly_intensities_3$date <- format(hourly_intensities_3$ActivityHour, format = "%m/%d/%y")
hourly_intensities_4$ActivityHour=as.POSIXct(hourly_intensities_4$ActivityHour, format="%m/%d/%Y %I:%M:%S %p", tz=Sys.timezone())
hourly_intensities_4$time <- format(hourly_intensities_4$ActivityHour, format = "%H:%M:%S")
hourly_intensities_4$date <- format(hourly_intensities_4$ActivityHour, format = "%m/%d/%y")
calories_intensities_3 <- merge(hourly_calories_3, hourly_intensities_3, by=c('Id','ActivityHour'))
calories_intensities_4 <- merge(hourly_calories_4, hourly_intensities_4, by=c('Id','ActivityHour'))
Graphing the merged data
ggplot(data=calories_intensities_3, aes(x=TotalIntensity, y= Calories))+
geom_point(color ="green")+
geom_smooth(method = "loess") +
ggtitle("Calories vs Intensities (March-April)") +
theme(plot.title = element_text(hjust = 0.5))
## `geom_smooth()` using formula = 'y ~ x'
ggplot(data=calories_intensities_4, aes(x=TotalIntensity, y= Calories))+
geom_point(color="red")+
geom_smooth(method = "loess") +
ggtitle("Calories vs Intensities (April-May)") +
theme(plot.title = element_text(hjust = 0.5))
## `geom_smooth()` using formula = 'y ~ x'
As expected in both graphs the higher the intensity, the more calories
burned. The graph seems to be starting to take more of an exponential
curve than a linear one.
After going through the data we come back to the initial question of how non-Bellabeat smart devices are used to be able to better market Bellabeat products. We used the [Fitbit data] (https://www.kaggle.com/datasets/arashnic/fitbit/data) to draw some conclusions.
The percentage for the tracker being used for the whole day and 2/3rds of the day went up from the first month of tracking data to the second month. So did the total number of steps. So one recommendation I would make is for the Bellabeat app to have a notification in the morning to remember your tracker. By remembering your tracker you’re going to be more cautious about meeting your daily goal of steps so more likely to meet that goal.
More steps means more calories burned so having products or app giving users a reminder about number of steps could help users reach their end goal. When giving reminder could also give suggestions on how to higher intensity to help burn more calories.
In the steps, distance, calorie, total intensity and average intensity we saw an increase in the mean from the first month to the second month while seeing a decrease in the mean of sedentary minutes from the first month to the second. So by ads, products and app helping to get users into a routine with tips and info on a healthy lifestyle will help them to continue to grow.