Table of Contents:

  1. Introduction
  2. Scenario
  3. The Goal of this case Study
  4. Ask
  5. Prepare
  6. Process
  7. Analyze
  8. Share
  9. Conclusion

Introduction

Welcome to the Cyclistic bike-share analysis case study! In this case study, we delve into the operations of Cyclistic, a prominent bike-share company based in Chicago. The objective of this analysis is to understand how different types of riders, including annual members and casual riders ,Utilize Cyclistic bikes and uncover insights that can inform the development of a new marketing strategy and make recommendations .

We will study on history of trip , we will follow the data analysis process, encompassing various steps such as ask, prepare, process, analyze, share, and act . By employing a data-driven approach, we will gain valuable insights into rider behavior and devise effective strategies to drive Cyclistic’s success in the bike-sharing market. We will perform on R to handle data and Tableau for data Visualization.

Scenario

As a junior data analyst, and the director of marketing believes the company’s future success depends on maximizing the number of annual memberships. Therefore,our team wants to understand how casual riders and annual members use Cyclistic bikes differently. then i do marketing strategies to maximize annual memberships or persuade casual rudders to be annual memberships

The Goal of this case Study

Three questions will guide the future marketing program:

  1. How do annual members and casual riders use Cyclistic bikes differently?

  2. Why would casual riders buy Cyclistic annual memberships?

  3. How can Cyclistic use digital media to influence casual riders to become members?

The director of marketing has assigned me the first question to answer: How do annual members and casual riders use Cyclistic bikes differently?

In this assignment, I will produce a report with the following deliverables:

1. A clear statement of the business task
2. A description of all data sources used
3. Documentation of any cleaning or manipulation of data
4. A summary of my analysis
5. Supporting visualizations and key findings
6. Your top three recommendations based on your analysis

Ask

Objective: Maximize the number of annual memberships by identifying and analyzing trends and patterns among casual riders and membership riders. The aim is to identify potential casual riders who could benefit from converting to annual memberships. Importantly, raising awareness of the membership program among casual riders is not necessary, as they are already familiar with the offering.

Stakeholder Expectations

The stakeholders expect the creation of strategic marketing initiatives focused on converting casual riders into annual members. This requires a comprehensive understanding of:

The marketing team will utilize historical bike trip data from Cyclistic to identify relevant trends and insights.

Prepare

### DATA TYPE check’

ROOOC Check

Sampling bias
Observer bias
Interpretation bias
Confirmation bias

About the data set:

Since Cyclistic is a fictional company, I will use Divvy’s, a bike-share program based in Chicago, data from May 2020 – April 2021 to complete this case study. To download the data, please use this link. This data was made public by Motivate International Inc, under this license. Due to data privacy issues, personal information has been removed or encrypted.

library(tidyverse)  #helps wrangle data
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.4.4     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.0
## ✔ 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)  #helps wrangle date attributes
library(ggplot2)  #helps visualize data
library(dplyr) #helps clean data
library(tidyr) #helps clean data
# Load the trip dataset entire a year of 2023

data_2023_1<- read.csv("Dataset for Case Study 1/202301-divvy-tripdata.csv")
data_2023_2<- read.csv("Dataset for Case Study 1/202302-divvy-tripdata.csv")
data_2023_3<- read.csv("Dataset for Case Study 1/202303-divvy-tripdata.csv")
data_2023_4<- read.csv("Dataset for Case Study 1/202304-divvy-tripdata.csv")
data_2023_5<- read.csv("Dataset for Case Study 1/202305-divvy-tripdata.csv")
data_2023_6<- read.csv("Dataset for Case Study 1/202306-divvy-tripdata.csv")
data_2023_7<- read.csv("Dataset for Case Study 1/202307-divvy-tripdata.csv")
data_2023_8<- read.csv("Dataset for Case Study 1/202308-divvy-tripdata.csv")
data_2023_9<- read.csv("Dataset for Case Study 1/202309-divvy-tripdata.csv")
data_2023_10<- read.csv("Dataset for Case Study 1/202310-divvy-tripdata.csv")
data_2023_11<- read.csv("Dataset for Case Study 1/202311-divvy-tripdata.csv")
data_2023_12<- read.csv("Dataset for Case Study 1/202312-divvy-tripdata.csv")



# List of dataset names
dataset_names <- c(
  "data_2023_1", "data_2023_2", "data_2023_3",
  "data_2023_4", "data_2023_5", "data_2023_6",
  "data_2023_7", "data_2023_8", "data_2023_9",
  "data_2023_10", "data_2023_11", "data_2023_12"
)
# Iterate over each dataset and print its column names

for (dataset_name in dataset_names) {
  cat("Columns for", dataset_name, ":\n")
  print(colnames(get(dataset_name)))
  cat("\n")
  
}
## Columns for data_2023_1 :
##  [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"     
## 
## Columns for data_2023_2 :
##  [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"     
## 
## Columns for data_2023_3 :
##  [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"     
## 
## Columns for data_2023_4 :
##  [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"     
## 
## Columns for data_2023_5 :
##  [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"     
## 
## Columns for data_2023_6 :
##  [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"     
## 
## Columns for data_2023_7 :
##  [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"     
## 
## Columns for data_2023_8 :
##  [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"     
## 
## Columns for data_2023_9 :
##  [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"     
## 
## Columns for data_2023_10 :
##  [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"     
## 
## Columns for data_2023_11 :
##  [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"     
## 
## Columns for data_2023_12 :
##  [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"
# Iterate over each dataset and print its structure using str()

