<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/boost-series-ii-pricing-optimization/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://insightr.wordpress.com/2018/10/01/boost-series-ii-pricing-optimization/"> R – insightR</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<div>
<p><strong>By Gabriel Vasconcelos &amp; Yuri Fonseca</strong></p>
</div>
<h2>Introduction</h2>
<p>This post is the second of a series of examples of the BooST (Boosting Smooth Trees) model. You can see an introduction to the model <a rel="nofollow" href="https://insightr.wordpress.com/2018/08/14/boost-boosting-smooth-trees-a-new-machine-learning-model-for-partial-effect-estimation-in-nonlinear-regressions/" target="_blank">here</a> and the first example <a rel="nofollow" href="https://insightr.wordpress.com/2018/08/20/boost-series-i-advantage-in-smooth-functions/" target="_blank">here</a>. Our objective in this post is to use the derivatives of the BooST to obtain prices that maximize the profit for a given set of products. We will use a very simple setup that we know the true optimal prices to compare with the estimated prices. The tricky thing here is that the demand functions we defined are for substitute products. Therefore, if we increase the price of product A it will affect positively the demand for product B.</p>
<p><span></span></p>
<h2>Little Math for those who like it <img alt="🙂" src="https://i0.wp.com/s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f642.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></h2>
<p>Suppose we have <img alt="n" title="n" src="https://s0.wp.com/latex.php?latex=n&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> products with linear demand function. As mentioned above, the demand of each product depends on it’s own price and the price of the other products. In matrix notation, we can write this relationship with the following expression:</p>
<p><img alt="displaystyle q = beta p + alpha," title="displaystyle q = beta p + alpha," src="https://s0.wp.com/latex.php?latex=%5Cdisplaystyle+q+%3D+%5Cbeta+p+%2B+%5Calpha%2C&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"></p>
<p>where <img alt="q in mathbb{R}^n" title="q in mathbb{R}^n" src="https://s0.wp.com/latex.php?latex=q+%5Cin+%5Cmathbb%7BR%7D%5En&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> is the demand vector with the quantity sold, <img alt="beta" title="beta" src="https://s0.wp.com/latex.php?latex=%5Cbeta&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> is a <img alt="n times n" title="n times n" src="https://s0.wp.com/latex.php?latex=n+%5Ctimes+n&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> matrix that has the coefficients of the demand curve, <img alt="alpha in mathbb{R}^n" title="alpha in mathbb{R}^n" src="https://s0.wp.com/latex.php?latex=%5Calpha+%5Cin+%5Cmathbb%7BR%7D%5En&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> is the vector with the intercept of each demand curve and <img alt="p in mathbb{R}^n" title="p in mathbb{R}^n" src="https://s0.wp.com/latex.php?latex=p+%5Cin+%5Cmathbb%7BR%7D%5En&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> is the vector of prices. Moreover, we will assume that the matrix <img alt="beta" title="beta" src="https://s0.wp.com/latex.php?latex=%5Cbeta&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> is negative definite, which is simply an assumption that the higher the price, the lower the demand and that the products compete among themselves. If this assumption do not hold, we can come up with crazy situations, where the higher the price, the higher the demand. Therefore, we could charge an infinite price for the product and get extremely rich. Normally life is harder than that, right?</p>
<p>For the profit function, we can write it in the following form in matrix notation:</p>
<p><img alt="displaystyle pi(p,q) = langle p - c, q rangle," title="displaystyle pi(p,q) = langle p - c, q rangle," src="https://s0.wp.com/latex.php?latex=%5Cdisplaystyle+%5Cpi%28p%2Cq%29+%3D+%5Clangle+p+-+c%2C+q+%5Crangle%2C&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"></p>
<p>where <img alt="d,p,c" title="d,p,c" src="https://s0.wp.com/latex.php?latex=d%2Cp%2Cc&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> are the vectors of demand, prices and unit costs, respectively. <img alt="langle .,.rangle" title="langle .,.rangle" src="https://s0.wp.com/latex.php?latex=%5Clangle+.%2C.%5Crangle&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> denotes the inner product. The inner product is there just to sum the profit of all products. Using the first equation and the second we have:</p>
<p><img alt="displaystyle pi = langle p - c, beta p + alpha rangle," title="displaystyle pi = langle p - c, beta p + alpha rangle," src="https://s0.wp.com/latex.php?latex=%5Cdisplaystyle+%5Cpi+%3D+%5Clangle+p+-+c%2C+%5Cbeta+p+%2B+%5Calpha+%5Crangle%2C&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"></p>
<p>Now, we can take the derivative of <img alt="pi" title="pi" src="https://s0.wp.com/latex.php?latex=%5Cpi&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> with respect to the vector of prices <img alt="p" title="p" src="https://s0.wp.com/latex.php?latex=p&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex">. The first order condition gives us:</p>
<p><img alt="displaystyle p^star = (beta^top + beta)^{-1}(-alpha + beta^top c)," title="displaystyle p^star = (beta^top + beta)^{-1}(-alpha + beta^top c)," src="https://s0.wp.com/latex.php?latex=%5Cdisplaystyle+p%5E%5Cstar+%3D+%28%5Cbeta%5E%5Ctop+%2B+%5Cbeta%29%5E%7B-1%7D%28-%5Calpha+%2B+%5Cbeta%5E%5Ctop+c%29%2C&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"></p>
<p>where <img alt="p^star" title="p^star" src="https://s0.wp.com/latex.php?latex=p%5E%5Cstar&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> is the vector of optimal prices. Moreover, we know that this is a maximum point for the profit function, because <img alt="beta" title="beta" src="https://s0.wp.com/latex.php?latex=%5Cbeta&bg=ffffff&%23038;fg=333333&%23038;s=0" class="latex"> is negative definite.</p>
<h2>Example</h2>
<p>In this example we are going to generate data for the demand function of three substitute products, for example, three different TVs. The data will be generated from the equations in the previous section (we included an error term in the demand equation to introduce some noise). The code below generates the data and presents the optimal analytical prices for each of the three TVs.</p>
<pre>library(tidyverse)
library(reshape2)
library(BooST)
</pre>
<pre># Declare intercept
alpha1 = 2000
alpha2 = 2500
alpha3 = 6000
alpha = c(alpha1, alpha2, alpha3)

