Learn Decision making under uncertainty — Part 1: Solve the problem with mean values | by Ramakrishna Thiruveedhi | Towards Data Science

Many decision-making problems can be solved as a linear system of equations. Handling uncertainty in the problem is not straightforward. In this series of articles, we will explore the concept of using Stochastic Programming on a simple business problem. This first article covers the basic approach of building a model that can solve the problem based on mean values. It is important to get the problem modeled this way before we can handle uncertainty. We will solve the problem in python using an open-source solver that has these algorithms under the hood.
In future articles, we will change this model to account for uncertainty and improve the solution we find here.
Linear equations
Probability, Expected value
Note: The news vendor problem is another problem used to learn this topic. There are several articles already on medium. This farmer problem gives a different perspective especially the decisions made after the future is revealed. This problem has been explained in textbooks (see references below) but getting solutions requires using linear programming software. Using Python makes it easier to experiment and visualize solutions without installing new software or obtaining licenses.
Solving system of linear equations in Python
Computing expected value of any solution especially the “Mean value solution” using Python
An intuitive explanation of solution (optional)
A farmer is planning her crops for the season this year. The crops produced will be used to feed cattle until next year. The remaining crops can be sold in the open market.
The farmer has to decide how many acres to plant for each crop. She has a total of 500 acres available on the farm. Planting costs per crop are shown in the table below. The average yield is given for each crop. In bad season yield is only 80% and in good season yield increases to120%. The probability of these scenarios is equal (33%). The average yield per crop is shown in the table below.
When the growing season ends farmer knows how much crop is produced from the farm based on the yield. To meet the consumption needs on the farm until next season, the farmer can also buy the crops (only wheat and corn) in the open market. Excess crops can be sold into the market. Please note that beans are not needed on the farm but can be grown for a good profit until 6000 Tons and a much-reduced price over 6000 Tons.
Do we have enough information to solve the problem? What are our yields? Let us assume our yield is average and try to plan acres allocated to each crop. This is a very reasonable approach since it accounts for both bad yields and good yields. Many linear and mixed inter programming models are being built to solve business problems using this approach.
We will solve this problem by using a system of linear equations. I would recommend running the notebook step by step to understand the following.
The farmer has several decisions to make. We can think of the decisions being made at two stages — before the yield is known and after the yield is known. Hence problem like this is called a Two-stage Stochastic Programming problem. However, for this problem just like the Newsvendor problem, the second stage decisions are trivial (do not buy more crops than what we need for cattle, sell all remaining amounts).
Acres to plant for each crop (First stage)
Amount to buy for Wheat and Corn (Second stage)
Amount to sell for Wheat, Corn, and Beans (Second stage)
Excess amount of beans to sell at a lower price (Second stage)
Objective:
The farmer wants us to maximize profit at end of the season. We get revenue from selling crops remaining at end of the season after cattle consumption. We incur costs from planting costs before the season and from buying wheat and corn to feed cattle.
Maximize Profit =
Revenue for crop sales at end of season — Cost of buying Wheat and Corn deficits — Cost of planting crops
M = LpProblem("Farmer", LpMaximize)M += lpSum(       [      selling_prices[item]       * var_tons_sold[item]        for item in items ]    + [      selling_price_excess_beans * var_excess_beans_sold]     #excess beans    + [ -1 * planting_costs[item]       * var_acres_planted[item]    for item in items ]      + [ -1 * purchase_prices[item]      * var_tons_purchased[item]   for item in purchasable_items ]    )
Farm Acres Available
Acres Planted for all crops ≤ 500
M += lpSum([var_acres_planted[item] for item in items]) <= total_acres
For Wheat and Corn:
Crops produced by planting + Crops purchased = Crops used for consumption + Crops sold to market
M += lpSum([yields[item] * var_acres_planted[item]] + [var_tons_purchased[item]] + [-1 * var_tons_sold[item]]) == consumption_feed[item]
For Beans:
Crops produced by planting - Crops sold to the market at regular price — Crops sold to the market at a lower price = Consumption for beans ( 0 for our farmer)
Crops sold to the market at regular price ≤ 6000 T
M += lpSum([yields[item] * var_acres_planted[item]] + [-1 * var_tons_sold[item]] + [-1 * var_excess_beans_sold]) == consumption_feed[item]    M += lpSum([var_tons_sold[item]]) <= limit_on_beans_regular_price
The system of equations can be solved in any linear programming solver. Even though plugins are available for Excel, a modeling language is easier to use and is necessary for solving the stochastic version of this problem. Commerical solvers (IBM CPLEX, Gurobi, FICO Xpress, AMPL, etc.) can be used for this purpose but they need installation. Some commercial solvers have python APIs but they need licensing. Commercial solvers may be a better choice for production systems with better performance and customer support. For purpose of learning, I have chosen the open-source Python package PuLP to allow anyone to run the notebook with minimal installation.
The notebook can be found here. Please install PuLPusing conda or pip.
pip install pulp
We can run the solver and obtain an optimal solution and use python to compute the following table to compute costs, revenue, and profit. The solution is to plan beans to sell 6000 Tons at a higher price, produce enough corn to feed cattle and use the rest of the acres to produce wheat.
We already know the profit if yields are average (118600) from the optimal solution to mean value yields (see table above).
If yields are bad and we had already planted based on our solution from average yield we will realize the following results. (no real decisions to be made — we have to buy deficits 48 in this case and sell the remaining)
Similarly, we can compute profit if we realize good yields
If the farmer decides to implement our recommendation based on average yields she will get an optimal profit of 118600 33% of the time but also get profits of 55120 and 148000. Her expected profit, in the long run, can be computed as below (over 99 seasons he will realize each profit 33 times).
EV of mean value Solution = (55120+118600+148000)/3= $107240
Please note that this is lower than what we hoped ($118600). This is due to the fact we planned based on average yield — the profit we gain in good years does not make up for the loss of profit in bad years.
Use the notebook to explore how solutions will change in the following scenarios.
What are the optimal solutions if we use other yields instead of average yields? (Hint: Use the notebook to change yield).
If the farmer has an optimistic or pessimistic bias and wants us to use either of the optimal solutions found using BAD or GOOD yields, what will be the expected value of using those solutions? How do they compare to using the mean value solution? Crosscheck your answers with the table below. For this example, it looks like an optimistic farmer who wants to use our solution based on good yields will do better compared to using an average yield. Please note that our mean value solution is close.
Can we use all three optimal solutions simultaneously? Since we do not know which season will have which yield, we can do this only if we can hire an oracle or machine learning expert who can predict the yield with 100% accuracy. We can compute the expected value of this approach so that we can establish an upper bound for the profit. In this case it is 1/3(59950+118600+167666) = $115406. So our mean value solution is doing well ($107240) but there is room for improvement. If the farmer is not too excited about the $8166 increase, we do not need to invest more effort to improve our profit.
Is there a solution that maximizes our expected profit, not for a given yield but all three yields simultaneously? Yes, there is and that solution should have a profit between $107240 and $115406. We will cover that in the next article.
We have modeled business problem as a system of linear equations
We used Python and Pulp to obtain a solution based on the average scenario. This notebook can be used to evaluate tradeoffs between all parameters.
We know the expected value of this solution even if other scenarios were to happen. This will be the benchmark we will try to beat by adding stochastic elements to our linear program.
With the understanding of how different solutions will behave under the three different scenarios, we are ready to move from linear programming to stochastic programming.
I will limit my references to resources that explain basics and refer to this problem.
[1] J. Linderoth, Class Notes covering this problem. Additional notes
[2] J. Birge, F. Louveaux, Textbook: Introduction to Stochastic Programming — this problem is covered in chapter 1.
[3] Official site for PuLP solver in Python
Read this section only to get an intuition of tradeoffs. Methods like this will not guarantee optimality in the presence of complex constraints. Also, this method is not possible once we start doing stochastic programming.
Can we take a greedy approach by allocating each acre to a crop that gives us maximum profit until we hit a constraint?
Let's compute the profit per acre for each crop. Since we are planning for the average case, we will use average yields.
For Wheat it is 2.5 * 170 -150 = 275 $ per acreSimilarly, for corn, it is 220 and for beans, it is 460 (at regular price) and -60 (at a reduced price).
However for Wheat and Corn until we meet the farm needs the profit comes from cost savings the farmer gains from avoiding purchasing them at a much higher price. In other words, until he meets consumption needs he can increase his profit by selling to himself (at the buyer’s price). For Wheat, it is 2.5*238–150 = 445 and for Corn, it is 400. These numbers are important to consider until we can meet the farm’s consumption.
Sort the marginal profits in decreasing order: 460 (sell beans), 445 (produce wheat to meet needs), 400 (produce corn to meet needs), 275 (produce wheat to sell), 220 (produce corn to sell), -60 (produce beans to sell at a lower price)
Execute the steps for each profit margin until farm acres are consumed or until the margin disappears.
Produce beans using 300 acres until marginal profit disappears at 6000 units. Acres left = 200Produce wheat using 80 acres to meet the farm’s needs. Acres left = 120Produce corn using 80 acres to meet the farm’s needs. Acres left = 40Produce wheat using 40 acres to sell to the market. Acres left = 0
Produce beans using 300 acres until marginal profit disappears at 6000 units. Acres left = 200
Produce wheat using 80 acres to meet the farm’s needs. Acres left = 120
Produce corn using 80 acres to meet the farm’s needs. Acres left = 40
Produce wheat using 40 acres to sell to the market. Acres left = 0
This gives us the solution: Wheat 120 acres, Corn 80 acres, and Beans 300 acres.
It turns out our intuitive solution is indeed optimal since there are no other complex constraints.
Note: To understand the intuition behind this approach try changing the sale price of beans — both primary and secondary.
There are a couple of inflection points where the marginal profit of beans matches producing wheat and corn for consumption = 33 and 35.25 (Hint: you can compute these easily by solving simple equations). At a price lower than 33 we should produce wheat and corn before we produce beans for sale.
There are a couple of inflection points where the marginal profit of beans matches producing corn for sale at 24 and 26.75. At a price lower than 24 we should produce wheat and corn for consumption first, sale next, and then only we produce beans for sale.
Check out new articles on this topic at my medium profile. If you would like to contact me here is my LinkedIn.