Introduction

This is the report on Citi Bike NYC a bike sharing system for New York City (USA). We examine the factors associated with the recent behaviours of Citi Bike users answering the following research question.

This approach will enable the Citi Bike executives to gain valuable insights into the factors associated with the recent behaviors of Citi Bike users, facilitating informed decision-making and strategic planning.

Data Cleaning

##            ride_id          started_at            ended_at
## 1 159C90AB46D5631B 2023-04-01 17:24:06 2023-04-01 17:46:10
## 2 4349D44670885CED 2023-04-13 15:09:12 2023-04-13 15:16:11
## 3 55EB4E8AF45439D2 2023-04-28 15:17:00 2023-04-28 15:26:09
## 4 3133FC58AA938D08 2023-04-23 16:18:49 2023-04-23 17:10:50
## 5 BF2DD897668DA1AC 2023-04-21 15:42:08 2023-04-21 15:47:04
## 6 FF558338220E455B 2023-04-21 22:21:17 2023-04-21 22:26:53
##        start_station_name start_station_id          end_station_name
## 1     Hoyt St & Warren St          4330.09 Washington St & Laight St
## 2         E 25 St & 2 Ave          6046.02           E 47 St & 2 Ave
## 3         3 Ave & E 62 St          6762.04           W 55 St & 6 Ave
## 4   Washington Pl & 6 Ave          5838.09           E 56 St & 3 Ave
## 5         3 Ave & E 62 St          6762.04           W 55 St & 6 Ave
## 6 Evergreen Ave & Noll St          4873.08 Stockholm St & Wilson Ave
##   end_station_id start_lat start_lng  end_lat   end_lng member_casual
## 1        5509.02  40.68429 -73.98894 40.72231 -74.01060        member
## 2        6498.10  40.73913 -73.97974 40.75323 -73.97033        member
## 3        6809.09  40.76313 -73.96527 40.76319 -73.97843        member
## 4        6691.11  40.73224 -74.00026 40.75935 -73.96760        member
## 5        6809.09  40.76311 -73.96581 40.76319 -73.97843        member
## 6        4824.03  40.70106 -73.93318 40.69930 -73.92304        member
##   day_period classic_bike electric_bike docked_bike
## 1  afternoon        22.07            NA          NA
## 2  afternoon           NA          6.98          NA
## 3  afternoon           NA          9.15          NA
## 4  afternoon        52.02            NA          NA
## 5  afternoon         4.93            NA          NA
## 6      night           NA          5.60          NA
# Combine bike type columns into a single column
citi_bike_data_bike <- citi_bike_data %>%
  mutate(bike_type = case_when(
    !is.na(classic_bike) ~ "classic",
    !is.na(electric_bike) ~ "electric",
    !is.na(docked_bike) ~ "docked"
  )) %>%
  # Remove the individual bike type columns
  select(-classic_bike, -electric_bike, -docked_bike)

