Pricing Optimization: How to find the price that maximizes your profit
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 , where is the quantity sold given a specific price . To simplify things, let’s suppose that is a linear function:
The total revenue will be given by:
And total profit will be given by:
Where 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 and to find the first order conditions, which allow us to find the optimal police under the hypothesis of a linear demand curve. is expected to be negative (demand decrease when prices increase) and are concave functions of . As consequence, the critical point will be a maximum point. Therefore, the optimal police for revenue is given by:
And for profit:
Note that sometimes people write the linear demand curve as , in this case 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 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:
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[1] alpha = model.fit$coefficients[2] 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[2]*p + model.fit$coefficients[1]) estimated.profit = function(p) (p - unity.cost)*(model.fit$coefficients[2]*p + model.fit$coefficients[1]) 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 , it might be useful to simulate , 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.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.