Economics for Tech People — Demand (Part 1)
By: Tyler Harris
Tags: Technology, Tech, Economics, R Programming, Education

The Code

Load Libraries

We will need the readxl and tidyverse libraries for this project. If you do not have them installed in your R environment, simply remove the “#” sign before the “install.packages…” lines of code [1]. Once they are installed, you will not need to install them again on your machine.

Here’s the code:

# If you do not have readxl or tidyverse installed, uncomment the following lines

# install.packages("readxl")

# install.packages("tidyverse") # Load Libraries

require(readxl)

require(tidyverse)

Check Data Import

Let’s check that the data came in okay. The code I have shows the way to read in the Excel file with code rather than button clicking. Make sure your Working Directory is set to the right place so you do not have to find the entire file path.

We will use the head() function to check the first few rows look good.

Here’s the code:

# Import data

Demand_Data <- read_excel("Demand_Data.xlsx") # Check data import

head(Demand_Data)

Here’s the output:

Screenshot of the first six rows of our demand data in RStudio on a Mac

Quick Test Plot

When working with economic data, it is always a good idea to just make a quick and dirty graph just to make sure that there is nothing weird going on. Remember, demand curves, with rare exception, trend down and to the right [2]. Let’s just pick a random column of Quantity to plot and make sure it passes the smell test here.

Here’s the code:

# Test plot

plot(Demand_Data$Qd_6, Demand_Data$Price, type = "l", main = "Test Plot", xlab = "Quantity", ylab = "Price")

Here’s the output:

Quick plot of one of the Quantity columns vs. price to check the data in RStudio on a Mac

I know, it is not the prettiest graph you have ever seen. The point is that we have data that generally slopes down and to the right, which is what we want to see! Thank you Law of Demand [2]!

Plot All Individual Demand Curves

Seeing one plot is great, but what about seeing all 10 of our individual demand curves at the same time? We will use the magic of ggplot to accomplish this.

If there is one thing I have learned about ggplot over time it is that the entire package is temperamental and only likes data a very specific way. Rather than try to fight the system, we need to structure our data in a way that plays nice with ggplot’s way of doing things.

So, we are going to use the stack() function to do a really neat job of wrangling our data from its current form in 10 different columns to a much smaller and more ggplot appropriate form where price and quantity data is labeled by Qd_# in 2 small columns of glory.

While we’re at it, we will go ahead and combine it into a single data frame with the price data to make a third column automatically putting the right price data with the right quantity and label data.

Finally, we’ll change the column names from the ones generated by the stack() function to make them a little more appropriate for our project.

Here’s the code:

# Wrangle the data into a ggplot friendly structure

Wrangled_Data <- data.frame(Price = Demand_Data$Price, stack(Demand_Data[2:11]))

names(Wrangled_Data)[2] <- "Quantity"

names(Wrangled_Data)[3] <- "Qd_num" # Check the data

head(Wrangled_Data)

Here’s the output:

First six rows of the wrangled and labeled demand data in a ggplot friendly structure in RStudio on a Mac

With that accomplished, we can much more easily use the facet_wrap() function with a few styling parameters to elegantly show all the individual demand curves.

Here’s the code:

# Plot the individual demand curves

ggplot(data = Wrangled_Data, aes(x = Quantity, y = Price)) +

geom_line(color = "steelblue", size = 1) +

geom_point(color = "steelblue") +

facet_wrap(. ~ Qd_num)

Here’s the output:

Screenshot of a plot of all the individual demand curves in the data set in RStudio on a Mac

There is a lot to unpack here! Let’s think about what these 10 plots of individual demands mean for us in our project of selling SaaS license subscriptions.

One observation that stands out to me is that many firms are not really buying many if any units above $5–6. As the price gets lower, most firms start to buy quite a lot more licenses. Some aren’t really buying many licenses no matter what the price is like firms 4, 8, and 10.

Others like firms 6, 7, and 9 are buying a lot of licenses and buying a lot more as the price goes down.