# Declare betas (effect in the own demand, must be negative)
b11 = - 3
b22 = - 3
b33 = - 5

# (effect in the demand of other products, must be positive but not too big)
b12 = 0.5 ; b13 = 0.1
b21 = 0.5 ; b23 = 0.5
b31 = 0.1; b32 = 0.5  

# Matrix beta of the demand function
B = matrix(data = c(b11,b12,b13,b21,b22,b23,b31,b32,b33), byrow = T, ncol = 3)

# Declare costs
c1 = 200
c2 = 500
c3 = 1000

# Vector of costs
c = c(c1,c2,c3)

# Formula for optimal prices
op = as.vector(solve(t(B) + B)%*%(-alpha + t(B)%*%c))
op
</pre>
<pre>## [1]  556.3723  854.3220 1169.5596
</pre>
<p>Now we are going to generate some data from the demand equations. For each equation we generated 300 observations with prices following a uniform distribution centered in the true optimal prices. Each equation was adjusted to have and R2 of approximately 67\%</p>
<pre>set.seed(1)
N = 300
p1 = runif(N,op[1]-0.5*op[1],op[1]+0.5*op[1])
p2 = runif(N,op[2]-0.5*op[2],op[2]+0.5*op[2])
p3 = runif(N,op[3]-0.5*op[3],op[3]+0.5*op[3])

#
q1 = alpha1+b11*p1+p2*b12+p3*b13
q2 = alpha2+b21*p1+p2*b22+p3*b23
q3 = alpha3+b31*p1+p2*b32+p3*b33 

set.seed(1)
q1 = q1 + rnorm(N,sd = sd(q1)/2)
q2 = q2 + rnorm(N,sd = sd(q2)/2)
q3 = q3 + rnorm(N,sd = sd(q3)/2)
</pre>
<p>The plot below gives us an idea of the three demand functions. Note that we plotted each demand against only their respective price. However, each demand function also depends on the prices of the other TVs.</p>
<pre>ind = as.factor(c(rep(1,300),rep(2,300),rep(3,300)))
dfplot = data.frame(product = ind, q = c(q1,q2,q3), p = c(p1,p2,p3))
ggplot(data = dfplot) +
  geom_point(aes(x = p, y = q, color = product))
</pre>
<p><img alt="plot of chunk unnamed-chunk-4" src="https://i1.wp.com/i.imgur.com/uNOUXDx.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>Next, we use the generated data to run the BooST for each demand. Note that all models must have the three prices to capture the substitution effect.</p>
<pre># Run BooST #
df = data.frame(q1,q2,q3,p1,p2,p3)
y1 = df$q1
y2 = df$q2
y3 = df$q3
x = as.matrix(df[,-c(1:3)])
set.seed(1)
BooST1 = BooST(x,y1, v = 0.1, M = 50)
BooST2 = BooST(x,y2, v = 0.1, M = 50)
BooST3 = BooST(x,y3, v = 0.1, M = 50)
</pre>
<p>Before estimating the optimal prices we can explore the resulting demand functions. Recall that the demand of product 1 also depends on the prices of products 2 and 3 and cannot be visualized in two dimensions. To make the example more visual we fixed the prices of products 2 and 3 in their median and estimated the fitted demand curve for product one (black line in the plot below).</p>
<pre>dfplot1 = as.data.frame(x)
dfplot1$p2 = median(dfplot1$p2)
dfplot1$p3 = median(dfplot1$p3)
dfplot1$fitted = predict(BooST1,dfplot1)
dfplot1$q1 = q1

