We are interested in how costs respond to business decisions? Why?
Apple chooses how many devices to produce based projections of how costs and revenues will respond to this decision.2
Today we will focus on modelling the cost portion of this equation.
2: All my examples are Apple. Sorry.
Consider three firms that produce two products with quantities denoted $q_1$ and $q_2$. The three distinct cost functions are:
Output | Total Cost | Average Cost | Marginal Cost | Incremental Cost |
---|---|---|---|---|
$q_1, q_2$ | $q_1, q_2$ | $q_1, q_2$ | $q_1, q_2$ | |
100, 50 | ||||
60, 50 | ||||
40, 50 | ||||
30, 10 | ||||
30, 50 | ||||
30, 70 |
Let's fill this out using Python (don't panic), Excel (also don't panic).
We'll start with Excel
First we need to load some data science libraries:
# import pandas so we can put everything into a nice friendly data frame
import pandas as pd
import numpy as np
# lets put what we know into a dict (python dicts are POWERFUL use them when in doubt)
outputs = {
"q1" : [100, 60, 40, 30, 30, 30],
"q2" : [50, 50, 50, 10, 50, 70],
}
outputs
# use pandas to make that into a dataframe
cost_frame_1 = pd.DataFrame(outputs)
cost_frame_2 = pd.DataFrame(outputs)
cost_frame_3 = pd.DataFrame(outputs)
cost_frame_2
# write down our cost functions
## total cost
def cost_1(q1,q2):
return 10 * q1 + 5 * q2
def cost_2(q1,q2):
return 6 * q1 + q1**2 + 8 * q2 + q2**2 # note that we have to use ** inplace of ^ here
def cost_3(q1,q2):
return 7 * q1 + 9 * q2 + q1 * q2
cost_1(100,50)
cost_2(100,50)
cost_3(100,50)
Now we need to do this to all the data in the data frames
TotalCost1 = []
for q1,q2 in zip(outputs['q1'],outputs['q2']):
TotalCost1.append(cost_1(q1,q2))
print(TotalCost1)
TotalCost1 = [cost_1(q1,q2) for q1,q2 in zip(outputs['q1'],outputs['q2'])]
print(TotalCost1)
cost_frame_1["Total Cost"] = np.vectorize(cost_1)(cost_frame_1['q1'],cost_frame_1['q2'])
cost_frame_1
# we can do this for the other to firms:
cost_frame_2["Total Cost"] = np.vectorize(cost_2)(cost_frame_2['q1'],cost_frame_2['q2'])
cost_frame_3["Total Cost"] = np.vectorize(cost_3)(cost_frame_3['q1'],cost_frame_3['q2'])
cost_frame_2
The average cost of a each product is the total cost for producing that product alone devided by the number of units produced.
For firm 1 & 2 this is straightforward, each firm has an AC for each project where we plug in zero for the other product:
Let's do these and then come back to firm 3
One way to think of this is that average cost requires us to pretend that the firm only produces one product. When we can separate costs then this pretend firm tells us something about the real firm. When we cannot separate costs, this pretend firm does not tell us anything about the real firm!!
# avg cost by product
def avg_cost(cost_function,q1=0,q2=0):
"""
cost_function: the cost function you are averaging
pass either q1 or q2 but not both to tell which product to use
"""
if q1!=0 & q2!=0:
print("only pass one nonzero argument")
return None
else:
return cost_function(q1,q2) / (q1+q2)
# average cost the fast way
cost_frame_1["Average Cost q1"] = np.vectorize(avg_cost)(cost_1,q1=cost_frame_1['q1'])
cost_frame_1["Average Cost q2"] = np.vectorize(avg_cost)(cost_1,q2=cost_frame_1['q2'])
cost_frame_1
# average cost the fast way
cost_frame_2["Average Cost q1"] = np.vectorize(avg_cost)(cost_2,q1=cost_frame_2['q1'])
cost_frame_2["Average Cost q2"] = np.vectorize(avg_cost)(cost_2,q2=cost_frame_2['q2'])
cost_frame_2
The marginal cost is the derivative of the cost function wrt. the product.
let's make python do the work
# we'll use symbolic python
import sympy as sp
# we need to tell it which symbols to use
q1,q2 = sp.symbols('q1 q2')
# sympy can take the derivative for us
c1 = "10 * q1 + 5 * q2"
s_mcost_1_q1 = sp.diff(c1 , q1)
s_mcost_1_q2 = sp.diff(c1 , q2)
print(s_mcost_1_q1,s_mcost_1_q2)
10 5
# and we can convert that to a function
mcost_1_q1 = sp.lambdify(q1,s_mcost_1_q1)
mcost_1_q2 = sp.lambdify(q2,s_mcost_1_q2)
mcost_1_q1(100),mcost_1_q2(100)
# marginal cost
cost_frame_1["Marginal Cost q1"] = np.vectorize(mcost_1_q1)(cost_frame_1['q1'])
cost_frame_1["Marginal Cost q2"] = np.vectorize(mcost_1_q2)(cost_frame_1['q2'])
cost_frame_1
q1,q2 = sp.symbols('q1 q2')
# sympy can take the derivative for us
c2 = "6 * q1 + q1**2 + 8 * q2 + q2**2"
s_mcost_2_q1 = sp.diff(c2 , q1)
s_mcost_2_q2 = sp.diff(c2 , q2)
print(s_mcost_2_q1,s_mcost_2_q2)
# and we can convert that to a function
mcost_2_q1 = sp.lambdify(q1,s_mcost_2_q1)
mcost_2_q2 = sp.lambdify(q2,s_mcost_2_q2)
mcost_2_q1(100),mcost_2_q2(50)
# marginal cost
cost_frame_2["Marginal Cost q1"] = np.vectorize(mcost_2_q1)(cost_frame_2['q1'])
cost_frame_2["Marginal Cost q2"] = np.vectorize(mcost_2_q2)(cost_frame_2['q2'])
cost_frame_2
q1,q2 = sp.symbols('q1 q2')
# sympy can take the derivative for us
c3 = "7*q1 + 9*q2 + q1*q2"
s_mcost_3_q1 = sp.diff(c3 , q1)
s_mcost_3_q2 = sp.diff(c3 , q2)
print(s_mcost_3_q1,s_mcost_3_q2)
# and we can convert that to a function
# note tht we flip the inputs to match the function
mcost_3_q1 = sp.lambdify(q2,s_mcost_3_q1)
mcost_3_q2 = sp.lambdify(q1,s_mcost_3_q2)
mcost_3_q1(50),mcost_3_q2(100)
# marginal cost
cost_frame_3["Marginal Cost q1"] = np.vectorize(mcost_3_q1)(cost_frame_3['q2'])
cost_frame_3["Marginal Cost q2"] = np.vectorize(mcost_3_q2)(cost_frame_3['q1'])
cost_frame_3
Which I find a little easier to write than to say :)
# incremental cost if the cost of making the next unit by product
def inc_cost(cost_function,q1=q1,q2=q2,increment=str):
'''
cost_function: total cost function that you'd like to increment (over q1,q2)
q1: the quantity you'd like to pass to the cost func as q1, defaults q1
q2: same, default q2
increment: the quantity you'd like to increment
'''
C_0 = cost_function(q1,q2)
if increment == "q1":
q1=q1+1
elif increment == "q2":
q2=q2+1
else:
print("increment must be one of q1,q2")
return None
C_1 = cost_function(q1,q2)
return C_1 - C_0
# Incremental cost
cost_frame_1["Incremental Cost q1"] = np.vectorize(inc_cost)(
cost_1,
cost_frame_1['q1'],
cost_frame_1['q2'],
increment="q1"
)
cost_frame_1["Incremental Cost q2"] = np.vectorize(inc_cost)(
cost_1,
cost_frame_1['q1'],
cost_frame_1['q2'],
increment="q2"
)
cost_frame_1
# Incremental cost
cost_frame_2["Incremental Cost q1"] = np.vectorize(inc_cost)(
cost_2,
cost_frame_2['q1'],
cost_frame_2['q2'],
increment="q1"
)
cost_frame_2["Incremental Cost q2"] = np.vectorize(inc_cost)(
cost_2,
cost_frame_2['q1'],
cost_frame_2['q2'],
increment="q2"
)
cost_frame_2
# Incremental cost
cost_frame_3["Incremental Cost q1"] = np.vectorize(inc_cost)(
cost_3,
cost_frame_3['q1'],
cost_frame_3['q2'],
increment="q1"
)
cost_frame_3["Incremental Cost q2"] = np.vectorize(inc_cost)(
cost_3,
cost_frame_3['q1'],
cost_frame_3['q2'],
increment="q2"
)
cost_frame_3
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np # we already have np
# Create data for the plot
q1 = np.linspace(0, 1_000, 1_000)
q2 = np.linspace(0, 1_000, 1_000)
Q1, Q2 = np.meshgrid(q1, q2)
# calc costs
C1 = 10 * Q1 + 5 * Q2
C2 = 6 * Q1 + Q1**2 + 8 * Q2 + Q2**2
C3 = 7 * Q1 + 9 * Q2 + Q1 * Q2
# Create the figure and add a 3D axis
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Plot the data
ax.plot_surface(Q1, Q2, C1)
# ax.plot_surface(Q1, Q2, C2)
# ax.plot_surface(Q1, Q2, C3)
# Set axis labels and show the plot
ax.set_xlabel('Q1')
ax.set_ylabel('Q2')
ax.set_zlabel('Cost')
plt.show()