Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

By Yuri Fonseca

## Basic idea

In this post we will discuss briefly about pricing optimization. The main idea behind this problem is the following question: As manager of a company/store, how much should I charge in order to maximize my revenue or profit?

Obviously, the answer isn’t as high as possible. If you charge one hundred dollars for a candy, probably only one or two people will accept to buy it. Although the profit per product is very high, you probably won’t even your fixed costs. Charge a very small is also not the best call.

Before showing an example for this problem, let us build some simple formulas.

Imagine a monopolist selling a specific product with demand curve $Q(p)$, where $Q(p)$ is the quantity sold given a specific price $p$. To simplify things, let’s suppose that $Q(p)$ is a linear function: $\displaystyle Q(p) = \alpha p + \beta$

The total revenue will be given by: $\displaystyle R(p) = p Q(p) = \alpha p^2 + p\beta$

And total profit will be given by: $\displaystyle L(p) = (p - c)Q(p) = \alpha p^2 - \alpha pc + \beta(p - c)$

Where $c$ is the unity cost of the product. Adding fixed costs in the profit equation does not change the price police, so we will suppose it’s zero.

Next, we differentiate the equations for $R(p)$ and $L(p)$ to find the first order conditions, which allow us to find the optimal police under the hypothesis of a linear demand curve. $\alpha$ is expected to be negative (demand decrease when prices increase) $R$ and $L$ are concave functions of $p$. As consequence, the critical point will be a maximum point. Therefore, the optimal police for revenue is given by: $\displaystyle P_{\textrm{max rev}}= \frac{-\beta}{2\alpha}$

And for profit: $\displaystyle P_{\textrm{max prof}} = \frac{-\beta + \alpha c}{2\alpha}$

Note that sometimes people write the linear demand curve as $Q(p) = -\alpha p + \beta$, in this case $\alpha$ should be positive, and the signs in equation 2 and equation 3 must change. Moreover, it is interesting to note that the price that maximizes profit is always bigger than the one that maximizes total revenue because $c$ is always positive.

If taxes are calculated just on profit the price police remains the same. However, countries like Brazil usually charges a lot of taxes on total revenue. In this case, the price police for maximizing revenue doesn’t change, but the police for maximizing profit will change according to the following expression: $\displaystyle P_{\textrm{max prof}}^{(tax)} = \frac{-\beta(1-tax) + \alpha c}{2\alpha(1-tax)}$

## Example and implementations:

As an example of how to proceed with the estimation of the optimum price, let’s generate a linear demand curve with for daily selling of a product:

library(ggplot2)

# example of linear demand curve (first equation)

demand = function(p, alpha = -40, beta = 500, sd = 10) {

error = rnorm(length(p), sd = sd)
q = p*alpha + beta + error

return(q)
}

set.seed(100)

prices = seq(from = 5, to = 10, by = 0.1)
q = demand(prices)

data = data.frame('prices' = prices,'quantity' = q)

ggplot(data, aes(prices, quantity)) +
geom_point(shape=1) +
geom_smooth(method='lm') +
ggtitle('Demand Curve') Imagine a company that has been selling the product which follows the demand curve above for a while (one year changing prices daily), testing some prices over time. The following time-series is what we should expect for the historical revenue, profit and cost of the company:

set.seed(10)

hist.prices = rnorm(252, mean = 6, sd = .5) # random prices defined by the company
hist.demand = demand(hist.prices) # demand curve defined in the chunck above
hist.revenue = hist.prices*hist.demand # From the revenue equation
unity.cost = 4 # production cost per unity
hist.cost = unity.cost*hist.demand
hist.profit = (hist.prices - unity.cost)*hist.demand # From the price equation

data = data.frame('Period' = seq(1,252),'Daily.Prices' = hist.prices,
'Daily.Demand' = hist.demand, 'Daily.Revenue' = hist.revenue,
'Daily.Cost' = hist.cost, 'Daily.Profit' = hist.profit)

