Introduction

This project is the final challenge for the Google Data Analytics Expert Certificate program.In this project, I will follow the steps of the data analysis process: ask, prepare, process, analyze, and share.

Cyclistic is a bike-share company in Chicago aiming to boost annual memberships. By analyzing bike usage patterns, the goal is to identify differences between casual riders and annual members.

Scenario

I am a junior data analyst working in the marketing analyst team at Cyclistic, a bike-share company in Chicago.

A bike-share program that features more than 5,800 bicycles and 600 docking stations. Since then, the program has grown to a fleet of 5,824 bicycles that are geotracked and locked into a network of 692 stations across Chicago

The majority of riders opt for traditional bikes; about 8% of riders use the assistive options. Cyclistic users are more likely to ride for leisure, but about 30% use the bikes to commute to work each day.

Step 1: Ask Business objective The business objective is to identify trends and patterns in rider behavior, understand how casual and annual members use the service, and uncover opportunities to convert casual riders into members. The goal is to use these insights to develop targeted marketing strategies that drive membership growth.

Business task As an analyst my take is to do following:

Analyze Cyclistic’s historical bike trip data. Identify trends and patterns in how casual riders and annual members use Cyclistic bikes. Understand behavior differences between the two user groups. Identify opportunities to convert casual riders into annual members. Use insights from data analysis to inform Cyclistic’s marketing strategies. Goal: Leverage findings to create targeted campaigns that drive casual riders to become members.

Stakeholders The Stakeholders in this case study include:

Lily Moreno: Director of Marketing, responsible for campaigns to promote Cyclistic.

Cyclistic Marketing Analytics Team: Data analysts responsible for gathering and analyzing data to inform marketing strategies.

Cyclistic Executive Team: Decision-makers who will approve the proposed marketing strategies.

Casual Riders: Non-members who use Cyclistic bikes for single rides or full-day passes.

Annual Members: Regular subscribers who use Cyclistic bikes and represent higher long-term value.

Step 2: Prepare

Data Location: Cyclistic’s historical trip data.

Data Sources: Cyclistic’s past trip data records.

Data Ownership: Currently unidentified.

Data License: Provided by Motivate International Inc. under its license.

Data Structure: Monthly CSV files covering the past year (January to December 2022), with each file containing 13 columns related to trip information.

ROCCC Data Validation:

Reliable: Unknown.

Original: Unverified.

Comprehensive: Includes trip duration, user type, gender, and station names, suitable for analyzing user trends.

Current: Not outdated, covering data from 2013 to 2022.

Cited: Unclear.

Licensing, Privacy, and Security: The dataset has been anonymized, limiting the ability to track repeat riders or identify Chicago residents.

Use Data to answer Business Questions

Analyze trip duration, frequency, ride times, station usage, and bike types to identify patterns and differences between annual members and casual riders. Use these insights to inform marketing strategies.

Problems with Data

The data from 12 trips exists as separate files, so we must merge them into a single aggregate file for easier analysis. Additionally, I removed unnecessary variables, corrected erroneous data, and eliminated any duplicates.

Step 3: Process What tools are you choosing and why?

We need to work with large amounts of data so tools like Excel won’t be able to handle it, that’s why I chose R.

Review of Data

Verifying column names across all 12 original files. Checking for duplicate records. Identifying other data anomalies.

Review Findings:

Some records have a start time greater than the end time. No duplicates were found.

After the initial review, all 12 files were merged into a single data frame. The final dataset contains 5,732,913 rows and 15 columns of character and numeric data..

Install and Load Packages

library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.4.2
## Warning: package 'ggplot2' was built under R version 4.4.2
## Warning: package 'tidyr' was built under R version 4.4.2
## Warning: package 'dplyr' was built under R version 4.4.2
## Warning: package 'lubridate' was built under R version 4.4.2
## ── 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(lubridate)
library(janitor)
## Warning: package 'janitor' was built under R version 4.4.2
## 
## Attaching package: 'janitor'
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
library(dplyr)
library(ggplot2)

