import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from numpy.polynomial import polynomial as P
64 Optimal nitrogen rate
Dataset description: Fertilized corn crop in Nebraska.
Corn Trial conducted jointly with Dennis Francis and Jim Schepers, USDA-ARS, University of Nebraska, Lincoln, NE. Corn trial located near Shelton, NE. Harvested in October, 2003
Source: http://www.nue.okstate.edu/Nitrogen_Conference2003/Corn_Research.htm
# Define auxiliary function for computing the root mean squared error (RMSE)
= lambda obs,pred: np.sqrt(np.mean((obs - pred)**2)) rmse_fn
# Fit polynomial: Example using yield responses to nitrogen rates
= [118, 165, 170, 193, 180, 181, 141, 177, 165, 197, 175] # Corn yield
yield_obs = [0, 89, 161, 165, 80, 160, 37, 105, 69, 123, 141] nitrogen_obs
# Visualize field observations
=(5,4))
plt.figure(figsize='w', edgecolor='k')
plt.scatter(nitrogen_obs, yield_obs, facecolor'Nitrogen rate (kg/ha)')
plt.xlabel('Yield rate (kg/ha)')
plt.ylabel( plt.show()
# Fit polynomial model
= P.polyfit(nitrogen_obs, yield_obs, 2)
par print(par)
# Use P.polyval? to access function help
[ 1.15569115e+02 9.61329119e-01 -3.41221057e-03]
# Compute fitting error
# Compute
= P.polyval(nitrogen_obs, par)
yield_pred
= rmse_fn(yield_obs, yield_pred)
rmse print(round(rmse,1),'kg/ha')
8.4 kg/ha
# Compute fitted curve
= np.min(nitrogen_obs)
N_min = np.max(nitrogen_obs)
N_max
= np.linspace(N_min, N_max, 50)
nitrogen_curve = P.polyval(nitrogen_curve, par) yield_curve
# Find index at which yield in the nitrogen curve is highest
= np.argmax(yield_curve)
idx_yield_max
# Use the index to retrieve the optinal nitrogen rate at which yield is maximum
= nitrogen_curve[idx_yield_max]
N_opt
# Find min and max yield
= np.max(yield_curve)
Y_max = np.min(yield_curve)
Y_min
print(f'The optimal N rate is {N_opt:.1f} kg/ha')
The optimal N rate is 141.4 kg/ha
We can also find the optimal Nitrogen rate by approximating the first derivative of the function. Note that np.diff()
will return an array that is one-element shorter.
= np.argmin(np.abs(np.diff(yield_curve, 1)))
idx +1] nitrogen_curve[idx
# Visualize field observations
=(5,4))
plt.figure(figsize='w', edgecolor='k', label='Observations')
plt.scatter(nitrogen_obs, yield_obs, facecolor
plt.plot(nitrogen_curve, yield_curve, ='tomato',linestyle='dashed', linewidth=2, label='Fit')
color
='k')
plt.axvline(N_opt, color'Nitrogen rate (kg/ha)')
plt.xlabel('Yield rate (kg/ha)')
plt.ylabel(
plt.legend() plt.show()
Analytical solution
We can also use the Sympy module in Python to solve the equation analytically (exact solution). Remember that the optimal nitrogen rate is when yield no longer responds to additional nitrogen fertilizer. Thus, the optimal nitrogen rate occurs when the rate of change of yield as a function of nitrogen rate is zero.
# Import sympy module
from sympy import symbols, diff, solve, lambdify
# Define the variable and coefficients of the quadratic polynomial
= symbols('x')
x = symbols('a b c')
a, b, c
# Define the quadratic polynomial
= a + b*x + c*x**2
polynomial
# Compute the first derivative of the polynomial with respect to x
= diff(polynomial, x)
first_derivative
# Solve for x where the first derivative equals zero
# Solve accepts: a single Expr or Poly that must be zero
= solve(first_derivative, x)
solution print(solution)
[-b/(2*c)]
# Convert symbolic solution into lambda function
= lambdify((b,c),solution) fun
# Call the new lambda function with b and c coefficients as inputs
1],par[2]) fun(par[
[140.86603077026513]
The above answer represents the exact optimal nitrogen rate. THe value that we obtained earlier using the yield curve is very close to this value.