1. Summary of the Business Task

analyze user activity data to provide insights and recommendations that can enhance product usage and customer satisfaction.

2. Description of Data Sources

The primary dataset used is here.

containing information on daily activity metrics such as steps taken, active minutes, sedentary minutes, and calories burned, among others.

2. Exploring the data in dailyActivity_merged dataset

data <- read.csv("dailyActivity_merged.csv")

colnames(data)
##  [1] "Id"                       "ActivityDate"            
##  [3] "TotalSteps"               "TotalDistance"           
##  [5] "TrackerDistance"          "LoggedActivitiesDistance"
##  [7] "VeryActiveDistance"       "ModeratelyActiveDistance"
##  [9] "LightActiveDistance"      "SedentaryActiveDistance" 
## [11] "VeryActiveMinutes"        "FairlyActiveMinutes"     
## [13] "LightlyActiveMinutes"     "SedentaryMinutes"        
## [15] "Calories"

3. Documentation of Data Cleaning or Manipulation

Converted ActivityDate column to Date format

data$ActivityDate <- as.Date(data$ActivityDate, format = "%m/%d/%Y")
str(data)
## 'data.frame':    940 obs. of  15 variables:
##  $ Id                      : num  1.5e+09 1.5e+09 1.5e+09 1.5e+09 1.5e+09 ...
##  $ ActivityDate            : Date, format: "2016-04-12" "2016-04-13" ...
##  $ TotalSteps              : int  13162 10735 10460 9762 12669 9705 13019 15506 10544 9819 ...
##  $ TotalDistance           : num  8.5 6.97 6.74 6.28 8.16 ...
##  $ TrackerDistance         : num  8.5 6.97 6.74 6.28 8.16 ...
##  $ LoggedActivitiesDistance: num  0 0 0 0 0 0 0 0 0 0 ...
##  $ VeryActiveDistance      : num  1.88 1.57 2.44 2.14 2.71 ...
##  $ ModeratelyActiveDistance: num  0.55 0.69 0.4 1.26 0.41 ...
##  $ LightActiveDistance     : num  6.06 4.71 3.91 2.83 5.04 ...
##  $ SedentaryActiveDistance : num  0 0 0 0 0 0 0 0 0 0 ...
##  $ VeryActiveMinutes       : int  25 21 30 29 36 38 42 50 28 19 ...
##  $ FairlyActiveMinutes     : int  13 19 11 34 10 20 16 31 12 8 ...
##  $ LightlyActiveMinutes    : int  328 217 181 209 221 164 233 264 205 211 ...
##  $ SedentaryMinutes        : int  728 776 1218 726 773 539 1149 775 818 838 ...
##  $ Calories                : int  1985 1797 1776 1745 1863 1728 1921 2035 1786 1775 ...

4. Checked for and handled duplicated rows and null values (none found in this case).

#cleaning: check for duplicated rows

duplicate <- data[duplicated(data), ]
print(duplicate) #no duplicate
##  [1] Id                       ActivityDate             TotalSteps              
##  [4] TotalDistance            TrackerDistance          LoggedActivitiesDistance
##  [7] VeryActiveDistance       ModeratelyActiveDistance LightActiveDistance     
## [10] SedentaryActiveDistance  VeryActiveMinutes        FairlyActiveMinutes     
## [13] LightlyActiveMinutes     SedentaryMinutes         Calories                
## <0 rows> (or 0-length row.names)
#cleaning: check for null values

is_null <- is.na(data)

data <- na.omit(data)

5. Subsetting the dataset (removing unecessory columns)

subset_data <- data[, c("Id", "ActivityDate", "TotalSteps", "VeryActiveMinutes", "FairlyActiveMinutes", "LightlyActiveMinutes", "SedentaryMinutes", "Calories")]

copy_of_subset <- data.frame(subset_data)

colnames(copy_of_subset)
## [1] "Id"                   "ActivityDate"         "TotalSteps"          
## [4] "VeryActiveMinutes"    "FairlyActiveMinutes"  "LightlyActiveMinutes"
## [7] "SedentaryMinutes"     "Calories"

Created categorical variables (ActivityState and RateHours) to segment users

based on activity levels and total hours of watch usage, respectively.

##           Id ActivityDate TotalSteps VeryActiveMinutes FairlyActiveMinutes
## 1 1503960366   2016-04-12      13162                25                  13
## 2 1503960366   2016-04-13      10735                21                  19
## 3 1503960366   2016-04-14      10460                30                  11
## 4 1503960366   2016-04-15       9762                29                  34
## 5 1503960366   2016-04-16      12669                36                  10
## 6 1503960366   2016-04-17       9705                38                  20
##   LightlyActiveMinutes SedentaryMinutes Calories ActivityState TotalHours
## 1                  328              728     1985        active         18
## 2                  217              776     1797        active         17
## 3                  181             1218     1776        active         24
## 4                  209              726     1745        normal         16
## 5                  221              773     1863        active         17
## 6                  164              539     1728        normal         12
##   RateHours
## 1       low
## 2       low
## 3      high
## 4       low
## 5       low
## 6    medium