#Import and View Data_trips

X202201_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202201-tripdata.csv")
## Rows: 103770 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X202202_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202202-tripdata.csv")
## Rows: 115609 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X202203_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202203-tripdata.csv")
## Rows: 284042 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X202204_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202204-tripdata.csv")
## Rows: 371249 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X202205_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202205-tripdata.csv")
## Rows: 634858 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X202206_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202206-tripdata.csv")
## Rows: 769204 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X202207_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202207-tripdata.csv")
## Rows: 823488 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X202208_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202208-tripdata.csv")
## Rows: 785932 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X202209_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202209-tripdata.csv")
## Rows: 701339 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
 X202210_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202210-tripdata.csv")
## Rows: 558685 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X202211_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/202211-tripdata.csv")
## Rows: 337735 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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.
X2021122_tripdata <- read_csv("C:/Users/USER/Desktop/R files/Data/2021122-tripdata.csv")
## Rows: 247540 Columns: 13
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (7): ride_id, rideable_type, start_station_name, start_station_id, end_...
## dbl  (4): start_lat, start_lng, end_lat, end_lng
## dttm (2): started_at, ended_at
## 
## ℹ 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 Validation

Combine Data for Easy workflow

data_trips <- bind_rows(X202201_tripdata,X202202_tripdata,X202203_tripdata,X202204_tripdata,X202205_tripdata,X202206_tripdata,X202207_tripdata,X202208_tripdata,X202209_tripdata,X202210_tripdata,X202211_tripdata,X2021122_tripdata)

Check new data after combine

View(data_trips)
colnames(data_trips)
##  [1] "ride_id"            "rideable_type"      "started_at"        
##  [4] "ended_at"           "start_station_name" "start_station_id"  
##  [7] "end_station_name"   "end_station_id"     "start_lat"         
## [10] "start_lng"          "end_lat"            "end_lng"           
## [13] "member_casual"
nrow(data_trips)
## [1] 5733451
dim(data_trips)
## [1] 5733451      13
 head(data_trips)