One of the fundamental concept is that individual firms have individual demands [2]. Some organizations simply value our SaaS application more than others, and lowering our price may not have much of an impact on their purchasing decision [2].

As a seller of monthly licenses, we need to be worried about the market demand. Let’s take a look at that.

Market Demand

The simplest definition for market demand is that it is the sum of all the individual firms’ demand curves [2]. This means that if we have 10 firms in our market, adding up all the quantities demanded and each price will give us the market demand curve [2].

Let’s take a look at how to assemble that.

Here’s the code:

# Create market demand

Market_Demand <- data.frame(Price = Demand_Data$Price, Market_Demand = rowSums(Demand_Data[2:11])) # Check the data

head(Market_Demand)

Here’s the output:

Screenshot of the market demand in RStudio on a Mac

Plot the Market Demand

Visualizing our data can be done with a little help from ggplot() by just plotting the sum of our quantities demanded for each price.

Here’s the code:

# Plot market demand

ggplot(data = Market_Demand, aes(x = Market_Demand, y = Price)) +

geom_line(color = "steelblue", size = 1) +

geom_point(color = "steelblue") +

geom_vline(xintercept = 0) +

geom_hline(yintercept = 0)

Here’s the output:

Screenshot of the plot of the market demand in RStudio on a Mac

When I look at this, I notice instantly that in certain ranges of this market demand curve that a change in price is not going to yield the same change in quantity demanded by the market at every point on the curve because it is not linear [2].

Visually inspect this, I see four distinct regions where we have similar slopes. Let’s take a look at that next and introduce the concept of elasticity.

Elasticity

Elasticity of demand is simply the idea of seeing how the combination of prices and quantities change between two points on a curve [2]. It can be mathematically stated as the percent change in quantity divided by the percent change in price [3].

In plain language, we are looking for the slope between two points just like we would using the classic y = mx + b formula from high school algebra class by looking specifically at that m value.

The business question from our point of view is:

By how much does the quantity demand change for each unit of price change?

What I did to illustrate the point is ranges of prices different elasticity zones. It might not be the most formal way in the world to do this, but you can really see that different areas along the market demand curve have different slopes in various ranges.

Here’s the code:

# Add Elasticity zones

# 10-6.5 zone 1

# 6-4 zone 2

# 3.5-2 zone 3

# 1.5-0 zone 4

Market_Demand$Elasticity_Zone <- as.character(c(1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,4,4,4,4))

Market_Demand

Here’s the output:

Screenshot of the market demand with elasticity zones in RStudio on a Mac

From a programming in R with ggplot point of view, it is really important to put the vector of numbers inside the as.character() function so that ggplot will automatically know that these are categorical values and not numbers to use for math [1]. We will see this in action in the next plot.

Plot Market Demand with Elasticity Zones

While ggplot can be frustrating at times, it does offer some great features. We are going to add on to our previous market demand code by adding color = Elasticity_Zone to the aes() function so that ggplot knows to assign a different color to each zone [1].

We also will add the geom_smooth() function with the method = “lm” parameter to have it make linear models for each elasticity zone [1]. We will make some dedicated models a little later to delve into that a bit further. For right now, this is clearly showing that different sections of the demand curve can have quite different slopes and elasticity numbers.

Here’s the code:

# Plot market demand with elasticity

ggplot(data = Market_Demand, aes(x = Market_Demand, y = Price, color = Elasticity_Zone)) +

geom_line(size = 1) +

geom_point() +

geom_smooth(method = "lm") +

geom_vline(xintercept = 0) +

geom_hline(yintercept = 0) +

ggtitle("Market Demand with Elasticity Zones") +

theme(plot.title = element_text(hjust = 0.5))

Here’s the output:

Screenshot of the elasticity zones in the market demand in RStudio on a Mac

Deeper Dive with Elasticity

While using linear models inside of the ggplot is great for visualization, we need to make some dedicated models to get precise slopes to compare the elasticity of each section in a meaningful way.