for (dataset_name in dataset_names) {
  dataset <- get(dataset_name)
  cat("Structure for", dataset_name, ":\n")
  str(dataset)
  cat("\n")
}
## Structure for data_2023_1 :
## 'data.frame':    190301 obs. of  13 variables:
##  $ ride_id           : chr  "F96D5A74A3E41399" "13CB7EB698CEDB88" "BD88A2E670661CE5" "C90792D034FED968" ...
##  $ rideable_type     : chr  "electric_bike" "classic_bike" "electric_bike" "classic_bike" ...
##  $ started_at        : chr  "2023-01-21 20:05:42" "2023-01-10 15:37:36" "2023-01-02 07:51:57" "2023-01-22 10:52:58" ...
##  $ ended_at          : chr  "2023-01-21 20:16:33" "2023-01-10 15:46:05" "2023-01-02 08:05:11" "2023-01-22 11:01:44" ...
##  $ start_station_name: chr  "Lincoln Ave & Fullerton Ave" "Kimbark Ave & 53rd St" "Western Ave & Lunt Ave" "Kimbark Ave & 53rd St" ...
##  $ start_station_id  : chr  "TA1309000058" "TA1309000037" "RP-005" "TA1309000037" ...
##  $ end_station_name  : chr  "Hampden Ct & Diversey Ave" "Greenwood Ave & 47th St" "Valli Produce - Evanston Plaza" "Greenwood Ave & 47th St" ...
##  $ end_station_id    : chr  "202480.0" "TA1308000002" "599" "TA1308000002" ...
##  $ start_lat         : num  41.9 41.8 42 41.8 41.8 ...
##  $ start_lng         : num  -87.6 -87.6 -87.7 -87.6 -87.6 ...
##  $ end_lat           : num  41.9 41.8 42 41.8 41.8 ...
##  $ end_lng           : num  -87.6 -87.6 -87.7 -87.6 -87.6 ...
##  $ member_casual     : chr  "member" "member" "casual" "member" ...
## 
## Structure for data_2023_2 :
## 'data.frame':    190445 obs. of  13 variables:
##  $ ride_id           : chr  "CBCD0D7777F0E45F" "F3EC5FCE5FF39DE9" "E54C1F27FA9354FF" "3D561E04F739CC45" ...
##  $ rideable_type     : chr  "classic_bike" "electric_bike" "classic_bike" "electric_bike" ...
##  $ started_at        : chr  "2023-02-14 11:59:42" "2023-02-15 13:53:48" "2023-02-19 11:10:57" "2023-02-26 16:12:05" ...
##  $ ended_at          : chr  "2023-02-14 12:13:38" "2023-02-15 13:59:08" "2023-02-19 11:35:01" "2023-02-26 16:39:55" ...
##  $ start_station_name: chr  "Southport Ave & Clybourn Ave" "Clarendon Ave & Gordon Ter" "Southport Ave & Clybourn Ave" "Southport Ave & Clybourn Ave" ...
##  $ start_station_id  : chr  "TA1309000030" "13379" "TA1309000030" "TA1309000030" ...
##  $ end_station_name  : chr  "Clark St & Schiller St" "Sheridan Rd & Lawrence Ave" "Aberdeen St & Monroe St" "Franklin St & Adams St (Temp)" ...
##  $ end_station_id    : chr  "TA1309000024" "TA1309000041" "13156" "TA1309000008" ...
##  $ start_lat         : num  41.9 42 41.9 41.9 41.8 ...
##  $ start_lng         : num  -87.7 -87.6 -87.7 -87.7 -87.6 ...
##  $ end_lat           : num  41.9 42 41.9 41.9 41.8 ...
##  $ end_lng           : num  -87.6 -87.7 -87.7 -87.6 -87.6 ...
##  $ member_casual     : chr  "casual" "casual" "member" "member" ...
## 
## Structure for data_2023_3 :
## 'data.frame':    258678 obs. of  13 variables:
##  $ ride_id           : chr  "6842AA605EE9FBB3" "F984267A75B99A8C" "FF7CF57CFE026D02" "6B61B916032CB6D6" ...
##  $ rideable_type     : chr  "electric_bike" "electric_bike" "classic_bike" "classic_bike" ...
##  $ started_at        : chr  "2023-03-16 08:20:34" "2023-03-04 14:07:06" "2023-03-31 12:28:09" "2023-03-22 14:09:08" ...
##  $ ended_at          : chr  "2023-03-16 08:22:52" "2023-03-04 14:15:31" "2023-03-31 12:38:47" "2023-03-22 14:24:51" ...
##  $ start_station_name: chr  "Clark St & Armitage Ave" "Public Rack - Kedzie Ave & Argyle St" "Orleans St & Chestnut St (NEXT Apts)" "Desplaines St & Kinzie St" ...
##  $ start_station_id  : chr  "13146" "491" "620" "TA1306000003" ...
##  $ end_station_name  : chr  "Larrabee St & Webster Ave" "" "Clark St & Randolph St" "Sheffield Ave & Kingsbury St" ...
##  $ end_station_id    : chr  "13193" "" "TA1305000030" "13154" ...
##  $ start_lat         : num  41.9 42 41.9 41.9 41.9 ...
##  $ start_lng         : num  -87.6 -87.7 -87.6 -87.6 -87.7 ...
##  $ end_lat           : num  41.9 42 41.9 41.9 41.9 ...
##  $ end_lng           : num  -87.6 -87.7 -87.6 -87.7 -87.7 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
## 
## Structure for data_2023_4 :
## 'data.frame':    426590 obs. of  13 variables:
##  $ ride_id           : chr  "8FE8F7D9C10E88C7" "34E4ED3ADF1D821B" "5296BF07A2F77CB5" "40759916B76D5D52" ...
##  $ rideable_type     : chr  "electric_bike" "electric_bike" "electric_bike" "electric_bike" ...
##  $ started_at        : chr  "2023-04-02 08:37:28" "2023-04-19 11:29:02" "2023-04-19 08:41:22" "2023-04-19 13:31:30" ...
##  $ ended_at          : chr  "2023-04-02 08:41:37" "2023-04-19 11:52:12" "2023-04-19 08:43:22" "2023-04-19 13:35:09" ...
##  $ start_station_name: chr  "" "" "" "" ...
##  $ start_station_id  : chr  "" "" "" "" ...
##  $ end_station_name  : chr  "" "" "" "" ...
##  $ end_station_id    : chr  "" "" "" "" ...
##  $ start_lat         : num  41.8 41.9 41.9 41.9 41.9 ...
##  $ start_lng         : num  -87.6 -87.7 -87.7 -87.7 -87.7 ...
##  $ end_lat           : num  41.8 41.9 41.9 41.9 41.9 ...
##  $ end_lng           : num  -87.6 -87.7 -87.7 -87.7 -87.6 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
## 
## Structure for data_2023_5 :
## 'data.frame':    604827 obs. of  13 variables:
##  $ ride_id           : chr  "0D9FA920C3062031" "92485E5FB5888ACD" "FB144B3FC8300187" "DDEB93BC2CE9AA77" ...
##  $ rideable_type     : chr  "electric_bike" "electric_bike" "electric_bike" "classic_bike" ...
##  $ started_at        : chr  "2023-05-07 19:53:48" "2023-05-06 18:54:08" "2023-05-21 00:40:21" "2023-05-10 16:47:01" ...
##  $ ended_at          : chr  "2023-05-07 19:58:32" "2023-05-06 19:03:35" "2023-05-21 00:44:36" "2023-05-10 16:59:52" ...
##  $ start_station_name: chr  "Southport Ave & Belmont Ave" "Southport Ave & Belmont Ave" "Halsted St & 21st St" "Carpenter St & Huron St" ...
##  $ start_station_id  : chr  "13229" "13229" "13162" "13196" ...
##  $ end_station_name  : chr  "" "" "" "Damen Ave & Cortland St" ...
##  $ end_station_id    : chr  "" "" "" "13133" ...
##  $ start_lat         : num  41.9 41.9 41.9 41.9 42 ...
##  $ start_lng         : num  -87.7 -87.7 -87.6 -87.7 -87.7 ...
##  $ end_lat           : num  41.9 41.9 41.9 41.9 41.9 ...
##  $ end_lng           : num  -87.7 -87.7 -87.7 -87.7 -87.7 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
## 
## Structure for data_2023_6 :
## 'data.frame':    719618 obs. of  13 variables:
##  $ ride_id           : chr  "6F1682AC40EB6F71" "622A1686D64948EB" "3C88859D926253B4" "EAD8A5E0259DEC88" ...
##  $ rideable_type     : chr  "electric_bike" "electric_bike" "electric_bike" "electric_bike" ...
##  $ started_at        : chr  "2023-06-05 13:34:12" "2023-06-05 01:30:22" "2023-06-20 18:15:49" "2023-06-19 14:56:00" ...
##  $ ended_at          : chr  "2023-06-05 14:31:56" "2023-06-05 01:33:06" "2023-06-20 18:32:05" "2023-06-19 15:00:35" ...
##  $ start_station_name: chr  "" "" "" "" ...
##  $ start_station_id  : chr  "" "" "" "" ...
##  $ end_station_name  : chr  "" "" "" "" ...
##  $ end_station_id    : chr  "" "" "" "" ...
##  $ start_lat         : num  41.9 41.9 42 42 42 ...
##  $ start_lng         : num  -87.7 -87.7 -87.7 -87.7 -87.7 ...
##  $ end_lat           : num  41.9 41.9 41.9 42 42 ...
##  $ end_lng           : num  -87.7 -87.7 -87.6 -87.7 -87.7 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
## 
## Structure for data_2023_7 :
## 'data.frame':    767650 obs. of  13 variables:
##  $ ride_id           : chr  "9340B064F0AEE130" "D1460EE3CE0D8AF8" "DF41BE31B895A25E" "9624A293749EF703" ...
##  $ rideable_type     : chr  "electric_bike" "classic_bike" "classic_bike" "electric_bike" ...
##  $ started_at        : chr  "2023-07-23 20:06:14" "2023-07-23 17:05:07" "2023-07-23 10:14:53" "2023-07-21 08:27:44" ...
##  $ ended_at          : chr  "2023-07-23 20:22:44" "2023-07-23 17:18:37" "2023-07-23 10:24:29" "2023-07-21 08:32:40" ...
##  $ start_station_name: chr  "Kedzie Ave & 110th St" "Western Ave & Walton St" "Western Ave & Walton St" "Racine Ave & Randolph St" ...
##  $ start_station_id  : chr  "20204" "KA1504000103" "KA1504000103" "13155" ...
##  $ end_station_name  : chr  "Public Rack - Racine Ave & 109th Pl" "Milwaukee Ave & Grand Ave" "Damen Ave & Pierce Ave" "Clinton St & Madison St" ...
##  $ end_station_id    : chr  "877" "13033" "TA1305000041" "TA1305000032" ...
##  $ start_lat         : num  41.7 41.9 41.9 41.9 42 ...
##  $ start_lng         : num  -87.7 -87.7 -87.7 -87.7 -87.7 ...
##  $ end_lat           : num  41.7 41.9 41.9 41.9 42 ...
##  $ end_lng           : num  -87.7 -87.6 -87.7 -87.6 -87.6 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
## 
## Structure for data_2023_8 :
## 'data.frame':    771693 obs. of  13 variables:
##  $ ride_id           : chr  "903C30C2D810A53B" "F2FB18A98E110A2B" "D0DEC7C94E4663DA" "E0DDDC5F84747ED9" ...
##  $ rideable_type     : chr  "electric_bike" "electric_bike" "electric_bike" "electric_bike" ...
##  $ started_at        : chr  "2023-08-19 15:41:53" "2023-08-18 15:30:18" "2023-08-30 16:15:08" "2023-08-30 16:24:07" ...
##  $ ended_at          : chr  "2023-08-19 15:53:36" "2023-08-18 15:45:25" "2023-08-30 16:27:37" "2023-08-30 16:33:34" ...
##  $ start_station_name: chr  "LaSalle St & Illinois St" "Clark St & Randolph St" "Clark St & Randolph St" "Wells St & Elm St" ...
##  $ start_station_id  : chr  "13430" "TA1305000030" "TA1305000030" "KA1504000135" ...
##  $ end_station_name  : chr  "Clark St & Elm St" "" "" "" ...
##  $ end_station_id    : chr  "TA1307000039" "" "" "" ...
##  $ start_lat         : num  41.9 41.9 41.9 41.9 41.9 ...
##  $ start_lng         : num  -87.6 -87.6 -87.6 -87.6 -87.6 ...
##  $ end_lat           : num  41.9 41.9 41.9 41.9 41.9 ...
##  $ end_lng           : num  -87.6 -87.6 -87.6 -87.6 -87.7 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
## 
## Structure for data_2023_9 :
## 'data.frame':    666371 obs. of  13 variables:
##  $ ride_id           : chr  "011C1903BF4E2E28" "87DB80E048A1BF9F" "7C2EB7AF669066E3" "57D197B010269CE3" ...
##  $ rideable_type     : chr  "classic_bike" "classic_bike" "electric_bike" "classic_bike" ...
##  $ started_at        : chr  "2023-09-23 00:27:50" "2023-09-02 09:26:43" "2023-09-25 18:30:11" "2023-09-13 15:30:49" ...
##  $ ended_at          : chr  "2023-09-23 00:33:27" "2023-09-02 09:38:19" "2023-09-25 18:41:39" "2023-09-13 15:39:18" ...
##  $ start_station_name: chr  "Halsted St & Wrightwood Ave" "Clark St & Drummond Pl" "Financial Pl & Ida B Wells Dr" "Clark St & Drummond Pl" ...
##  $ start_station_id  : chr  "TA1309000061" "TA1307000142" "SL-010" "TA1307000142" ...
##  $ end_station_name  : chr  "Sheffield Ave & Wellington Ave" "Racine Ave & Fullerton Ave" "Racine Ave & 15th St" "Racine Ave & Belmont Ave" ...
##  $ end_station_id    : chr  "TA1307000052" "TA1306000026" "13304" "TA1308000019" ...
##  $ start_lat         : num  41.9 41.9 41.9 41.9 41.9 ...
##  $ start_lng         : num  -87.6 -87.6 -87.6 -87.6 -87.6 ...
##  $ end_lat           : num  41.9 41.9 41.9 41.9 41.9 ...
##  $ end_lng           : num  -87.7 -87.7 -87.7 -87.7 -87.7 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
## 
## Structure for data_2023_10 :
## 'data.frame':    537113 obs. of  13 variables:
##  $ ride_id           : chr  "4449097279F8BBE7" "9CF060543CA7B439" "667F21F4D6BDE69C" "F92714CC6B019B96" ...
##  $ rideable_type     : chr  "classic_bike" "electric_bike" "electric_bike" "classic_bike" ...
##  $ started_at        : chr  "2023-10-08 10:36:26" "2023-10-11 17:23:59" "2023-10-12 07:02:33" "2023-10-24 19:13:03" ...
##  $ ended_at          : chr  "2023-10-08 10:49:19" "2023-10-11 17:36:08" "2023-10-12 07:06:53" "2023-10-24 19:18:29" ...
##  $ start_station_name: chr  "Orleans St & Chestnut St (NEXT Apts)" "Desplaines St & Kinzie St" "Orleans St & Chestnut St (NEXT Apts)" "Desplaines St & Kinzie St" ...
##  $ start_station_id  : chr  "620" "TA1306000003" "620" "TA1306000003" ...
##  $ end_station_name  : chr  "Sheffield Ave & Webster Ave" "Sheffield Ave & Webster Ave" "Franklin St & Lake St" "Franklin St & Lake St" ...
##  $ end_station_id    : chr  "TA1309000033" "TA1309000033" "TA1307000111" "TA1307000111" ...
##  $ start_lat         : num  41.9 41.9 41.9 41.9 41.9 ...
##  $ start_lng         : num  -87.6 -87.6 -87.6 -87.6 -87.6 ...
##  $ end_lat           : num  41.9 41.9 41.9 41.9 41.9 ...
##  $ end_lng           : num  -87.7 -87.7 -87.6 -87.6 -87.6 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
## 
## Structure for data_2023_11 :
## 'data.frame':    362518 obs. of  13 variables:
##  $ ride_id           : chr  "4EAD8F1AD547356B" "6322270563BF5470" "B37BDE091ECA38E0" "CF0CA5DD26E4F90E" ...
##  $ rideable_type     : chr  "electric_bike" "electric_bike" "electric_bike" "classic_bike" ...
##  $ started_at        : chr  "2023-11-30 21:50:05" "2023-11-03 09:44:02" "2023-11-30 11:39:44" "2023-11-08 10:01:45" ...
##  $ ended_at          : chr  "2023-11-30 22:13:27" "2023-11-03 10:17:15" "2023-11-30 11:40:08" "2023-11-08 10:27:05" ...
##  $ start_station_name: chr  "Millennium Park" "Broadway & Sheridan Rd" "State St & Pearson St" "Theater on the Lake" ...
##  $ start_station_id  : chr  "13008" "13323" "TA1307000061" "TA1308000001" ...
##  $ end_station_name  : chr  "Pine Grove Ave & Waveland Ave" "Broadway & Sheridan Rd" "State St & Pearson St" "Theater on the Lake" ...
##  $ end_station_id    : chr  "TA1307000150" "13323" "TA1307000061" "TA1308000001" ...
##  $ start_lat         : num  41.9 42 41.9 41.9 41.9 ...
##  $ start_lng         : num  -87.6 -87.7 -87.6 -87.6 -87.6 ...
##  $ end_lat           : num  41.9 42 41.9 41.9 41.9 ...
##  $ end_lng           : num  -87.6 -87.6 -87.6 -87.6 -87.6 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
## 
## Structure for data_2023_12 :
## 'data.frame':    224073 obs. of  13 variables:
##  $ ride_id           : chr  "C9BD54F578F57246" "CDBD92F067FA620E" "ABC0858E52CBFC84" "F44B6F0E8F76DC90" ...
##  $ rideable_type     : chr  "electric_bike" "electric_bike" "electric_bike" "electric_bike" ...
##  $ started_at        : chr  "2023-12-02 18:44:01" "2023-12-02 18:48:19" "2023-12-24 01:56:32" "2023-12-24 10:58:12" ...
##  $ ended_at          : chr  "2023-12-02 18:47:51" "2023-12-02 18:54:48" "2023-12-24 02:04:09" "2023-12-24 11:03:04" ...
##  $ start_station_name: chr  "" "" "" "" ...
##  $ start_station_id  : chr  "" "" "" "" ...
##  $ end_station_name  : chr  "" "" "" "" ...
##  $ end_station_id    : chr  "" "" "" "" ...
##  $ start_lat         : num  41.9 41.9 41.9 42 41.9 ...
##  $ start_lng         : num  -87.7 -87.7 -87.6 -87.7 -87.6 ...
##  $ end_lat           : num  41.9 41.9 41.9 41.9 41.9 ...
##  $ end_lng           : num  -87.7 -87.6 -87.6 -87.7 -87.6 ...
##  $ member_casual     : chr  "member" "member" "member" "member" ...
library(dplyr)