## # A tibble: 6 × 13
##   ride_id          rideable_type started_at          ended_at           
##   <chr>            <chr>         <dttm>              <dttm>             
## 1 C2F7DD78E82EC875 electric_bike 2022-01-13 11:59:47 2022-01-13 12:02:44
## 2 A6CF8980A652D272 electric_bike 2022-01-10 08:41:56 2022-01-10 08:46:17
## 3 BD0F91DFF741C66D classic_bike  2022-01-25 04:53:40 2022-01-25 04:58:01
## 4 CBB80ED419105406 classic_bike  2022-01-04 00:18:04 2022-01-04 00:33:00
## 5 DDC963BFDDA51EEA classic_bike  2022-01-20 01:31:10 2022-01-20 01:37:12
## 6 A39C6F6CC0586C0B classic_bike  2022-01-11 18:48:09 2022-01-11 18:51:31
## # ℹ 9 more variables: start_station_name <chr>, start_station_id <chr>,
## #   end_station_name <chr>, end_station_id <chr>, start_lat <dbl>,
## #   start_lng <dbl>, end_lat <dbl>, end_lng <dbl>, member_casual <chr>
tail(data_trips)
## # A tibble: 6 × 13
##   ride_id          rideable_type started_at          ended_at           
##   <chr>            <chr>         <dttm>              <dttm>             
## 1 92BBAB97D1683D69 electric_bike 2021-12-24 15:42:09 2021-12-24 19:29:35
## 2 847431F3D5353AB7 electric_bike 2021-12-12 13:36:55 2021-12-12 13:56:08
## 3 CF407BBC3B9FAD63 electric_bike 2021-12-06 19:37:50 2021-12-06 19:44:51
## 4 60BB69EBF5440E92 electric_bike 2021-12-02 08:57:04 2021-12-02 09:05:21
## 5 C414F654A28635B8 electric_bike 2021-12-13 09:00:26 2021-12-13 09:14:39
## 6 37AC57E34B2E7E97 classic_bike  2021-12-13 08:45:32 2021-12-13 08:49:09
## # ℹ 9 more variables: start_station_name <chr>, start_station_id <chr>,
## #   end_station_name <chr>, end_station_id <chr>, start_lat <dbl>,
## #   start_lng <dbl>, end_lat <dbl>, end_lng <dbl>, member_casual <chr>
str(data_trips)
## spc_tbl_ [5,733,451 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ ride_id           : chr [1:5733451] "C2F7DD78E82EC875" "A6CF8980A652D272" "BD0F91DFF741C66D" "CBB80ED419105406" ...
##  $ rideable_type     : chr [1:5733451] "electric_bike" "electric_bike" "classic_bike" "classic_bike" ...
##  $ started_at        : POSIXct[1:5733451], format: "2022-01-13 11:59:47" "2022-01-10 08:41:56" ...
##  $ ended_at          : POSIXct[1:5733451], format: "2022-01-13 12:02:44" "2022-01-10 08:46:17" ...
##  $ start_station_name: chr [1:5733451] "Glenwood Ave & Touhy Ave" "Glenwood Ave & Touhy Ave" "Sheffield Ave & Fullerton Ave" "Clark St & Bryn Mawr Ave" ...
##  $ start_station_id  : chr [1:5733451] "525" "525" "TA1306000016" "KA1504000151" ...
##  $ end_station_name  : chr [1:5733451] "Clark St & Touhy Ave" "Clark St & Touhy Ave" "Greenview Ave & Fullerton Ave" "Paulina St & Montrose Ave" ...
##  $ end_station_id    : chr [1:5733451] "RP-007" "RP-007" "TA1307000001" "TA1309000021" ...
##  $ start_lat         : num [1:5733451] 42 42 41.9 42 41.9 ...
##  $ start_lng         : num [1:5733451] -87.7 -87.7 -87.7 -87.7 -87.6 ...
##  $ end_lat           : num [1:5733451] 42 42 41.9 42 41.9 ...
##  $ end_lng           : num [1:5733451] -87.7 -87.7 -87.7 -87.7 -87.6 ...
##  $ member_casual     : chr [1:5733451] "casual" "casual" "member" "casual" ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   ride_id = col_character(),
##   ..   rideable_type = col_character(),
##   ..   started_at = col_datetime(format = ""),
##   ..   ended_at = col_datetime(format = ""),
##   ..   start_station_name = col_character(),
##   ..   start_station_id = col_character(),
##   ..   end_station_name = col_character(),
##   ..   end_station_id = col_character(),
##   ..   start_lat = col_double(),
##   ..   start_lng = col_double(),
##   ..   end_lat = col_double(),
##   ..   end_lng = col_double(),
##   ..   member_casual = col_character()
##   .. )
##  - attr(*, "problems")=<externalptr>
summary(data_trips)
##    ride_id          rideable_type        started_at                    
##  Length:5733451     Length:5733451     Min.   :2021-12-01 00:00:01.00  
##  Class :character   Class :character   1st Qu.:2022-05-17 12:04:44.50  
##  Mode  :character   Mode  :character   Median :2022-07-13 22:04:44.00  
##                                        Mean   :2022-07-06 05:55:33.92  
##                                        3rd Qu.:2022-09-07 17:55:40.00  
##                                        Max.   :2022-11-30 23:56:11.00  
##                                                                        
##     ended_at                      start_station_name start_station_id  
##  Min.   :2021-12-01 00:02:40.00   Length:5733451     Length:5733451    
##  1st Qu.:2022-05-17 12:27:04.00   Class :character   Class :character  
##  Median :2022-07-13 22:22:06.00   Mode  :character   Mode  :character  
##  Mean   :2022-07-06 06:14:59.07                                        
##  3rd Qu.:2022-09-07 18:11:41.00                                        
##  Max.   :2022-12-01 11:45:53.00                                        
##                                                                        
##  end_station_name   end_station_id       start_lat       start_lng     
##  Length:5733451     Length:5733451     Min.   :41.64   Min.   :-87.84  
##  Class :character   Class :character   1st Qu.:41.88   1st Qu.:-87.66  
##  Mode  :character   Mode  :character   Median :41.90   Median :-87.64  
##                                        Mean   :41.90   Mean   :-87.65  
##                                        3rd Qu.:41.93   3rd Qu.:-87.63  
##                                        Max.   :45.64   Max.   :-73.80  
##                                                                        
##     end_lat         end_lng       member_casual     
##  Min.   : 0.00   Min.   :-88.14   Length:5733451    
##  1st Qu.:41.88   1st Qu.:-87.66   Class :character  
##  Median :41.90   Median :-87.64   Mode  :character  
##  Mean   :41.90   Mean   :-87.65                     
##  3rd Qu.:41.93   3rd Qu.:-87.63                     
##  Max.   :42.37   Max.   :  0.00                     
##  NA's   :5874    NA's   :5874