To do that, we will use the lm() function to create linear models. There are many ways to do this and filter the data, but the goal here is to be as explicit and readable as possible.

We will be doing the same basic process four times

Here’s the code:

### Create Linear Models ### # Filter Data

Zone_1_lm_data <- Market_Demand %>%

filter(Elasticity_Zone == 1) # Create linear model

Zone_1_lm <- lm(Market_Demand ~ Price, data = Zone_1_lm_data) # Create and print summary

summary(Zone_1_lm)

Here’s the output:

Screenshot of summary statistics for the linear model of Elasticity Zone 1 in RStudio on a Mac

Here’s the Code:

# Filter Data

Zone_2_lm_data <- Market_Demand %>%

filter(Elasticity_Zone == 2) # Create linear model

Zone_2_lm <- lm(Market_Demand ~ Price, data = Zone_2_lm_data) # Create and print summary

summary(Zone_2_lm)

Here’s the output:

Screenshot of summary statistics for the linear model of Elasticity Zone 2 in RStudio on a Mac

Here’s the Code:

# Filter Data

Zone_3_lm_data <- Market_Demand %>%

filter(Elasticity_Zone == 3) # Create linear model

Zone_3_lm <- lm(Market_Demand ~ Price, data = Zone_3_lm_data) # Create and print summary

summary(Zone_3_lm)

Here’s the output:

Screenshot of summary statistics for the linear model of Elasticity Zone 3 in RStudio on a Mac

Here’s the Code:

# Filter Data

Zone_4_lm_data <- Market_Demand %>%

filter(Elasticity_Zone == 4) # Create linear model

Zone_4_lm <- lm(Market_Demand ~ Price, data = Zone_4_lm_data) # Create and print summary

summary(Zone_4_lm)

Here’s the output:

Screenshot of summary statistics for the linear model of Elasticity Zone 4 in RStudio on a Mac

Now that we have some detailed summary statistics for the linear models for each Elasticity Zone, we need to interpret the results in the context of the project.

Just like with any linear model, we want to check that our model is of high enough quality to make a reliable interpretation. That means checking that all the p-values are statistically significant and that the R-squared values are as close to 1 as possible [1].

When we look at the Coefficients section of the output of each model and in the “Pr(>|t|)” column, we see that the coefficient of Price is a number that is smaller than 0.05 in all four models. That means that we can be at least 95% sure that our results are not due to chance [1]. In fact, we can be at least 99% sure that the relationship between price and quantity demand is not due to chance because all the p-values in this column are smaller than 0.01 [1].

Depending on who you ask, .7 and higher for either Multiple or Adjusted R-squared is pretty good [1]. R-squared measures how much of the dependent variable is explained by the independent variable(s) in the model [1]. In all four cases, we see we are explaining 99%+ of our dependent variable [1].

With that in mind, we want to look at the “Price” row in in the “Estimate” column for our slope value [1]. While it technically would be better to switch the price and quantity around to be more proper, it is easier to understand like this and really gets us to the same place for business purposes anyway [3].

Let’s just take a look at the last model of Zone 4. Here’s how you should read that:

As the price decreases by 1 unit, the quantity demanded increases by 540.4 units.

This aligns with the Law of Demand because as we lower our price, more units are demanded [2].

Once we know that everything is significant and does a good job of explaining the results, let’s make a comparison of results based on solid evidence.

Compare the Results

The simplest way to do this is going to be creating a little table with the slope coefficients pulled out from the summary statistics.

We will do this by making a data frame with labeled columns and viewing the output of the summary statistics as a table. The …coefficients[2,1]… part of the model is navigating through the output to get the second row and first column of the output of the summary statistics, which is the slope value [1]. Finally, we will round the results to 2 decimal places for our sanity and general readability.

Here’s the code:

# Create table of slope coefficients for each zone