# List of dataset names
dataset_names <- c(
  "data_2023_1", "data_2023_2", "data_2023_3",
  "data_2023_4", "data_2023_5", "data_2023_6",
  "data_2023_7", "data_2023_8", "data_2023_9",
  "data_2023_10", "data_2023_11", "data_2023_12"
)

# Read and combine all datasets
combined_data <- bind_rows(
  lapply(dataset_names, function(dataset_name) get(dataset_name))
)

Process

colnames(combined_data)
##  [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(combined_data) #How many rows are in data frame?
## [1] 5719877
dim(combined_data) #Dimensions of the data frame?
## [1] 5719877      13
head(combined_data)  #See the first 6 rows of data frame.
##            ride_id rideable_type          started_at            ended_at
## 1 F96D5A74A3E41399 electric_bike 2023-01-21 20:05:42 2023-01-21 20:16:33
## 2 13CB7EB698CEDB88  classic_bike 2023-01-10 15:37:36 2023-01-10 15:46:05
## 3 BD88A2E670661CE5 electric_bike 2023-01-02 07:51:57 2023-01-02 08:05:11
## 4 C90792D034FED968  classic_bike 2023-01-22 10:52:58 2023-01-22 11:01:44
## 5 3397017529188E8A  classic_bike 2023-01-12 13:58:01 2023-01-12 14:13:20
## 6 58E68156DAE3E311 electric_bike 2023-01-31 07:18:03 2023-01-31 07:21:16
##              start_station_name start_station_id               end_station_name
## 1   Lincoln Ave & Fullerton Ave     TA1309000058      Hampden Ct & Diversey Ave
## 2         Kimbark Ave & 53rd St     TA1309000037        Greenwood Ave & 47th St
## 3        Western Ave & Lunt Ave           RP-005 Valli Produce - Evanston Plaza
## 4         Kimbark Ave & 53rd St     TA1309000037        Greenwood Ave & 47th St
## 5         Kimbark Ave & 53rd St     TA1309000037        Greenwood Ave & 47th St
## 6 Lakeview Ave & Fullerton Pkwy     TA1309000019      Hampden Ct & Diversey Ave
##   end_station_id start_lat start_lng  end_lat   end_lng member_casual
## 1       202480.0  41.92407 -87.64628 41.93000 -87.64000        member
## 2   TA1308000002  41.79957 -87.59475 41.80983 -87.59938        member
## 3            599  42.00857 -87.69048 42.03974 -87.69941        casual
## 4   TA1308000002  41.79957 -87.59475 41.80983 -87.59938        member
## 5   TA1308000002  41.79957 -87.59475 41.80983 -87.59938        member
## 6       202480.0  41.92607 -87.63886 41.93000 -87.64000        member
str(combined_data)  #See list of columns and data types (numeric, character, etc)
## 'data.frame':    5719877 obs. of  13 variables:
##  $ ride_id           : chr  "F96D5A74A3E41399" "13CB7EB698CEDB88" "BD88A2E670661CE5" "C90792D034FED968" ...
##  $ rideable_type     : chr  "electric_bike" "classic_bike" "electric_bike" "classic_bike" ...
##  $ started_at        : chr  "2023-01-21 20:05:42" "2023-01-10 15:37:36" "2023-01-02 07:51:57" "2023-01-22 10:52:58" ...
##  $ ended_at          : chr  "2023-01-21 20:16:33" "2023-01-10 15:46:05" "2023-01-02 08:05:11" "2023-01-22 11:01:44" ...
##  $ start_station_name: chr  "Lincoln Ave & Fullerton Ave" "Kimbark Ave & 53rd St" "Western Ave & Lunt Ave" "Kimbark Ave & 53rd St" ...
##  $ start_station_id  : chr  "TA1309000058" "TA1309000037" "RP-005" "TA1309000037" ...
##  $ end_station_name  : chr  "Hampden Ct & Diversey Ave" "Greenwood Ave & 47th St" "Valli Produce - Evanston Plaza" "Greenwood Ave & 47th St" ...
##  $ end_station_id    : chr  "202480.0" "TA1308000002" "599" "TA1308000002" ...
##  $ start_lat         : num  41.9 41.8 42 41.8 41.8 ...
##  $ start_lng         : num  -87.6 -87.6 -87.7 -87.6 -87.6 ...
##  $ end_lat           : num  41.9 41.8 42 41.8 41.8 ...
##  $ end_lng           : num  -87.6 -87.6 -87.7 -87.6 -87.6 ...
##  $ member_casual     : chr  "member" "member" "casual" "member" ...
# You can also confirm each columns' data type here
summary(combined_data)  #Statistical summary of data. Mainly for numerics
##    ride_id          rideable_type       started_at          ended_at        
##  Length:5719877     Length:5719877     Length:5719877     Length:5719877    
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##  start_station_name start_station_id   end_station_name   end_station_id    
##  Length:5719877     Length:5719877     Length:5719877     Length:5719877    
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##    start_lat       start_lng         end_lat         end_lng      
##  Min.   :41.63   Min.   :-87.94   Min.   : 0.00   Min.   :-88.16  
##  1st Qu.:41.88   1st Qu.:-87.66   1st Qu.:41.88   1st Qu.:-87.66  
##  Median :41.90   Median :-87.64   Median :41.90   Median :-87.64  
##  Mean   :41.90   Mean   :-87.65   Mean   :41.90   Mean   :-87.65  
##  3rd Qu.:41.93   3rd Qu.:-87.63   3rd Qu.:41.93   3rd Qu.:-87.63  
##  Max.   :42.07   Max.   :-87.46   Max.   :42.18   Max.   :  0.00  
##                                   NA's   :6990    NA's   :6990    
##  member_casual     
##  Length:5719877    
##  Class :character  
##  Mode  :character  
##                    
##                    
##                    
## 
#Confirmed there are 5006 NA columns in end_lat and end_lat
# Add columns that list the date, month, day, and year of each ride as we might need to aggregate ride data for each month, day, or year.
combined_data$date <- as.Date(combined_data$started_at) #The default format is yyyy-mm-dd
combined_data$month <- format(as.Date(combined_data$date), "%m")
combined_data$day <- format(as.Date(combined_data$date), "%d")
combined_data$year <- format(as.Date(combined_data$date), "%Y")
combined_data$day_of_week <- format(as.Date(combined_data$date), "%A")
colnames(combined_data)
##  [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"      "date"               "month"             
## [16] "day"                "year"               "day_of_week"
head(combined_data)  #See the first 6 rows of data frame.
##            ride_id rideable_type          started_at            ended_at
## 1 F96D5A74A3E41399 electric_bike 2023-01-21 20:05:42 2023-01-21 20:16:33
## 2 13CB7EB698CEDB88  classic_bike 2023-01-10 15:37:36 2023-01-10 15:46:05
## 3 BD88A2E670661CE5 electric_bike 2023-01-02 07:51:57 2023-01-02 08:05:11
## 4 C90792D034FED968  classic_bike 2023-01-22 10:52:58 2023-01-22 11:01:44
## 5 3397017529188E8A  classic_bike 2023-01-12 13:58:01 2023-01-12 14:13:20
## 6 58E68156DAE3E311 electric_bike 2023-01-31 07:18:03 2023-01-31 07:21:16
##              start_station_name start_station_id               end_station_name
## 1   Lincoln Ave & Fullerton Ave     TA1309000058      Hampden Ct & Diversey Ave
## 2         Kimbark Ave & 53rd St     TA1309000037        Greenwood Ave & 47th St
## 3        Western Ave & Lunt Ave           RP-005 Valli Produce - Evanston Plaza
## 4         Kimbark Ave & 53rd St     TA1309000037        Greenwood Ave & 47th St
## 5         Kimbark Ave & 53rd St     TA1309000037        Greenwood Ave & 47th St
## 6 Lakeview Ave & Fullerton Pkwy     TA1309000019      Hampden Ct & Diversey Ave
##   end_station_id start_lat start_lng  end_lat   end_lng member_casual
## 1       202480.0  41.92407 -87.64628 41.93000 -87.64000        member
## 2   TA1308000002  41.79957 -87.59475 41.80983 -87.59938        member
## 3            599  42.00857 -87.69048 42.03974 -87.69941        casual
## 4   TA1308000002  41.79957 -87.59475 41.80983 -87.59938        member
## 5   TA1308000002  41.79957 -87.59475 41.80983 -87.59938        member
## 6       202480.0  41.92607 -87.63886 41.93000 -87.64000        member
##         date month day year day_of_week
## 1 2023-01-21    01  21 2023    Saturday
## 2 2023-01-10    01  10 2023     Tuesday
## 3 2023-01-02    01  02 2023      Monday
## 4 2023-01-22    01  22 2023      Sunday
## 5 2023-01-12    01  12 2023    Thursday
## 6 2023-01-31    01  31 2023     Tuesday
str(combined_data)
## 'data.frame':    5719877 obs. of  18 variables:
##  $ ride_id           : chr  "F96D5A74A3E41399" "13CB7EB698CEDB88" "BD88A2E670661CE5" "C90792D034FED968" ...
##  $ rideable_type     : chr  "electric_bike" "classic_bike" "electric_bike" "classic_bike" ...
##  $ started_at        : chr  "2023-01-21 20:05:42" "2023-01-10 15:37:36" "2023-01-02 07:51:57" "2023-01-22 10:52:58" ...
##  $ ended_at          : chr  "2023-01-21 20:16:33" "2023-01-10 15:46:05" "2023-01-02 08:05:11" "2023-01-22 11:01:44" ...
##  $ start_station_name: chr  "Lincoln Ave & Fullerton Ave" "Kimbark Ave & 53rd St" "Western Ave & Lunt Ave" "Kimbark Ave & 53rd St" ...
##  $ start_station_id  : chr  "TA1309000058" "TA1309000037" "RP-005" "TA1309000037" ...
##  $ end_station_name  : chr  "Hampden Ct & Diversey Ave" "Greenwood Ave & 47th St" "Valli Produce - Evanston Plaza" "Greenwood Ave & 47th St" ...
##  $ end_station_id    : chr  "202480.0" "TA1308000002" "599" "TA1308000002" ...
##  $ start_lat         : num  41.9 41.8 42 41.8 41.8 ...
##  $ start_lng         : num  -87.6 -87.6 -87.7 -87.6 -87.6 ...
##  $ end_lat           : num  41.9 41.8 42 41.8 41.8 ...
##  $ end_lng           : num  -87.6 -87.6 -87.7 -87.6 -87.6 ...
##  $ member_casual     : chr  "member" "member" "casual" "member" ...
##  $ date              : Date, format: "2023-01-21" "2023-01-10" ...
##  $ month             : chr  "01" "01" "01" "01" ...
##  $ day               : chr  "21" "10" "02" "22" ...
##  $ year              : chr  "2023" "2023" "2023" "2023" ...
##  $ day_of_week       : chr  "Saturday" "Tuesday" "Monday" "Sunday" ...
# Add a "ride_length" calculation to all_trips (in seconds) so that I can compare ride length for each ride
# https://stat.ethz.ch/R-manual/R-devel/library/base/html/difftime.html