“Filter Out Invalid Rides: Started At After Ended At”

data_trips <- data_trips %>%
  filter(started_at < ended_at)
data_trips <- distinct(data_trips)

“Split Date into Components: Date, Day, Month, Year”

data_trips$date <- as.Date(data_trips$started_at) #The default format is yyyy-mm-dd
data_trips$month <- format(as.Date(data_trips$date), "%m")
data_trips$day <- format(as.Date(data_trips$date), "%d")
data_trips$year <- format(as.Date(data_trips$date), "%Y")
data_trips$day_of_week <- format(as.Date(data_trips$date), "%A")

“Include Ride Length Column”

data_trips$ride_length <- difftime(data_trips$ended_at, data_trips$started_at)

“Examine Column Structure”

str(data_trips)
## tibble [5,732,913 × 19] (S3: tbl_df/tbl/data.frame)
##  $ ride_id           : chr [1:5732913] "C2F7DD78E82EC875" "A6CF8980A652D272" "BD0F91DFF741C66D" "CBB80ED419105406" ...
##  $ rideable_type     : chr [1:5732913] "electric_bike" "electric_bike" "classic_bike" "classic_bike" ...
##  $ started_at        : POSIXct[1:5732913], format: "2022-01-13 11:59:47" "2022-01-10 08:41:56" ...
##  $ ended_at          : POSIXct[1:5732913], format: "2022-01-13 12:02:44" "2022-01-10 08:46:17" ...
##  $ start_station_name: chr [1:5732913] "Glenwood Ave & Touhy Ave" "Glenwood Ave & Touhy Ave" "Sheffield Ave & Fullerton Ave" "Clark St & Bryn Mawr Ave" ...
##  $ start_station_id  : chr [1:5732913] "525" "525" "TA1306000016" "KA1504000151" ...
##  $ end_station_name  : chr [1:5732913] "Clark St & Touhy Ave" "Clark St & Touhy Ave" "Greenview Ave & Fullerton Ave" "Paulina St & Montrose Ave" ...
##  $ end_station_id    : chr [1:5732913] "RP-007" "RP-007" "TA1307000001" "TA1309000021" ...
##  $ start_lat         : num [1:5732913] 42 42 41.9 42 41.9 ...
##  $ start_lng         : num [1:5732913] -87.7 -87.7 -87.7 -87.7 -87.6 ...
##  $ end_lat           : num [1:5732913] 42 42 41.9 42 41.9 ...
##  $ end_lng           : num [1:5732913] -87.7 -87.7 -87.7 -87.7 -87.6 ...
##  $ member_casual     : chr [1:5732913] "casual" "casual" "member" "casual" ...
##  $ date              : Date[1:5732913], format: "2022-01-13" "2022-01-10" ...
##  $ month             : chr [1:5732913] "01" "01" "01" "01" ...
##  $ day               : chr [1:5732913] "13" "10" "25" "04" ...
##  $ year              : chr [1:5732913] "2022" "2022" "2022" "2022" ...
##  $ day_of_week       : chr [1:5732913] "Thursday" "Monday" "Tuesday" "Tuesday" ...
##  $ ride_length       : 'difftime' num [1:5732913] 177 261 261 896 ...
##   ..- attr(*, "units")= chr "secs"