slopes <- data.frame(Zone_1_slope = round(summary(Zone_1_lm)$coefficients[2,1], 2),

Zone_2_slope = round(summary(Zone_2_lm)$coefficients[2,1], 2),

Zone_3_slope = round(summary(Zone_3_lm)$coefficients[2,1], 2),

Zone_4_slope = round(summary(Zone_4_lm)$coefficients[2,1], 2))

slopes

Here’s the output:

Screenshot of the slope coefficients for all four linear models of each Elasticity Zone in RStudio on a Mac

Again, yes, I understand that is not technically a bunch of slopes in a purely mathematical sense [3]. It is really how much the quantity demanded changes per unit of price change [3]. It is just much easier to understand the idea this way.

Update the Market Demand Plot

Now it is time to quickly update the Market Demand plot from earlier by annotating the change in Quantity Demanded per unit of price so it is clear what is happening. We will need to paste some text and numbers together, position the text appropriately, and use the abs() function to get the absolute value of the numbers so they positive and easier to read.

Here’s the code:

# Plot market demand with elasticity

ggplot(data = Market_Demand, aes(x = Market_Demand, y = Price, color = Elasticity_Zone)) +

geom_line(size = 1) +

geom_point() +

geom_smooth(method = "lm") +

geom_vline(xintercept = 0) +

geom_hline(yintercept = 0) +

ggtitle("Market Demand with Elasticity Zones") +

theme(plot.title = element_text(hjust = 0.5)) +

annotate("text", label = paste("Qd change / P change:", abs(slopes$Zone_1_slope)), x = 430, y = 7, size = 3, color = "black") +

annotate("text", label = paste("Qd change / P change:", abs(slopes$Zone_2_slope)), x = 680, y = 4.5, size = 3, color = "black") +

annotate("text", label = paste("Qd change / P change:", abs(slopes$Zone_3_slope)), x = 1150, y = 2.5, size = 3, color = "black") +

annotate("text", label = paste("Qd change / P change:", abs(slopes$Zone_4_slope)), x = 1600, y = 1.5, size = 3, color = "black")

Here’s the output:

Screenshot of the market demand plot with labels of quantity change per unit of price in RStudio on a Mac

So what does this all really mean?

When prices are high, the market is relatively more inelastic than when prices are really low [2]. We get a much smaller effect in terms of number of subscriptions demanded when we move from a price of $10 to $9 than we do from $2 to $1 where the curve is relatively more elastic [2]. In fact, it is almost a 14x difference in number of subscriptions demanded going from a point in zone 1 to a point in zone 2.

The real question we need to ask here is:

How does this help us find where we would maximize total revenue?

Good question! Let’s quickly find out.

Maximum Total Revenue

First, we need to create a column to our market data that simply multiples price by quantity demanded to get total revenue [2].

Here’s the code:

# Maximize Total Revenue

Market_Demand$Total_Revenue = Market_Demand$Price * Market_Demand$Market_Demand # Check the data

Market_Demand

Here’s the output:

Screenshot of the total revenue for the market demand data in RStudio on a Mac

Plot the Data

Let’s make a plot to see where total revenue gets maximized.

Here’s the code:

# Plot market demand with elasticity

ggplot(data = Market_Demand, aes(x = Price, y = Total_Revenue, color = Elasticity_Zone)) +

geom_line(size = 1) +

geom_point() +

geom_vline(xintercept = 0) +

geom_hline(yintercept = 0) +

ggtitle("Total Revenue Curve for Market Demand with Elasticity Zones") +

theme(plot.title = element_text(hjust = 0.5))

Here’s the output:

Screenshot of the total revenue curve for the market data in RStudio on a Mac

Looking at the chart, we see that a price of $2.50 is where the maximum total revenue given our market demand data, which is the third elasticity zone. What this means is that as we raise the price from free to $2, we keep increasing revenue [2]. We maximize total revenue at a price of $2.50 with a total revenue of $1,850 [2]. As we continue raising the price from $3 and up, we actually make less revenue [2]!