This repository is a Python implementation of the Newsvendor Model.
Python>=3.8
scipy>=1.8.1
pip install git+https://github.com/takazawa/newsvendor-model
- demand
$D$ (random variable) - retail price
$p$ - purchase price
$c$
The standard newsvendor model is to find the optimal quantity $q_{\text{opt}} $of the product, which
maximizes the expected profit
The optimal solution to the problem is known to be
where
The model to be imported depends on whether the probability distribution used is discrete or continuous as follows:
from nvmodel import ContinuousNewsvendorModel, DiscreteNewsvendorModel
Using the Wikipedia example, consider the following problem:
- retail price
$p = 7$ - purchase price
$c = 5$ - demand
$D$ follows a (continuous) uniform distribution between$D_{\min}=50$ and$D_{\max}=80$ .
Then the newsvendeor model is as follows:
from nvmodel import ContinuousNewsvendorModel
def p_func(x):
d_min, d_max = 50, 80
if d_min <= x <= d_max:
return 1 / (d_max - d_min)
else:
return 0
model = ContinuousNewsvendorModel(retail_price=7,
cost_price=5,
probability_function=p_func)
Now, we can calculate values
-
model.critical_ratio()
$=\frac{p-c}{c}$ -
model.optimal_quantity()
$=q_{\text{opt}}$ -
model.revenue(q, D)
$=F(q, D)$ -
model.expected_revenue(q)
$=E[F(q, D)]$
>> q_opt = model.optimal_quantity()
>> q_opt
58.57142857142857
from scipy.stats import norm
from nvmodel import ContinuousNewsvendorModel
def normal_pdf(x):
mu, sigma = 50, 20
return norm(mu, sigma).pdf(x)
model = ContinuousNewsvendorModel(retail_price=7, cost_price=5, probability_function=normal_pdf)
q_opt = model.optimal_quantity()
>> q_opt
39.04454355287975
In the Continuous Model, the inverse CDF is computed approximately. It can also be computed exactly by explicitly giving inverseCDF as follows.
from scipy.stats import norm
from nvmodel import ContinuousNewsvendorModel
def normal_inverse_cdf(x):
mu, sigma = 50, 20
return mu + sigma * norm.ppf(x)
model = ContinuousNewsvendorModel(retail_price=7,
cost_price=5,
inverse_cdf=normal_inverse_cdf)
q_opt = model.optimal_quantity()
>> q_opt
38.68102356134274
- retail price
$p = 8$ - purchase price
$c = 5$ - demand
$D$ follows the poisson distribution (mean=25) - salvaged revenue
$s = 4$ - a profit per unit from unsold products
from scipy.stats import poisson
from nvmodel import DiscreteNewsvendorModel
def poisson_pmf(x):
return poisson.pmf(x, 25)
model = DiscreteNewsvendorModel(retail_price=8,
cost_price=5,
probability_function=poisson_pmf,
salvaged_revenue=4)
q_opt = model.optimal_quantity()
>> q_opt
28