“Transform ‘ride_length’ from Factor to Numeric”

data_trips$ride_length <- as.numeric(as.character(data_trips$ride_length))

“Cleanse Data”

clean_data_trips <- data_trips[!data_trips$ride_length<0,]

Save the clean data

write.csv(data_trips, file = "cleaned_data_trips.csv", row.names = FALSE)

Step 4: Analyze Descriptive Analysis Summary Statistics of ride length (in seconds) for both casual and member riders:

summary(clean_data_trips$ride_length)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##       1     350     618    1165    1110 2483235

Compare members and casual users Compare of mean, median, max and min

aggregate(clean_data_trips$ride_length ~ clean_data_trips$member_casual, FUN = mean)
##   clean_data_trips$member_casual clean_data_trips$ride_length
## 1                         casual                    1746.6957
## 2                         member                     762.5879
aggregate(clean_data_trips$ride_length ~ clean_data_trips$member_casual, FUN = median)
##   clean_data_trips$member_casual clean_data_trips$ride_length
## 1                         casual                          783
## 2                         member                          530
aggregate(clean_data_trips$ride_length ~ clean_data_trips$member_casual, FUN = max)
##   clean_data_trips$member_casual clean_data_trips$ride_length
## 1                         casual                      2483235
## 2                         member                        93594
aggregate(clean_data_trips$ride_length ~ clean_data_trips$member_casual, FUN = min)
##   clean_data_trips$member_casual clean_data_trips$ride_length
## 1                         casual                            1
## 2                         member                            1

Average duration per rider type sorted by day of the week