# Check the modification
head(citi_bike_data_bike)
##            ride_id          started_at            ended_at
## 1 159C90AB46D5631B 2023-04-01 17:24:06 2023-04-01 17:46:10
## 2 4349D44670885CED 2023-04-13 15:09:12 2023-04-13 15:16:11
## 3 55EB4E8AF45439D2 2023-04-28 15:17:00 2023-04-28 15:26:09
## 4 3133FC58AA938D08 2023-04-23 16:18:49 2023-04-23 17:10:50
## 5 BF2DD897668DA1AC 2023-04-21 15:42:08 2023-04-21 15:47:04
## 6 FF558338220E455B 2023-04-21 22:21:17 2023-04-21 22:26:53
##        start_station_name start_station_id          end_station_name
## 1     Hoyt St & Warren St          4330.09 Washington St & Laight St
## 2         E 25 St & 2 Ave          6046.02           E 47 St & 2 Ave
## 3         3 Ave & E 62 St          6762.04           W 55 St & 6 Ave
## 4   Washington Pl & 6 Ave          5838.09           E 56 St & 3 Ave
## 5         3 Ave & E 62 St          6762.04           W 55 St & 6 Ave
## 6 Evergreen Ave & Noll St          4873.08 Stockholm St & Wilson Ave
##   end_station_id start_lat start_lng  end_lat   end_lng member_casual
## 1        5509.02  40.68429 -73.98894 40.72231 -74.01060        member
## 2        6498.10  40.73913 -73.97974 40.75323 -73.97033        member
## 3        6809.09  40.76313 -73.96527 40.76319 -73.97843        member
## 4        6691.11  40.73224 -74.00026 40.75935 -73.96760        member
## 5        6809.09  40.76311 -73.96581 40.76319 -73.97843        member
## 6        4824.03  40.70106 -73.93318 40.69930 -73.92304        member
##   day_period bike_type
## 1  afternoon   classic
## 2  afternoon  electric
## 3  afternoon  electric
## 4  afternoon   classic
## 5  afternoon   classic
## 6      night  electric
# Convert the 'started_at' and 'ended_at' columns to POSIXct format
citi_bike_data_bike$started_at <- as.POSIXct(citi_bike_data_bike$started_at, format = "%Y-%m-%d %H:%M:%S")
citi_bike_data_bike$ended_at <- as.POSIXct(citi_bike_data_bike$ended_at, format = "%Y-%m-%d %H:%M:%S")

# Calculate the ride duration in seconds
citi_bike_data_bike <- citi_bike_data_bike %>%
  mutate(ride_duration = as.numeric(difftime(ended_at, started_at, units = "secs")))

head(citi_bike_data_bike)
##            ride_id          started_at            ended_at
## 1 159C90AB46D5631B 2023-04-01 17:24:06 2023-04-01 17:46:10
## 2 4349D44670885CED 2023-04-13 15:09:12 2023-04-13 15:16:11
## 3 55EB4E8AF45439D2 2023-04-28 15:17:00 2023-04-28 15:26:09
## 4 3133FC58AA938D08 2023-04-23 16:18:49 2023-04-23 17:10:50
## 5 BF2DD897668DA1AC 2023-04-21 15:42:08 2023-04-21 15:47:04
## 6 FF558338220E455B 2023-04-21 22:21:17 2023-04-21 22:26:53
##        start_station_name start_station_id          end_station_name
## 1     Hoyt St & Warren St          4330.09 Washington St & Laight St
## 2         E 25 St & 2 Ave          6046.02           E 47 St & 2 Ave
## 3         3 Ave & E 62 St          6762.04           W 55 St & 6 Ave
## 4   Washington Pl & 6 Ave          5838.09           E 56 St & 3 Ave
## 5         3 Ave & E 62 St          6762.04           W 55 St & 6 Ave
## 6 Evergreen Ave & Noll St          4873.08 Stockholm St & Wilson Ave
##   end_station_id start_lat start_lng  end_lat   end_lng member_casual
## 1        5509.02  40.68429 -73.98894 40.72231 -74.01060        member
## 2        6498.10  40.73913 -73.97974 40.75323 -73.97033        member
## 3        6809.09  40.76313 -73.96527 40.76319 -73.97843        member
## 4        6691.11  40.73224 -74.00026 40.75935 -73.96760        member
## 5        6809.09  40.76311 -73.96581 40.76319 -73.97843        member
## 6        4824.03  40.70106 -73.93318 40.69930 -73.92304        member
##   day_period bike_type ride_duration
## 1  afternoon   classic          1324
## 2  afternoon  electric           419
## 3  afternoon  electric           549
## 4  afternoon   classic          3121
## 5  afternoon   classic           296
## 6      night  electric           336
# Remove the specified variables
citi_bike_data_bike<-citi_bike_data_bike %>%
  select(-started_at, -ended_at, -start_station_id, -end_station_id, -start_lat, -start_lng, -end_lat, -end_lng)