combined_data$ride_length <- difftime(combined_data$ended_at,combined_data$started_at)
# Convert "ride_length" from Double to numeric so we can run calculations on the data
combined_data$ride_length <- as.numeric(as.character(combined_data$ride_length))
is.numeric(combined_data$ride_length)
## [1] TRUE
# Remove "bad" data
# The dataframe includes a few hundred entries when bikes were taken out of docks and checked for quality by Divvy or ride_length was negative

#Create a new data frame without records that have ride length <= zero minute OR > 1440 minutes
combined_data_v2 <- combined_data[!(combined_data$ride_length <= 0 | combined_data$ride_length > 1440),]
#Check the new data frame
dim(combined_data_v2) 
## [1] 4902180      19
View(combined_data_v2)
summary(combined_data_v2)
##    ride_id          rideable_type       started_at          ended_at        
##  Length:4902180     Length:4902180     Length:4902180     Length:4902180    
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##  start_station_name start_station_id   end_station_name   end_station_id    
##  Length:4902180     Length:4902180     Length:4902180     Length:4902180    
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##    start_lat       start_lng         end_lat         end_lng      
##  Min.   :41.64   Min.   :-87.92   Min.   : 0.00   Min.   :-87.99  
##  1st Qu.:41.88   1st Qu.:-87.66   1st Qu.:41.88   1st Qu.:-87.66  
##  Median :41.90   Median :-87.64   Median :41.90   Median :-87.65  
##  Mean   :41.90   Mean   :-87.65   Mean   :41.90   Mean   :-87.65  
##  3rd Qu.:41.93   3rd Qu.:-87.63   3rd Qu.:41.93   3rd Qu.:-87.63  
##  Max.   :42.07   Max.   :-87.52   Max.   :42.09   Max.   :  0.00  
##                                   NA's   :146     NA's   :146     
##  member_casual           date               month               day           
##  Length:4902180     Min.   :2023-01-01   Length:4902180     Length:4902180    
##  Class :character   1st Qu.:2023-05-18   Class :character   Class :character  
##  Mode  :character   Median :2023-07-20   Mode  :character   Mode  :character  
##                     Mean   :2023-07-15                                        
##                     3rd Qu.:2023-09-19                                        
##                     Max.   :2023-12-31                                        
##                                                                               
##      year           day_of_week         ride_length    
##  Length:4902180     Length:4902180     Min.   :   1.0  
##  Class :character   Class :character   1st Qu.: 295.0  
##  Mode  :character   Mode  :character   Median : 492.0  
##                                        Mean   : 560.1  
##                                        3rd Qu.: 778.0  
##                                        Max.   :1440.0  
## 
#Confirmed the total number of rows is 4,902,180       (down from 5,719,877 - decreased by 10% - significant but necessary removals.
#1,241 NAs Remains in end_lat and end_long
1. Remove NA data from the all_trips_v2 to get accurate data.
# Remove rows with NAs using na.omit()
combined_data_v2 <- na.omit(combined_data_v2)

