Profit sensitivity analysis in base R Using base R, I've conducted a simple profit sensitivity analysis, i.e. measuring the impact on profit if there is a change in price, variable cost per sale, unit sales or fixed costs assuming that there are no interaction effects between the dependent variables, e.g. a change in price does not change unit sales.

I'd like to have feedback on my code, which is 'just for fun'. Particularly I'm interested in:


Making the loops slicker
Assigning the matrices full of zeroes with fewer bytes if I can




# Aim: conduct a profit sensitivity analysis

# Define parameters

Param   = c(10,5,100000,10000) # I.e. a business with a price, variable cost, unit sales and fixed cost of these values

Max_Change  = 0.1
Changes     = seq(-Max_Change, Max_Change, by=0.01)

# Define profit function

Profit  = function(Price, Var_Cost, Units, Fixed_Cost){
Profit  = (Price - Var_Cost)*Units - Fixed_Cost
return(Profit)
}

# Calculating base and updated profit

Start_Profit = do.call("Profit", as.list(Param))

New_Price       = matrix(0,length(Changes),4)
New_Var_Cost    = matrix(0,length(Changes),4)
New_Unit_Sales  = matrix(0,length(Changes),4)
New_Fixed_Costs     = matrix(0,length(Changes),4)

for(i in 1:length(Changes))
{
New_Price[i,]       = c((1+Changes[i])*Param[1], Param[2], Param[3], Param[4])
New_Var_Cost[i,]        = c(Param[1], (1+Changes[i])*Param[2], Param[3], Param[4])
New_Unit_Sales[i,]  = c(Param[1], Param[2], (1+Changes[i])*Param[3], Param[4])
New_Fixed_Costs[i,]     = c(Param[1], Param[2], Param[3], (1+Changes[i])*Param[4])
}

Profit_New_Price        = matrix(0,length(Changes),1)
Profit_New_Var_Cost     = matrix(0,length(Changes),1)
Profit_New_Unit_Sales   = matrix(0,length(Changes),1)
Profit_New_Fixed_Costs  = matrix(0,length(Changes),1)

for(i in 1:length(Changes))
{
Profit_New_Price[i,]        = do.call("Profit", as.list(New_Price[i,]))
Profit_New_Var_Cost[i,]     = do.call("Profit", as.list(New_Var_Cost[i,]))
Profit_New_Unit_Sales[i,]   = do.call("Profit", as.list(New_Unit_Sales[i,]))
Profit_New_Fixed_Costs[i,]  = do.call("Profit", as.list(New_Fixed_Costs[i,]))
}

Diff_Profit_New_Price       = Profit_New_Price-Start_Profit
Diff_Profit_New_Var_Cost    = Profit_New_Var_Cost-Start_Profit
Diff_Profit_New_Unit_Sales  = Profit_New_Unit_Sales-Start_Profit
Diff_Profit_New_Fixed_Costs     = Profit_New_Fixed_Costs-Start_Profit

# Plot the profit sensitivities

options(scipen=999) # Remove scientific notation from the chart axes

msg=paste("Starting Business Conditions: Price = £",
    format(Param[1],big.mark=",",scientific=FALSE),
    ", Variable Cost = £",
    format(Param[2],big.mark=",",scientific=FALSE),
    ", Unit Sales = ",
    format(Param[3],big.mark=",",scientific=FALSE),
    ", Fixed Costs = £",
    format(Param[4],big.mark=",",scientific=FALSE),
    ", Giving a Profit of £",
    format(Start_Profit,big.mark=",",scientific=FALSE))

plot(100*Changes,Diff_Profit_New_Price,
    xlab="Change in Dependent Variable (%)",
    ylab="Change in Profit (£)",
    main="Profit Sensitivity Analysis of Changing One Variable at a Time, Assuming no Interaction Among Dependent Variables",
    type="l",
    sub=msg)