ggplot(data, aes(Period, Daily.Prices)) +
geom_line(color = 4) +
ggtitle('Historical Prices used for explotation') ggplot(data, aes(Period, Daily.Revenue, colour = 'Revenue')) +
geom_line() +
geom_line(aes(Period, Daily.Profit, colour = 'Profit')) +
geom_line(aes(Period, Daily.Cost, colour = 'Cost')) +
labs(title = 'Historical Performance', colour = '') We can recover the demand curve using the historical data (that is how it is done in the real world).

library(stargazer)

model.fit = lm(hist.demand ~ hist.prices) # linear model for demand
stargazer(model.fit, type = 'html', header = FALSE) # output

 Dependent variable: hist.demand hist.prices -38.822*** (1.429) Constant 493.588*** (8.542) Observations 252 R2 0.747 Adjusted R2 0.746 Residual Std. Error 10.731 (df = 250) F Statistic 738.143*** (df = 1; 250) Note: *p<0.1; **p<0.05; ***p<0.01

And now we need to apply equation 2 and equation 3.

# estimated parameters
beta = model.fit$coefficients alpha = model.fit$coefficients

p.revenue = -beta/(2*alpha) # estimated price for revenue
p.profit = (alpha*unity.cost - beta)/(2*alpha) # estimated price for profit


The final plot with the estimated prices:

true.revenue = function(p) p*(-40*p + 500) # Revenue with true parameters (chunck demand)
true.profit = function(p) (p - unity.cost)*(-40*p + 500) # price with true parameters

# estimated curves
estimated.revenue = function(p) p*(model.fit$coefficients*p + model.fit$coefficients)
estimated.profit = function(p) (p - unity.cost)*(model.fit$coefficients*p + model.fit$coefficients)

opt.revenue = true.revenue(p.revenue) # Revenue with estimated optimum price
opt.profit = true.profit(p.profit) # Profit with estimated optimum price

# plot
df = data.frame(x1 = p.revenue, x2 = p.profit,
y1 = opt.revenue, y2 = opt.profit, y3 = 0)

ggplot(data = data.frame(Price = 0)) +
stat_function(fun = true.revenue, mapping = aes(x = Price, color = 'True Revenue')) +
stat_function(fun = true.profit, mapping = aes(x = Price, color = 'True Profit')) +
stat_function(fun = estimated.revenue, mapping = aes(x = Price, color = 'Estimated Revenue')) +
stat_function(fun = estimated.profit, mapping = aes(x = Price, color = 'Estimated Profit')) +
scale_x_continuous(limits = c(4, 11)) +
labs(title = 'True curves without noise') +
ylab('Results') +
scale_color_manual(name = "", values = c("True Revenue" = 2, "True Profit" = 3, "Estimated Revenue" = 4, "Estimated Profit" = 6)) +
geom_segment(aes(x = x1, y = y1, xend = x1, yend = y3), data = df) +
geom_segment(aes(x = x2, y = y2, xend = x2, yend = y3), data = df) ## Final observations

As you can see, the estimated Revenue and estimated Profit curves are quite similar to the true ones without noise and the expected revenue for our estimated optimal policies looks very promising. Although the linear and monopolist assumption looks quite restrictive, this might not be the case, check Besbes and Zeevi (2015) and Cooper et al (2015).

If one expect a large variance for $\alpha$, it might be useful to simulate $\alpha$, $\beta$ and then the optimal price using Jensen’s inequality.

## References

Phillips, Robert Lewis. Pricing and revenue optimization. Stanford University Press, 2005.

Besbes, Omar, and Assaf Zeevi. “On the (surprising) sufficiency of linear models for dynamic pricing with demand learning.” Management Science 61.4 (2015): 723-739.

Cooper, William L., Tito Homem-de-Mello, and Anton J. Kleywegt. “Learning and pricing with models that do not explicitly incorporate competition.” Operations research 63.1 (2015): 86-103.

Talluri, Kalyan T., and Garrett J. Van Ryzin. The theory and practice of revenue management. Vol. 68. Springer Science & Business Media, 2006.  