Visualization: Relationship Between Activity Levels and Calories Burned

ggplot(data = subset_data) +
  geom_point(mapping = aes(x = ActivityState, y= Calories, color= ActivityState)) + 
  labs(title = "Relationship Between Calories Burned and Activity State") +
  theme_minimal() +
  theme(plot.title = element_text(size= 16, face= "bold"),
        axis.title = element_text(size = 12),
        legend.title = element_text(size = 12),
        legend.text = element_text(size = 10)) 

Calculte average steps per a day

subset_data$day_of_week <- weekdays(subset_data$ActivityDate)

average_steps_per_weekday <- subset_data %>%
  group_by(day_of_week) %>%
  summarize(avg_steps = mean(TotalSteps))

Visualizing Weekly Steps

q<- ggplot(data = average_steps_per_weekday, aes(x= day_of_week, y= avg_steps)) +
  geom_bar(stat= "identity", fill= "skyblue", color= "black")+
  labs(title= "Average Steps by Day of the Week",
       x = "Day of the Week",
       y = "Average Steps",
       caption = "Data source: dailyActivity_merged.csv")+
       theme_minimal() +  # Optional: Customize theme
       scale_y_continuous(labels = scales::comma)  # Optional: Format y-axis labels
      
q + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

Note:

  • Users are most active on Saturdays.

  • Users tend to be less active on Sundays

Calculating and Visualizing Activity Percentages

The percentage of each activity typesand visualize it using a pie chart

# Calculate the sum of each column
sums <- subset_data %>%
  summarise(
    VeryActiveMinutes = sum(VeryActiveMinutes),
    FairlyActiveMinutes = sum(FairlyActiveMinutes),
    LightlyActiveMinutes = sum(LightlyActiveMinutes),
    SedentaryMinutes = sum(SedentaryMinutes)
  )

# Convert to a long format and calculate percentages
df <- sums %>%
  gather(key = "ActivityType", value = "Value") %>%
  mutate(Percentage = Value / sum(Value) * 100)

# Plot pie chart
ggplot(df, aes(x = "", y = Percentage, fill = ActivityType)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_stack(vjust = 0.5), 
            size = 3) +
  labs(
    title = "Percentage Distribution of Activity Minutes",
    fill = "Activity Type",
    caption = "Data source: Your Source Name"
  ) +
  theme_void()

Note:

  • significant portion of sedentary time may be due to sleep

Analyze the correlation between different activity types and calories burned

# Make the labels smaller
adjuste <- theme(
  axis.title.x = element_text(size = 5),  # Adjust x-axis label size
  axis.title.y = element_text(size = 5)   # Adjust y-axis label size
)

# Create individual scatter plots without using color mapping for activity minutes

p1 <- ggplot(data = subset_data) + 
  geom_point(mapping = aes(x = FairlyActiveMinutes, y = Calories, color = Calories), size= 0.3) +
  labs(x = "Fairly Active Minutes", y = "Calories") + 
  guides(color= FALSE) + adjuste
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
p2 <- ggplot(data = subset_data) + 
  geom_point(mapping = aes(x = VeryActiveMinutes, y = Calories, color = Calories), size= 0.3) +
  labs(x = "Very Active Minutes", y = "Calories") + 
  guides(color= FALSE) + adjuste

p3 <- ggplot(data = subset_data) + 
  geom_point(mapping = aes(x = LightlyActiveMinutes, y = Calories, color = Calories), size= 0.3) +
  labs(x = "Lightly Active Minutes", y = "Calories") +
  guides(color= FALSE)+ adjuste

p4 <- ggplot(data = subset_data) + 
  geom_point(mapping = aes(x = SedentaryMinutes, y = Calories, color = "Calories"), size= 0.3) +
  labs(x = "Sedentary Minutes", y = "Calories") + 
  guides(color= FALSE)+ adjuste

# Arrange the plots in a 2x2 grid
grid.arrange(p1, p2, p3, p4, ncol = 2)

Note:

  • Users with higher sedentary activity burn fewer calories

  • Highly active users burn significantly more calories.

  • There is no significant correlation between lightly active or fairly active minutes and calories burned.

Conclusion

Overall, the data highlights the need for personalized interventions and community-driven initiatives to enhance user engagement and promote healthier lifestyles.

Recommendations