# Set seed for reproducibility
student_id <- 67816 
set.seed(student_id)

# Randomly sample 50,000 rows
citi_bike_data_bike_sample <- citi_bike_data_bike %>%
  sample_n(50000)

# Save the sampled dataset
write.csv(citi_bike_data_bike_sample, "Citi-Bike-NYC-Sample.csv", row.names = FALSE)

# Display the first 6 rows of the sampled dataset
head(citi_bike_data_bike_sample)
##            ride_id           start_station_name             end_station_name
## 1 77C141FD968C2DBA                23 Rd & 31 St                23 Rd & 31 St
## 2 79D065D3303940F4 MacDougal St & Washington Sq MacDougal St & Washington Sq
## 3 A58DF6EBEBBB1E3C      Mercer St & Bleecker St          St Marks Pl & 1 Ave
## 4 93D264A51E33171F              1 Ave & E 68 St              E 77 St & 1 Ave
## 5 800E80CC8D9F67E6              W 21 St & 6 Ave              2 Ave & E 31 St
## 6 CDA6779FA9EC06D9         48 St & Skillman Ave               45 Ave & 21 St
##   member_casual day_period bike_type ride_duration
## 1        member  afternoon   classic             0
## 2        member      night   classic            51
## 3        member      night   classic           336
## 4        member  afternoon   classic           170
## 5        member  afternoon   classic           868
## 6        member    morning   classic           716

After importing the dataset into R, we performed the following data cleaning steps:

# Parameters for Uniform distribution
min_duration <- ride_duration_stats$minimum
max_duration <- ride_duration_stats$maximum

# Generate random sample from Uniform distribution
uniform_sample <- runif(50000, min = min_duration, max = max_duration)

# Parameters for Normal distribution
mean_duration <- ride_duration_stats$mean
sd_duration <- ride_duration_stats$sd

# Generate random sample from Normal distribution
normal_sample <- rnorm(50000, mean = mean_duration, sd = sd_duration)
# Plot histograms of ride durations, Uniform sample, and Normal sample
par(mfrow = c(1, 3)) # Arrange plots in a single row

# Histogram of ride durations
hist(citi_bike_data_bike_sample$ride_duration, breaks = 50, main = "Ride Durations", xlab = "Duration (mins)", col = "blue", probability = TRUE)

# Histogram of Uniform sample
hist(uniform_sample, breaks = 50, main = "Uniform Distribution", xlab = "Duration (mins)", col = "green", probability = TRUE)

# Histogram of Normal sample
hist(normal_sample, breaks = 50, main = "Normal Distribution", xlab = "Duration (mins)", col = "red", probability = TRUE)

par(mfrow = c(1, 1)) # Reset plot arrangement
# Creating a histogram of trip durations
histogram_plot <- ggplot(citi_bike_data_bike_sample, aes(x = ride_duration)) +
  geom_histogram(binwidth = 100, fill = "skyblue", color = "black") +
  labs(title = "Trip Durations", x = "Duration (seconds)", y = "Frequency") +
  theme_minimal()

# Displaying the histogram
print(histogram_plot)

Similarities and Differences between Ride Durations and the Uniform Sample

  • Similarities:

    • Both distributions cover a similar range of values since the uniform sample is generated based on the range of ride durations.
  • Differences:

    • The ride duration histogram is highly skewed to the left, with many short rides and a few longer rides.

    • The uniform sample histogram is flat, showing an equal frequency of all values across the range, reflecting the uniform distribution.

    Similarities and Differences between Ride Durations and the Normal Sample

    • Similarities:

      • Both distributions have a central tendency, but this similarity is superficial given the actual shapes of the distributions.
    • Differences:

      • The ride duration histogram is highly skewed to the left, indicating that most rides are short, with fewer longer rides.

      • The normal sample histogram is symmetrical and bell-shaped, indicating a normal distribution with most values clustered around the mean and fewer values at the extremes.