ggplot(data = dfplot1) + geom_point(aes(x = p1, y = q1),color = &quot;blue&quot;) +
  geom_line(aes(x=p1,y=fitted))
</pre>
<p><img alt="plot of chunk unnamed-chunk-6" src="https://i1.wp.com/i.imgur.com/l47hpGo.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>We can follow the same idea from the previous plot to obtain the price elasticity for product 1.</p>
<pre>dfplot1$d1 = estimate_derivatives(BooST1,dfplot1[,1:3],1)
dfplot1$elast = dfplot1$d1*(dfplot1$p1/dfplot1$fitted)

ggplot(data = dfplot1) + geom_point(aes(x = p1,y = elast))
</pre>
<p><img alt="plot of chunk unnamed-chunk-7" src="https://i1.wp.com/i.imgur.com/oruOQSX.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>Since our objective is to estimate the optimal prices, the next step is to create a gradient function that estimates the derivatives from each BooST and use them to obtain the gradient of the profit.</p>
<pre>gr = function(x,BooST1,BooST2,BooST3){
  X = matrix(c(x[1],x[2],x[3]),nrow = 1)
  q1p1 = estimate_derivatives(BooST1,X,1)
  q1p2 = estimate_derivatives(BooST2,X,1)
  q1p3 = estimate_derivatives(BooST3,X,1)

  q2p1 = estimate_derivatives(BooST1,X,2)
  q2p2 = estimate_derivatives(BooST2,X,2)
  q2p3 = estimate_derivatives(BooST3,X,2)

  q3p1 = estimate_derivatives(BooST1,X,3)
  q3p2 = estimate_derivatives(BooST2,X,3)
  q3p3 = estimate_derivatives(BooST3,X,3)

  q1 = predict(BooST1, X)
  q2 = predict(BooST2, X)
  q3 = predict(BooST3, X)

  g1 = q1+(x[1]-c1)*q1p1+(x[2]-c2)*q1p2+(x[3]-c3)*q1p3
  g2 = q2+(x[1]-c1)*q2p1+(x[2]-c2)*q2p2+(x[3]-c3)*q2p3
  g3 = q3+(x[1]-c1)*q3p1+(x[2]-c2)*q3p2+(x[3]-c3)*q3p3

  g = c(g1,g2,g3)

  return(g)
}
</pre>
<p>All we have to do now is to move on the gradient until the prices converge. The code below does 10 iterations in a very naive algorithm to obtain the optimal prices. The starting values are far from the true optimal prices but they must be in the support of observed prices.</p>
<pre>p_est = matrix(NA,10,3)
p_est[1,] = c(300,1200,1700)
for(i in 2:10){
  p_est[i,] = p_est[i-1,]+0.1*gr(p_est[i-1,],BooST1,BooST2,BooST3)
}
p_est = as.data.frame(p_est)
colnames(p_est) = c(&quot;p1&quot;,&quot;p2&quot;,&quot;p3&quot;)
p_est$iter = 1:10
</pre>
<p>Finally, the results. The dashed lines show the true optimal prices and the continuous lines show the algorithm moving towards the optimal values as we increase the iterations.</p>
<pre>dfm = melt(p_est,id.vars = &quot;iter&quot;)
ggplot(data = dfm) + geom_line(aes(x = iter, y = value, color = variable)) +
  theme_light() +
  geom_hline(yintercept = op[1],col = &quot;red&quot;,linetype = 2) +
  geom_hline(yintercept = op[2],col = &quot;green&quot;,linetype = 2) +
  geom_hline(yintercept = op[3],col = &quot;blue&quot;,linetype = 2)
</pre>
<p><img alt="plot of chunk unnamed-chunk-10" src="https://i1.wp.com/i.imgur.com/wbkJDV9.png?w=456&ssl=1" data-recalc-dims="1"></p>
<h2>Some observations</h2>
<ul>
<li>
<p>You could also use the gradient function we defined in the R function optim and find similar results. It is always good to use the analytical gradient in the optim, especially if we are optimizing on many variables.</p>
</li>
<li>
<p>We estimated three BooSTs, one for each product. However, it is possible to obtain the same results with only one BooST if we estimate the model straight on the profits without looking at the demand. The downside is that we will recover the individual demand functions separated from the profit.</p>
</li>
</ul>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://insightr.wordpress.com/2018/10/01/boost-series-ii-pricing-optimization/"> R – insightR</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/2YCAu7gen84" height="1"></a></div>