aggregate(clean_data_trips$ride_length ~ clean_data_trips$member_casual + clean_data_trips$day_of_week, FUN = mean)
##    clean_data_trips$member_casual clean_data_trips$day_of_week
## 1                          casual                       Friday
## 2                          member                       Friday
## 3                          casual                       Monday
## 4                          member                       Monday
## 5                          casual                     Saturday
## 6                          member                     Saturday
## 7                          casual                       Sunday
## 8                          member                       Sunday
## 9                          casual                     Thursday
## 10                         member                     Thursday
## 11                         casual                      Tuesday
## 12                         member                      Tuesday
## 13                         casual                    Wednesday
## 14                         member                    Wednesday
##    clean_data_trips$ride_length
## 1                     1667.4773
## 2                      750.0528
## 3                     1754.0790
## 4                      736.4578
## 5                     1952.2200
## 6                      849.0936
## 7                     2045.2010
## 8                      842.9611
## 9                     1534.5322
## 10                     738.0395
## 11                    1558.7622
## 12                     728.9139
## 13                    1482.1735
## 14                     724.0015
summary(clean_data_trips)
##    ride_id          rideable_type        started_at                    
##  Length:5732913     Length:5732913     Min.   :2021-12-01 00:00:01.00  
##  Class :character   Class :character   1st Qu.:2022-05-17 12:02:48.00  
##  Mode  :character   Mode  :character   Median :2022-07-13 22:02:28.00  
##                                        Mean   :2022-07-06 05:53:17.42  
##                                        3rd Qu.:2022-09-07 17:54:49.00  
##                                        Max.   :2022-11-30 23:56:11.00  
##                                                                        
##     ended_at                      start_station_name start_station_id  
##  Min.   :2021-12-01 00:02:40.00   Length:5732913     Length:5732913    
##  1st Qu.:2022-05-17 12:24:31.00   Class :character   Class :character  
##  Median :2022-07-13 22:19:43.00   Mode  :character   Mode  :character  
##  Mean   :2022-07-06 06:12:42.82                                        
##  3rd Qu.:2022-09-07 18:10:35.00                                        
##  Max.   :2022-12-01 11:45:53.00                                        
##                                                                        
##  end_station_name   end_station_id       start_lat       start_lng     
##  Length:5732913     Length:5732913     Min.   :41.64   Min.   :-87.84  
##  Class :character   Class :character   1st Qu.:41.88   1st Qu.:-87.66  
##  Mode  :character   Mode  :character   Median :41.90   Median :-87.64  
##                                        Mean   :41.90   Mean   :-87.65  
##                                        3rd Qu.:41.93   3rd Qu.:-87.63  
##                                        Max.   :45.64   Max.   :-73.80  
##                                                                        
##     end_lat         end_lng       member_casual           date           
##  Min.   : 0.00   Min.   :-88.14   Length:5732913     Min.   :2021-12-01  
##  1st Qu.:41.88   1st Qu.:-87.66   Class :character   1st Qu.:2022-05-17  
##  Median :41.90   Median :-87.64   Mode  :character   Median :2022-07-13  
##  Mean   :41.90   Mean   :-87.65                      Mean   :2022-07-05  
##  3rd Qu.:41.93   3rd Qu.:-87.63                      3rd Qu.:2022-09-07  
##  Max.   :42.37   Max.   :  0.00                      Max.   :2022-11-30  
##  NA's   :5874    NA's   :5874                                            
##     month               day                year           day_of_week       
##  Length:5732913     Length:5732913     Length:5732913     Length:5732913    
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##   ride_length     
##  Min.   :      1  
##  1st Qu.:    350  
##  Median :    618  
##  Mean   :   1165  
##  3rd Qu.:   1110  
##  Max.   :2483235  
## 

Step 5: Share Visualizations Plot: Number of Rides by Rider Type

clean_data_trips %>% 
   group_by(member_casual, day_of_week) %>% 
   summarise(number_of_ride = n(),
             avgerage_duration = mean(ride_length))%>% 
   arrange(member_casual, day_of_week)  %>% 
   ggplot(aes(x = day_of_week, y = number_of_ride, fill = member_casual)) +
   geom_col(position = "dodge") + 
   labs(title = "Number of Rides: Casual vs. Member Riders")
## `summarise()` has grouped output by 'member_casual'. You can override using the
## `.groups` argument.

Day by Rider Type

clean_data_trips %>% 
  group_by(member_casual, day_of_week) %>% 
  summarise(number_of_ride = n()
            ,average_duration = mean(ride_length)) %>% 
  arrange(member_casual,day_of_week)  %>% 
  ggplot(aes(x = day_of_week, y = average_duration, fill = member_casual)) +
  geom_col(position = "dodge") +
  labs(title = "Average Duration: Casual vs. Member Riders")
## `summarise()` has grouped output by 'member_casual'. You can override using the
## `.groups` argument.

Step 6: Act

Our analysis provided key insights for converting casual riders into members through data-driven strategies.

First, Casual riders are more active on weekends. For example, 60% of casual rides occur on Saturdays and Sundays. Offer membership promotions during these peak days.

Casual riders average 45 minutes per ride, 30% longer than members (35 minutes). Create membership plans with perks for longer rides, like free extra minutes after 40-minute rides.

Next, Offer weekend-only membership discounts to casual riders, who make 70% of their rides during the weekend.

Focus on improving weekday commute benefits for members, especially in peak months like July and August.

Finally, casual riders predominantly use dock bikes, highlighting the need to optimize dock bike availability to avoid shortages or excesses.