The normal distribution would be more suitable to approximate the trip durations since it shows more variation in the frequency of different durations, indicating that certain durations are more common than others just as the Ride durations have more frequency in short durations.

# Calculate ride count by time of day and user type
time_of_day_summary <- citi_bike_data_bike %>%
  group_by(member_casual, day_period) %>%
  summarize(ride_count = n(), .groups = 'drop')

time_of_day_summary
## # A tibble: 6 × 3
##   member_casual day_period ride_count
##   <chr>         <chr>           <int>
## 1 casual        afternoon      267759
## 2 casual        morning         97037
## 3 casual        night          165661
## 4 member        afternoon      970674
## 5 member        morning        621389
## 6 member        night          731830
# Bar plot of ride count by time of day and user type
ggplot(time_of_day_summary, aes(x = day_period, y = ride_count, fill = member_casual)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Ride Count by Time of Day and User Type", x = "Time of Day", y = "Ride Count") +
  theme_minimal() +
  scale_fill_manual(values = c("member" = "blue", "casual" = "red"))

The bar plot shows that the peak periods for Citi Bike usage are in the afternoon. Members exhibit higher ride counts, indicating that they primarily use the service for commuting. Both casual and members use bikes in the afternoon most, followed by the night and lastly in the morning. This difference in peak usage periods between members and casual users highlights the importance of ensuring bike availability during peak commuting times to cater to the needs of regular users. Members exhibit significantly higher ride counts across all periods, with the afternoon being the peak usage period. Casual users also have their peak usage in the afternoon, followed by night and morning. This indicates that while members use the service more frequently overall, both groups tend to prefer afternoon rides, possibly due to leisure activities or post-work travel.

# Calculate summary statistics for ride duration by bike type
ride_duration_summary <- citi_bike_data_bike %>%
  group_by(bike_type) %>%
  summarize(
    count = n(),
    mean_duration = mean(ride_duration, na.rm = TRUE),
    median_duration = median(ride_duration, na.rm = TRUE),
    sd_duration = sd(ride_duration, na.rm = TRUE),
    IQR_duration = IQR(ride_duration, na.rm = TRUE),
    .groups = 'drop'
  )

ride_duration_summary
## # A tibble: 3 × 6
##   bike_type   count mean_duration median_duration sd_duration IQR_duration
##   <chr>       <int>         <dbl>           <dbl>       <dbl>        <dbl>
## 1 classic   2381013          893.             552       2771.          712
## 2 docked      15758         9802.            1461      69280.         1315
## 3 electric   457579          892.             537       3213.          658
# Box plot of ride duration by bike type
# theme_minimal() +
 # scale_fill_manual(values = c("classic_bike" = "green", "electric_bike" = "yellow", "docked_bike" = "purple"))

The summary statistics and box plot reveal that electric bikes tend to have shorter ride durations. Additionaly the most popular bike being used is the clasic bikes with a count of 2381013.
The mean ride duration for electric bikes and classic bikes is significantly lower, which could be attributed to their faster speed, allowing users to reach their destinations more quickly. Docked bikes, which are typically rented for short periods, have a median ride duration that is much higher, indicating a skew in the data.

Conclusion

Studying the behavior of Citi Bike users, one can find a lot of interesting patterns in trip time and peak usage. On average, both members and casual users tend to use the service more intensively during the afternoon, but members use it much more often than casual ones. Another important factor that greatly affects ride duration is the type of bike, where e-bikes are used for tiny, short distances, whereas classic bikes are used for longer rides. In addition, these results can be combined into knowledge with which to best manage Citi Bike NYC operations, deal with fluctuating demand in bicycle flows for peak hours, and service the diverse pool of users who have varying preferences. With the knowledge of patterns of user behavior, Citi Bike NYC will actually optimize the satisfaction of users coupled with increasing operational effectiveness required for the growth of the bike-sharing system in New York City.