Bellabeat Capstone Project For Google Data Analysis Certificate

Introduction

This is the optional capstone project for the completion of the Google Data Analysis Certificate. I have chosen the Case study 2 which is about analyzing competition data of Bellabeat health products. we will go into the scenario and details in the next steps.

Scenario

You are a junior data analyst working on the marketing analyst team at Bellabeat, a high-tech manufacturer of health-focused products for women. Bellabeat is a successful small company, but they have the potential to become a larger player in the global smart device market. Urška Sršen, cofounder and Chief Creative Officer of Bellabeat, believes that analyzing smart device fitness data could help unlock new growth opportunities for the company.

You have been asked to focus on one of Bellabeat’s products and analyze smart device data to gain insight into how consumers are using their smart devices. The insights you discover will then help guide marketing strategy for the company. You will present your analysis to the Bellabeat executive team along with your high-level recommendations for Bellabeat’s marketing strategy.

Installing and loading common packages and libraries
install.packages("vctrs",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## Warning: cannot remove prior installation of package 'vctrs'
## Warning in file.copy(savedcopy, lib, recursive = TRUE): problem copying
## C:\Users\George
## Karam\AppData\Local\R\win-library\4.2\00LOCK\vctrs\libs\x64\vctrs.dll to
## C:\Users\George Karam\AppData\Local\R\win-library\4.2\vctrs\libs\x64\vctrs.dll:
## Permission denied
## Warning: restored 'vctrs'
install.packages("tidyverse",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## also installing the dependencies 'conflicted', 'cli', 'dplyr', 'forcats', 'ggplot2', 'lubridate', 'readr', 'readxl'
## Warning: cannot remove prior installation of package 'cli'
## Warning in file.copy(savedcopy, lib, recursive = TRUE): problem copying
## C:\Users\George
## Karam\AppData\Local\R\win-library\4.2\00LOCK\cli\libs\x64\cli.dll to
## C:\Users\George Karam\AppData\Local\R\win-library\4.2\cli\libs\x64\cli.dll:
## Permission denied
## Warning: restored 'cli'
## Warning: cannot remove prior installation of package 'dplyr'
## Warning in file.copy(savedcopy, lib, recursive = TRUE): problem copying
## C:\Users\George
## Karam\AppData\Local\R\win-library\4.2\00LOCK\dplyr\libs\x64\dplyr.dll to
## C:\Users\George Karam\AppData\Local\R\win-library\4.2\dplyr\libs\x64\dplyr.dll:
## Permission denied
## Warning: restored 'dplyr'
install.packages("tidyr",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
install.packages("ggplot2",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
install.packages("dplyr",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## Warning: cannot remove prior installation of package 'dplyr'
## Warning in file.copy(savedcopy, lib, recursive = TRUE): problem copying
## C:\Users\George
## Karam\AppData\Local\R\win-library\4.2\00LOCK\dplyr\libs\x64\dplyr.dll to
## C:\Users\George Karam\AppData\Local\R\win-library\4.2\dplyr\libs\x64\dplyr.dll:
## Permission denied
## Warning: restored 'dplyr'
install.packages("lubridate",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
install.packages("janitor",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
install.packages("ggVennDiagram",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
install.packages("plotrix",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
install.packages("corrplot",repos = "http://cran.us.r-project.org")
## Installing package into 'C:/Users/George Karam/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
Loading Libraries
library(vctrs)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.0.10     ✔ readr     2.1.4 
## ✔ forcats   1.0.0      ✔ stringr   1.5.0 
## ✔ ggplot2   3.4.1      ✔ tibble    3.1.8 
## ✔ lubridate 1.9.2      ✔ tidyr     1.3.0 
## ✔ purrr     1.0.1      
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::data_frame() masks tibble::data_frame(), vctrs::data_frame()
## ✖ dplyr::filter()     masks stats::filter()
## ✖ dplyr::lag()        masks stats::lag()
## ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(tidyr)
library(ggplot2)
library(lubridate)
library(dbplyr)
## 
## Attaching package: 'dbplyr'
## 
## The following objects are masked from 'package:dplyr':
## 
##     ident, sql
library(janitor)
## 
## Attaching package: 'janitor'
## 
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
library(plotrix)
library(ggVennDiagram)
library(corrplot)
## corrplot 0.92 loaded

Data

The Dataset provided is from Kaggle and is the FitBit Fitness Tracker Data (CC0: Public Domain, dataset made available through Mobius). The Data is from thirty eligible fitibit users and contains information about daily activity, sleep, weight and heart rate.

Loading CSV files
activity_users <- read.csv("dailyActivity_merged.csv")
sleep_users <- read.csv("sleepDay_merged.csv")
weight_log_users <-read.csv("weightLogInfo_merged.csv")
heart_rate <- read.csv("heartrate_seconds_merged.csv")
Exploring a few key tables

Taking a look at the data.

head(activity_users)
##           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
head(sleep_users)
##           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(weight_log_users)
##           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
head(heart_rate)
##           Id                 Time Value
## 1 2022484408 4/12/2016 7:21:00 AM    97
## 2 2022484408 4/12/2016 7:21:05 AM   102
## 3 2022484408 4/12/2016 7:21:10 AM   105
## 4 2022484408 4/12/2016 7:21:20 AM   103
## 5 2022484408 4/12/2016 7:21:25 AM   101
## 6 2022484408 4/12/2016 7:22:05 AM    95
Identify column names in data.
colnames(activity_users)
##  [1] "Id"                       "ActivityDate"            
##  [3] "TotalSteps"               "TotalDistance"           
##  [5] "TrackerDistance"          "LoggedActivitiesDistance"
##  [7] "VeryActiveDistance"       "ModeratelyActiveDistance"
##  [9] "LightActiveDistance"      "SedentaryActiveDistance" 
## [11] "VeryActiveMinutes"        "FairlyActiveMinutes"     
## [13] "LightlyActiveMinutes"     "SedentaryMinutes"        
## [15] "Calories"
colnames(sleep_users)
## [1] "Id"                 "SleepDay"           "TotalSleepRecords" 
## [4] "TotalMinutesAsleep" "TotalTimeInBed"
colnames(weight_log_users)
## [1] "Id"             "Date"           "WeightKg"       "WeightPounds"  
## [5] "Fat"            "BMI"            "IsManualReport" "LogId"
colnames(heart_rate)
## [1] "Id"    "Time"  "Value"
Identifying distinct ids in each of the tracked functions.
n_distinct(activity_users$Id)
## [1] 33
n_distinct(sleep_users$Id)
## [1] 24
n_distinct(weight_log_users$Id)
## [1] 8
n_distinct(heart_rate$Id)
## [1] 14

First impressions about the data is that it’s very limited and incomplete. the data is supposed to represent 30 users but we identified 33 distinct ids in the daily activity table, and not all users are using all the features of the smart device.

Cleaning Data

Here we will clean the 4 different data frames we will be working with. we will convert all column names to snake_case make sure every row is distinct. We will use mutate to add new columns to summarize some data and standardize dates to be able to merge later on. And we will select which variables we want to work with. and we will print our findings.

Activity Table
activity_cleaned <- activity_users %>% 
  clean_names() %>% 
  distinct() %>% 
  mutate(total_active_minutes = 
           very_active_minutes + fairly_active_minutes + 
           lightly_active_minutes ) %>%
  mutate(date_new = as.Date(mdy(activity_date))) %>% 
  mutate(id = as.character(id)) %>% 
  select(id, date_new, total_steps, total_active_minutes,sedentary_minutes, calories)

print(paste0("Number of rows in Activity Table before cleaning: " , nrow(activity_users), " and after cleaning: " , nrow(activity_cleaned)))
## [1] "Number of rows in Activity Table before cleaning: 940 and after cleaning: 940"
print(paste0("duplicate rows : " , nrow(activity_users) - nrow(activity_cleaned)))
## [1] "duplicate rows : 0"
print(paste0("Distinct Ids in Activity Table before cleaning: " , n_distinct(activity_users$Id), " and after cleaning: " , n_distinct(activity_cleaned$id)))
## [1] "Distinct Ids in Activity Table before cleaning: 33 and after cleaning: 33"
Weight log table
weight_cleaned <- weight_log_users %>% 
  clean_names() %>% 
  distinct() %>% 
  mutate(date_new = as.Date(mdy_hms(date))) %>% 
  mutate(id = as.character(id)) %>% # convert id to string
  select(id, date_new, weight_kg, bmi) 

print(paste0("Number of rows in Weight Table before cleaning: " , nrow(weight_log_users), " and after cleaning: " , nrow(weight_cleaned)))
## [1] "Number of rows in Weight Table before cleaning: 67 and after cleaning: 67"
print(paste0("duplicate rows : " , nrow(weight_log_users) - nrow(weight_cleaned)))
## [1] "duplicate rows : 0"
print(paste0("Distinct Ids in Activity Table before cleaning: " , n_distinct(weight_log_users$Id), " and after cleaning: " , n_distinct(weight_cleaned$id)))
## [1] "Distinct Ids in Activity Table before cleaning: 8 and after cleaning: 8"
Sleep Table
sleep_cleaned <- sleep_users %>% 
  clean_names() %>% 
  distinct() %>% 
  mutate(id = as.character(id)) %>% 
  mutate(date_new = as.Date(mdy_hms(sleep_day))) %>% 
  select(id,date_new, total_minutes_asleep,total_time_in_bed)
print(paste0("Number of rows in Sleep Table before cleaning: " , nrow(sleep_users), " and after cleaning: " , nrow(sleep_cleaned)))

print(paste0("duplicate rows : " , nrow(sleep_users) - nrow(sleep_cleaned)))

print(paste0("Distinct Ids in Activity Table before cleaning: " , n_distinct(sleep_users$Id), " and after cleaning: " , n_distinct(sleep_cleaned$id)))
Heart Rate Table
heart_rate_cleaned <- heart_rate %>% 
  clean_names() %>% 
  distinct() %>%  
  mutate(id = as.character(id)) 

heart_rate_cleaned <- separate(heart_rate_cleaned, time, c("date_new", "time"), sep = " ")

heart_rate_cleaned %>% 
  mutate(date_new = as.Date(mdy(date_new)))
print(paste0("Number of rows in heart rate Table before cleaning: " , nrow(heart_rate), " and after cleaning: " , nrow(heart_rate_cleaned)))
## [1] "Number of rows in heart rate Table before cleaning: 2483658 and after cleaning: 2483658"
print(paste0("duplicate rows : " , nrow(heart_rate) - nrow(heart_rate_cleaned)))
## [1] "duplicate rows : 0"
print(paste0("Distinct Ids in Activity Table before cleaning: " , n_distinct(heart_rate$Id), " and after cleaning: " , n_distinct(heart_rate_cleaned$id)))
## [1] "Distinct Ids in Activity Table before cleaning: 14 and after cleaning: 14"

Analysing and Sharing Data

use_frequency <- activity_cleaned %>% 
  count(id, sort = TRUE,name = "days")

Most people have used the tracker for 26 days or more

##bar plot of how are users divided

id_categories <- c(n_distinct(activity_cleaned$id),n_distinct(sleep_cleaned$id),n_distinct(heart_rate_cleaned$id), n_distinct(weight_cleaned$id))
barplot(id_categories,
main = "what features are users using the most",
xlab = "categories",
ylab = "Nmuber of Users",
names.arg = c("Activity user", "Sleep users","Heart Rate Users", "Weight Users"),
cex.names = 0.75,col = "Grey")

Venn diagram to show how users intersect

activity_cleaned_ids <- unique(activity_cleaned$id)
sleep_cleaned_id <- unique(sleep_cleaned$id)
weight_cleaned_id <- unique(weight_cleaned$id)
heart_rate_cleaned_id <- unique(heart_rate_cleaned$id) 
library(ggvenn)
## Loading required package: grid
x = list(activity_cleaned_ids,sleep_cleaned_id,heart_rate_cleaned_id,weight_cleaned_id)
ggVennDiagram(x , category.names = c("Activity user", "Sleep users","Heart Rate Users", "Weight Users")) + scale_fill_gradient(low = "#F4FAFE", high = "#4981BF") + scale_x_continuous(expand = expansion(mult = .2)) 

#### Only 3 users out of the 33 users are using the full functionality of the smart device which is around 9%. we have to keep in mind that the sample size is too small to generalized results.

Creating summary for heart rate by daily average

heart_rate_summary <- heart_rate_cleaned %>% 
  group_by(id,date_new) %>%
  dplyr::summarize(avg_daily_heart_rate = mean(value)) %>% 
  mutate(date_new = as.Date(mdy(date_new)))
## `summarise()` has grouped output by 'id'. You can override using the `.groups`
## argument.
n_distinct(heart_rate_summary$id)
## [1] 14

merging each of the: heart rate summary, weight and sleep table with the activity table to be able to compare each tracked category with the main activity table where calories and steps are recorded.

heart_activity<- activity_cleaned[(activity_cleaned$id %in% heart_rate_summary$id),]
heart_activity_users <- merge(heart_activity, heart_rate_summary, by.x = c("id", "date_new"),by.y = c("id", "date_new"), all = TRUE)

sleep_activity_users<- activity_cleaned[(activity_cleaned$id %in% sleep_cleaned$id),] 
sleep_activity_users<-  merge(sleep_activity_users, sleep_cleaned, by.x=c("id", "date_new"), by.y=c("id", "date_new"),all = TRUE)

weight_activity_users<-activity_cleaned[(activity_cleaned$id %in% weight_cleaned$id),]
weight_activity_users<- merge(weight_activity_users, weight_cleaned, by.x=c("id", "date_new"), by.y=c("id", "date_new"),all = TRUE)

n_distinct(heart_activity_users$id)
## [1] 14
n_distinct(sleep_activity_users$id)
## [1] 24
n_distinct(weight_activity_users$id)
## [1] 8

##findig correlation by pearsons method

cor_activity = cor(activity_cleaned[, unlist(lapply(activity_cleaned, is.numeric))], use="pairwise.complete.obs")
corrplot(cor_activity, method="number", type = "lower",title = ("Activity Cor."),tl.cex = 0.9, tl.srt = 0)

cor_heart = cor(heart_activity_users[, unlist(lapply(heart_activity_users, is.numeric))], use="pairwise.complete.obs")
corrplot(cor_heart, method="number", type = "lower",title = "HR Activity cor.",tl.cex = 0.9, tl.srt = 0, )

cor_weight = cor(weight_activity_users[, unlist(lapply(weight_activity_users, is.numeric))], use="pairwise.complete.obs")
corrplot(cor_weight, method="number", type = "lower", title = "weight activity cor.",tl.cex = 0.9, tl.srt = 0, )

cor_sleep = cor(sleep_activity_users[, unlist(lapply(sleep_activity_users, is.numeric))], use="pairwise.complete.obs")
corrplot(cor_sleep, method="number", type = "lower", title = "sleep activity cor.",tl.cex = 0.9, tl.srt = 0)

obvious correltions can be confirmed here in the matrixes created above:

- calroies are positevely correlated to total steps and active minutes 
- average daily heart rate is positively related with sedentary mintues. which means less active people tend to have a higher heart rate.
- weight is positively related to sedentary minutes. which means less active people tend to be heavier
- bmi is negatively related to active minutes and positively to sendentary minutes. a higher bmi means a person is overweight/obese. so active people tend to have a lower bmi and sedentary people tend to have a higher bmi.
- Total sleep and bed time 
Merging all tables together by id and date
all_functions_users <- activity_cleaned [((activity_cleaned$id %in% sleep_cleaned$id) & (activity_cleaned$id %in% weight_cleaned$id)  & activity_cleaned$id %in% heart_rate_summary$id),]

n_distinct(all_functions_users$id)
## [1] 3
all_functions_users <- merge(all_functions_users, weight_cleaned, by.x=c("id", "date_new"), by.y=c("id", "date_new"),all.x = TRUE)
all_functions_users <- merge(all_functions_users, sleep_cleaned, by.x=c("id", "date_new"), by.y=c("id", "date_new"),all.x = TRUE)
all_functions_users <- merge(all_functions_users, heart_rate_summary, by.x=c("id", "date_new"), by.y=c("id", "date_new"),all.x = TRUE)

n_distinct(all_functions_users$id)
## [1] 3
cor_all = cor(all_functions_users[, unlist(lapply(all_functions_users, is.numeric))], use = "pairwise.complete.obs")
corrplot(cor_all, method="number", type = "lower", title = ("All Functions"),tl.cex = 0.9, tl.srt = 0)

correlation for all functions also confirms previous findings but sample size is only 3 people.

Summary, findings and recommendations

  • After Analysing the kaggle fitbit user i have found the following:
    • the Data is old, very small sample size, 33 ids were found instead of the supposed thirty ids in the introduction. but we will consider it complete for this capstone project. only 3 ids were found to have used all functionalities of the fitibit tracker, i would have prefered a much larger sample size to be able to conclude better findings.
    • Most users are interested most to least respectively in: recording and tracking steps followed by sleep patterns then heart rate, and finally weight logging.
    • correlations found between tracking activities and health vitals with overall health and weight.
  • I would recommend to the Bellabeat Marketing the following:
    • to increase total brand awareness by targeting the highest interested people who are tracking steps, calories and sleep which are already a part of bellabeat features.
    • focus on health benefits on how tracking your activity and vitals will result in a lower bmi and lower average daily heart rate.
    • create a campaign for existing customers to increase awareness of the health benefits of using the full functionalities of the device by subscribing to the bellabeat monthly membership