# Check for NAs in the dataframe

any_na <- anyNA(combined_data_v2)
print(any_na)
## [1] FALSE
1. Remove duplicated ID as I confirmed ride ID is associated with each ride, not riders.
#Remove duplicated ID (confirmed different ride_id is assigned for every rides even if same rider uses this service):
combined_data_v3 <- combined_data_v2[!duplicated(combined_data_v2$ride_id),]
dim(combined_data_v2) 
## [1] 4902034      19
# Confirmed 4,902,034 remained (Original data has 4,902,180 >>> Valid)

Data Cleaning/Validation process has been completed at this point.

Next, I am going to create additional columns for further analysis.

# Load the geosphere package
library(geosphere)
## Warning: package 'geosphere' was built under R version 4.3.3
#Find out the distance for each ride:
combined_data_v3$ride_distance <- distGeo(matrix(c(combined_data_v3$start_lng, combined_data_v3$start_lat), ncol = 2), matrix(c(combined_data_v3$end_lng, combined_data_v3$end_lat), ncol = 2))
View(combined_data_v3)
str(combined_data_v3)
## 'data.frame':    4902034 obs. of  20 variables:
##  $ ride_id           : chr  "F96D5A74A3E41399" "13CB7EB698CEDB88" "BD88A2E670661CE5" "C90792D034FED968" ...
##  $ rideable_type     : chr  "electric_bike" "classic_bike" "electric_bike" "classic_bike" ...
##  $ started_at        : chr  "2023-01-21 20:05:42" "2023-01-10 15:37:36" "2023-01-02 07:51:57" "2023-01-22 10:52:58" ...
##  $ ended_at          : chr  "2023-01-21 20:16:33" "2023-01-10 15:46:05" "2023-01-02 08:05:11" "2023-01-22 11:01:44" ...
##  $ start_station_name: chr  "Lincoln Ave & Fullerton Ave" "Kimbark Ave & 53rd St" "Western Ave & Lunt Ave" "Kimbark Ave & 53rd St" ...
##  $ start_station_id  : chr  "TA1309000058" "TA1309000037" "RP-005" "TA1309000037" ...
##  $ end_station_name  : chr  "Hampden Ct & Diversey Ave" "Greenwood Ave & 47th St" "Valli Produce - Evanston Plaza" "Greenwood Ave & 47th St" ...
##  $ end_station_id    : chr  "202480.0" "TA1308000002" "599" "TA1308000002" ...
##  $ start_lat         : num  41.9 41.8 42 41.8 41.8 ...
##  $ start_lng         : num  -87.6 -87.6 -87.7 -87.6 -87.6 ...
##  $ end_lat           : num  41.9 41.8 42 41.8 41.8 ...
##  $ end_lng           : num  -87.6 -87.6 -87.7 -87.6 -87.6 ...
##  $ member_casual     : chr  "member" "member" "casual" "member" ...
##  $ date              : Date, format: "2023-01-21" "2023-01-10" ...
##  $ month             : chr  "01" "01" "01" "01" ...
##  $ day               : chr  "21" "10" "02" "22" ...
##  $ year              : chr  "2023" "2023" "2023" "2023" ...
##  $ day_of_week       : chr  "Saturday" "Tuesday" "Monday" "Sunday" ...
##  $ ride_length       : num  651 509 794 526 919 193 840 561 747 753 ...
##  $ ride_distance     : num  839 1204 3540 1204 1204 ...
##  - attr(*, "na.action")= 'omit' Named int [1:146] 66648 113756 115015 202485 268133 378866 399457 542862 646262 655015 ...
##   ..- attr(*, "names")= chr [1:146] "71703" "122586" "123948" "218177" ...

