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 <- function(Price      = 10,
Var_Cost   = 5,
Units      = 100000,
Fixed_Cost = 10000) {

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

# Define profit function
Profit <- function(Price, Var_Cost, Units, Fixed_Cost)
(Price - Var_Cost) * Units - Fixed_Cost

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

Profit_New_Price       <- Profit(shock(Price), Var_Cost, Units, Fixed_Cost)
Profit_New_Var_Cost    <- Profit(Price, shock(Var_Cost), Units, Fixed_Cost)
Profit_New_Unit_Sales  <- Profit(Price, Var_Cost, shock(Units), Fixed_Cost)
Profit_New_Fixed_Costs <- Profit(Price, Var_Cost, Units, shock(Fixed_Cost))

diff_px <- function(px) px - Start_Profit
Diff_Profit_New_Price       <- diff_px(Profit_New_Price)
Diff_Profit_New_Var_Cost    <- diff_px(Profit_New_Var_Cost)
Diff_Profit_New_Unit_Sales  <- diff_px(Profit_New_Unit_Sales)
Diff_Profit_New_Fixed_Costs <- diff_px(Profit_New_Fixed_Costs)

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

fmt <- function(x) format(x, big.mark=",", scientific = FALSE)
msg <- 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 <- 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.