Which is Better? OMNY or 30-Day Unlimited MetroCard?

A Statistical Analysis

Macklin Fluehr
5 min readJan 7, 2023

(UPDATED: Dec 2023 to account for the $2.90 ride fare change)

TL;DR, (coincidentally) OMNY is better until you average 12 rides per week, then a 30-day unlimited card is better.

How did I get here?

I am a data scientist and work in a hybrid office environment. Before COVID, I commuted to the office 5 days a week. Getting a 30-day Unlimited MetroCard for $132 was a no-brainer. Now that I’m only in the office two to three days a week, it is trickier to know what type of MetroCard is most cost efficient for me.

The OMNY pass costs riders $2.90 per ride until they reach 12 rides in one week, and any ride after that is free. It’s been heavily advertised as an alternative for “commitment-phobes” all over the subway system. That said, I wasn’t convinced this was necessarily a good deal for me. As someone who likes math, I decided I wanted to figure this out for real.

Core Assumptions

From the MTA Fare Info Page

  • 30-Day MetroCard: $132
  • Single Ride Fare: $2.90
  • OMNY Weekly Free Ride Minimum: 12

OMNY runs on a weekly cadence, which doesn’t quite align with a 30 day MetroCard. To make sure we are comparing apples to apples, I have prorated the 30 day-MetroCard cost for 4 weeks of OMNY usage:

  • Prorated 30-Day MetroCard Cost: $123.2 / 4 weeks (28 days)

The Approach

The cost for a 30-day MetroCard is fixed. It doesn’t matter how much I ride, I’m going to pay $123 dollars no matter what. However, with OMNY, I can pay a totally different amount each week, depending on how many rides I take on the subway.

To figure out my break even, I am going to run some statistical simulations of how much I might spend on OMNY on an average week, using Python.

OMNY Spend Cap

After 12 swipes in one week, OMNY lets me ride free with my card. Let’s create a python function to simulate that.

fare = 2.90
omny_free_ride_limit = 12

def simulate_omny_week(num_rides: int) -> float:
"""
Given a particular number of rides for the week,
calculate how much that would cost with omny.

Input:
num_rides - how many swipes did I make this week?
Output:
total_fare - how much money would OMNY cost me?
"""

total_fare = 0

for ride in range(num_rides):
if ride >= omny_free_ride_limit: # python is zero indexed
break

total_fare += fare

return total_fare

Simulating Weekly Usage

I might assume that I average 10 rides a week with OMNY. While I could give this function that same 10 ride number every time, that’s not how real life works. Some weeks I use my MetroCard more, some weeks I use less. How can we model this pseudo-randomness?

In statistics, there is a distribution called the Poisson Distribution, which models the probability that a certain number of events will occur in a period of time. Sometimes more happen, sometimes less. It takes a value _lambda_ which is the average number of events that might happen during that period of time.

Translating this to our problem: how many MetroCard swipes could I make in 7 days? I can give this distribution the average number of subway swipes I think I make off the top of my head.

Here’s how we might do this in python:

import numpy as np

avg_weekly_usage = 10 # I think I average 10 rides a week

simulated_weekly_usage = np.random.poisson(avg_weekly_usage)

Simulating Monthly OMNY Cost

Ok. We have some code to calculate how much OMNY will cost me given a particular number of rides in one week. We also have some code to randomly generate how many rides I might take in one week, based on an average. Let’s roll this up into a 4 week cost, so that we can compare it to our 30-Day MetroCard cost.

def get_monthly_omny_cost(avg_weekly_use: int) -> float:
"""
Given an average weekly usage, simulate potential swipe usages
for 4 weeks. Then calculate the OMNY cost for each week and
sum them up.

Input:
avg_weekly_use - the number of swipes per week I use on average
Output:
the simulated 4-week cost of using OMNY, given my average usage
"""

# Simulate Nunber of rides taken with poisson distribution
weekly_usage = np.random.poisson(avg_weekly_use, 4)

weekly_omny_cost = [simulate_omny_week(usage) for usage in weekly_usage.tolist()]

return sum(weekly_omny_cost)

The Experiment

We can generate a monthly cost, which is pseudo-random, just like real life. But, that’s just one month. I want to know how often OMNY is better on any average month. We can fortunately do this with Python!

Below, I simulate getting my average OMNY cost 100,000 times. This is kind of like getting 100,000 other New Yorkers with the same commuting habits as me to help try out OMNY and then report back to me on how much they spent. But I get to do it with just my computer.

import pandas as pd
import matplotlib.pyplot as plt

def run_simulation(
avg_weekly_use: int,
num_simulations: int = 100000,
print_out: bool = False
):
"""
Simulate using OMNY for a particular number of 4-week periods.
Calculate the probability that OMNY costs less than a 30-day unlimited card.

Inputs:
avg_weekly_use - the number of swipes per week I use on average
num_simulations - how many times to run the simulation (how many New Yorkers are helping me)
print_out - print some cool plots
Output:
prob_omny_costs_less - the probability that OMNY costs less than the prorated 30-day metrocard
"""

simulations = []


for i in range(num_sim):
simulations.append(get_monthly_omny_cost(avg_weekly_use))

simulations = pd.Series(simulations)

prob_omny_costs_less = (simulations < pro_rated_unlimited_cost).sum() / simulations.shape[0]

if print_out:
simulations.hist(bins=40, density=True, alpha = 0.5, label='OMNY')
plt.vlines(x=pro_rated_unlimited_cost, ymin=0, ymax=0.025, color='r', label="unlmited")
plt.title(f"Costs with Omny for Avg {avg_weekly_use} Rides per Week")
plt.xlabel("$")

print("% of Time OMNY Costs Less: {:.2f}%".format(
prob_omny_costs_less * 100
))

return prob_omny_costs_less

Below is an example plot showing our results.

The red vertical line is the cost of our prorated 30-day unlimited MetroCard, at $123. The blue distribution is showing us the spread of potential spend we would have if we used OMNY on any given 4-week period, given some randomness.

We can see above that a lot of the blue is below the red line. In fact, 83% of the time, OMNY is cheaper than a 30-day MetroCard if I average 10 rides a week.

Let’s see if we can generalize this to other weekly averages:

As you can see, up until I average 12 rides a week, OMNY is usually better. More often than not, I’ll save money if I stick with it and skip the Unlimited card.

Considering I thought I probably used 10 rides per week these days on average, I think I’m an OMNY convert!

--

--

Macklin Fluehr

Macklin Fluehr is an engineer, machine learning specialist, and designer working to transform sustainability with a cross-disciplinary approach