Analyze

#Assign the correct order to each day of the week
combined_data_v3$day_of_week <- 
    ordered(combined_data_v3$day_of_week, levels = c('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'))

combined_data_v3 %>%
    group_by(member_casual, day_of_week) %>%
    summarise(number_of_ride = n(), .groups = 'drop') %>%
    arrange(day_of_week)
## # A tibble: 14 × 3
##    member_casual day_of_week number_of_ride
##    <chr>         <ord>                <int>
##  1 casual        Monday              183159
##  2 member        Monday              451692
##  3 casual        Tuesday             200147
##  4 member        Tuesday             525956
##  5 casual        Wednesday           206960
##  6 member        Wednesday           537335
##  7 casual        Thursday            222990
##  8 member        Thursday            538909
##  9 casual        Friday              244873
## 10 member        Friday              481725
## 11 casual        Saturday            297304
## 12 member        Saturday            413810
## 13 casual        Sunday              240627
## 14 member        Sunday              356547
# Summary statistics
summary_stats <- combined_data_v3 %>%
  group_by(member_casual) %>%
  summarise(
    total_rides = n(),
    average_ride_length = mean(ride_length),
    average_ride_distance = mean(ride_distance)
  )
print(summary_stats)
## # A tibble: 2 × 4
##   member_casual total_rides average_ride_length average_ride_distance
##   <chr>               <int>               <dbl>                 <dbl>
## 1 casual            1596060                612.                 1737.
## 2 member            3305974                535.                 1792.
# Visualizations
# Distribution of rides by member type
rides_distribution <- combined_data_v3 %>%
  group_by(member_casual) %>%
  summarise(total_rides = n())