lines(100*Changes, Diff_Profit_New_Var_Cost, col="red")
lines(100*Changes, Diff_Profit_New_Unit_Sales, col="blue")
lines(100*Changes, Diff_Profit_New_Fixed_Costs, col="green")

# Building legend

Leg_Names = c("Price Change", "Variable Cost Change", "Unit Sales Change", "Fixed Costs Change")
legend("bottomright",
    legend=Leg_Names,
    col=c("black","red","blue","green"),
    pch=15,
    bty="n")
The main thing to note is that your profit function only uses vectorized functions (- and *) so it is vectorized with respect to its four inputs. This means that you do not have to create loops; instead you can just feed the functions with vector(s): one vector for the variable that you are shocking, and scalars for the other three fixed inputs. Here is my suggested rewrite, having put everything into a function:

biz_sens_analysis &lt;- function(Price      = 10,
                              Var_Cost   = 5,
                              Units      = 100000,
                              Fixed_Cost = 10000) {

  Max_Change &lt;- 0.1
  Changes &lt;- seq(-Max_Change, Max_Change, by = 0.01)
  shock &lt;- function(x) x * (1 + Changes)

  # Define profit function
  Profit &lt;- function(Price, Var_Cost, Units, Fixed_Cost)
     (Price - Var_Cost) * Units - Fixed_Cost

  # Calculating base and updated profit
  Start_Profit &lt;- Profit(Price, Var_Cost, Units, Fixed_Cost)

  Profit_New_Price       &lt;- Profit(shock(Price), Var_Cost, Units, Fixed_Cost)
  Profit_New_Var_Cost    &lt;- Profit(Price, shock(Var_Cost), Units, Fixed_Cost)
  Profit_New_Unit_Sales  &lt;- Profit(Price, Var_Cost, shock(Units), Fixed_Cost)
  Profit_New_Fixed_Costs &lt;- Profit(Price, Var_Cost, Units, shock(Fixed_Cost))

  diff_px &lt;- function(px) px - Start_Profit
  Diff_Profit_New_Price       &lt;- diff_px(Profit_New_Price) 
  Diff_Profit_New_Var_Cost    &lt;- diff_px(Profit_New_Var_Cost)
  Diff_Profit_New_Unit_Sales  &lt;- diff_px(Profit_New_Unit_Sales)
  Diff_Profit_New_Fixed_Costs &lt;- diff_px(Profit_New_Fixed_Costs)

  # Plot the profit sensitivities
  options(scipen = 999) # Remove scientific notation from the chart axes

  fmt &lt;- function(x) format(x, big.mark=",", scientific = FALSE)
  msg &lt;- paste("Starting Business Conditions: Price = £", fmt(Price),
             ", Variable Cost = £",    fmt(Var_Cost),
             ", Unit Sales = ",        fmt(Units),
             ", Fixed Costs = £",      fmt(Fixed_Cost),
             ", Giving a Profit of £", fmt(Start_Profit))

  plot(100 * Changes, Diff_Profit_New_Price,
     xlab = "Change in Dependent Variable (%)",
     ylab = "Change in Profit (£)",
     main = "Profit Sensitivity Analysis of Changing One Variable at a Time, Assuming no Interaction Among Dependent Variables",
     type = "l",
     sub  = msg)

  lines(100 * Changes, Diff_Profit_New_Var_Cost,    col = "red")
  lines(100 * Changes, Diff_Profit_New_Unit_Sales,  col = "blue")
  lines(100 * Changes, Diff_Profit_New_Fixed_Costs, col = "green")

  # Building legend
  Leg_Names &lt;- c("Price Change", "Variable Cost Change", "Unit Sales Change", "Fixed Costs Change")
  legend("bottomright",
         legend = Leg_Names,
         col    = c("black", "red", "blue", "green"),
         pch    = 15,
         bty    = "n")
}

biz_sens_analysis()


Hope it helps. Let me know if you have questions.