# Plot
# Plot
ggplot(rides_distribution, aes(x = member_casual, y = total_rides, fill = member_casual)) +
  geom_bar(stat = "identity") +
  labs(title = "Distribution of Rides by Member Type",
       x = "Member Type",
       y = "Total Rides") +
  theme_minimal()

options(tibble.print_max = Inf)

combined_data_v3$month <- ordered(combined_data_v3$month, 
                                  levels = c('05', '06', '07', '08', '09', '10', '11', '12', '01', '02', '03', '04'))

result <- combined_data_v3 %>%
  group_by(member_casual, month) %>%
  summarise(number_of_ride = n(), .groups = 'drop') %>%
  arrange(month)

print(result)
## # A tibble: 24 × 3
##    member_casual month number_of_ride
##    <chr>         <ord>          <int>
##  1 casual        05            174691
##  2 member        05            330358
##  3 casual        06            227618
##  4 member        06            371516
##  5 casual        07            244366
##  6 member        07            384212
##  7 casual        08            235613
##  8 member        08            407410
##  9 casual        09            199955
## 10 member        09            361716
## 11 casual        10            143014
## 12 member        10            329680
## 13 casual        11             83949
## 14 member        11            244576
## 15 casual        12             45465
## 16 member        12            160705
## 17 casual        01             36061
## 18 member        01            141107
## 19 casual        02             37004
## 20 member        02            137087
## 21 casual        03             53963
## 22 member        03            183713
## 23 casual        04            114361
## 24 member        04            253894

Now, I would like to find out whether ride_length can be different depends on rider type.

aggregate(combined_data_v3$ride_length ~ combined_data_v3$member_casual + combined_data_v3$day_of_week, FUN=mean)
##    combined_data_v3$member_casual combined_data_v3$day_of_week
## 1                          casual                       Monday
## 2                          member                       Monday
## 3                          casual                      Tuesday
## 4                          member                      Tuesday
## 5                          casual                    Wednesday
## 6                          member                    Wednesday
## 7                          casual                     Thursday
## 8                          member                     Thursday
## 9                          casual                       Friday
## 10                         member                       Friday
## 11                         casual                     Saturday
## 12                         member                     Saturday
## 13                         casual                       Sunday
## 14                         member                       Sunday
##    combined_data_v3$ride_length
## 1                      592.5435
## 2                      519.9265
## 3                      586.8119
## 4                      528.8072
## 5                      583.3356
## 6                      531.1687
## 7                      589.8024
## 8                      532.8086
## 9                      609.1766
## 10                     530.4884
## 11                     651.8541
## 12                     559.4634
## 13                     645.3022
## 14                     551.6448
combined_data_v3 %>%
    group_by(member_casual, month) %>%
    summarise(average_ride_length = mean(ride_length), .groups = 'drop') %>%
    arrange(month)
## # A tibble: 24 × 3
##    member_casual month average_ride_length
##    <chr>         <ord>               <dbl>
##  1 casual        05                   625.
##  2 member        05                   547.
##  3 casual        06                   640.
##  4 member        06                   565.
##  5 casual        07                   646.
##  6 member        07                   569.
##  7 casual        08                   643.
##  8 member        08                   570.
##  9 casual        09                   627.
## 10 member        09                   558.
## 11 casual        10                   583.
## 12 member        10                   526.
## 13 casual        11                   549.
## 14 member        11                   507.
## 15 casual        12                   527.
## 16 member        12                   497.
## 17 casual        01                   499.
## 18 member        01                   469.
## 19 casual        02                   527.
## 20 member        02                   475.
## 21 casual        03                   529.
## 22 member        03                   478.
## 23 casual        04                   588.
## 24 member        04                   510.

Next, check whether how each type of rider use the bike by looking at ride distance.

combined_data_v3 %>%
    group_by(member_casual, day_of_week) %>%
    summarise(distance_of_ride = mean(ride_distance), .groups = 'drop') %>%
    arrange(day_of_week)
## # A tibble: 14 × 3
##    member_casual day_of_week distance_of_ride
##    <chr>         <ord>                  <dbl>
##  1 casual        Monday                 1690.
##  2 member        Monday                 1756.
##  3 casual        Tuesday                1739.
##  4 member        Tuesday                1792.
##  5 casual        Wednesday              1749.
##  6 member        Wednesday              1805.
##  7 casual        Thursday               1795.
##  8 member        Thursday               1822.
##  9 casual        Friday                 1723.
## 10 member        Friday                 1764.
## 11 casual        Saturday               1732.
## 12 member        Saturday               1806.
## 13 casual        Sunday                 1725.
## 14 member        Sunday                 1790.
combined_data_v3 %>%
    group_by(member_casual, month) %>%
    summarise(distance_of_ride = mean(ride_distance), .groups = 'drop') %>%
    arrange(month)
## # A tibble: 24 × 3
##    member_casual month distance_of_ride
##    <chr>         <ord>            <dbl>
##  1 casual        05               1757.
##  2 member        05               1843.
##  3 casual        06               1845.
##  4 member        06               1920.
##  5 casual        07               1775.
##  6 member        07               1884.
##  7 casual        08               1787.
##  8 member        08               1872.
##  9 casual        09               1762.
## 10 member        09               1845.
## 11 casual        10               1687.
## 12 member        10               1762.
## 13 casual        11               1622.
## 14 member        11               1703.
## 15 casual        12               1548.
## 16 member        12               1672.
## 17 casual        01               1504.
## 18 member        01               1564.
## 19 casual        02               1562.
## 20 member        02               1586.
## 21 casual        03               1579.
## 22 member        03               1640.
## 23 casual        04               1687.
## 24 member        04               1738.

Finaly, in order to support my assumption, let’s find out how many riders use the same bike station for start point and end point (ride_distance = 0).

combined_data_v3 %>%
    group_by(member_casual) %>%
    summarize(number_of_rides = n() , .groups = 'drop')
## # A tibble: 2 × 2
##   member_casual number_of_rides
##   <chr>                   <int>
## 1 casual                1596060
## 2 member                3305974
combined_data_v3 %>%
    group_by(member_casual) %>%
    filter(ride_distance < 1) %>%
    summarize(number_of_rides = n() , .groups = 'drop')
## # A tibble: 2 × 2
##   member_casual number_of_rides
##   <chr>                   <int>
## 1 casual                 102927
## 2 member                 110657

Proportions of rides returning to the start point were calculated as follows:

Findings

Conclusion

Casual riders show a higher tendency for short trips that begin and end at the same location, which could indicate recreational or exploratory use. Membership riders’ lower proportion of such trips suggests more practical and routine uses, possibly related to commuting. These insights can help tailor marketing strategies to convert casual riders into members by highlighting the benefits of membership for regular commuting.

Share

Here, I would like to share visualizations which would allow executives to understand my conclusion easily.

combined_data_v3 %>%
    group_by(member_casual, day_of_week) %>%
    summarise(number_of_rides = n(), .groups = 'drop') %>%
    ggplot(aes(x = day_of_week, y = number_of_rides, fill = member_casual)) + 
    geom_bar(position = "dodge", stat = "identity")

combined_data_v3 %>%
    group_by(member_casual, month) %>%
    summarise(number_of_rides = n(), .groups = 'drop') %>%
    ggplot(aes(x = month, y = number_of_rides, fill = member_casual)) + 
    geom_bar(position = "dodge", stat = "identity")

combined_data_v3 %>%
    group_by(member_casual, day_of_week) %>%
    summarise(average_ride_length = mean(ride_length), .groups = 'drop') %>%
    ggplot(aes(x = day_of_week, y = average_ride_length, fill = member_casual)) + 
    geom_bar(position = "dodge", stat = "identity")

combined_data_v3 %>%
    group_by(member_casual, month) %>%
    summarise(average_ride_length = mean(ride_length), .groups = 'drop') %>%
    ggplot(aes(x = month, y = average_ride_length, fill = member_casual)) + 
    geom_bar(position = "dodge", stat = "identity")

combined_data_v3 %>%
    group_by(member_casual) %>%
    filter(ride_distance < 10000) %>% #Remove outliner
    ggplot(aes(x = ride_distance, fill = member_casual)) + 
    geom_histogram() #Disregard binwidth
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

combined_data_v3 %>%
    group_by(member_casual, day_of_week) %>%
    summarise(average_ride_distance = mean(ride_distance), .groups = 'drop') %>%
    ggplot(aes(x = day_of_week, y = average_ride_distance, fill = member_casual)) + 
    geom_bar(position = "dodge", stat = "identity")

combined_data_v3 %>%
    group_by(member_casual, month) %>%
    summarise(average_ride_distance = mean(ride_distance), .groups = 'drop') %>%
    ggplot(aes(x = month, y = average_ride_distance, fill = member_casual)) + 
    geom_bar(position = "dodge", stat = "identity")

Analysis: