AGRICULTURE
Overview
The AGRICULTURE function fits specialized mathematical models for agricultural yield analysis to experimental data using non-linear least squares regression. These models are commonly used in crop science and agronomy to describe relationships between plant density, fertilizer application, and crop yield.
This function implements eight yield-density and fertilizer response models:
- Bleasdale-Nelder Yield Density: A four-parameter model (a, b, c, f) for yield-density relationships: y = (a + bx^f)^{-1/c}
- Bleasdale-Nelder Simplified: A three-parameter simplification: y = (a + bx)^{-1/c}
- Farazdaghi-Harris Competition: Models inter-plant competition: y = (a + bx^c)^{-1}
- Holliday Yield Density Quadratic: Includes quadratic density effects: y = (a + bx + cx^2)^{-1}
- Holliday Modified Rational: A rational function form: y = a / (1 + bx + cx^2)
- Nelder Fertilizer Response: Models fertilizer response curves with an asymptotic maximum
- Yield-Fertilizer Exponential Decay: Models diminishing returns: y = a + br^x where 0 < r < 1
- Yield-Fertilizer Natural Exponential: Uses natural exponential decay: y = a + be^{-kx}
The function uses scipy.optimize.curve_fit to perform the optimization via the Levenberg-Marquardt algorithm. For each model, intelligent initial parameter guesses are computed from the input data to improve convergence. The function returns the fitted parameter values along with their standard errors, which are derived from the covariance matrix of the fit.
These models originate from foundational agricultural research, including work by Bleasdale and Nelder (1960) on plant competition, Holliday (1960) on yield-density relationships, and Farazdaghi and Harris (1968) on competitive interactions. For more information on non-linear curve fitting methodology, see the SciPy optimization documentation.
This example function is provided as-is without any representation of accuracy.
Excel Usage
=AGRICULTURE(xdata, ydata, agriculture_model)
xdata(list[list], required): The xdata valueydata(list[list], required): The ydata valueagriculture_model(str, required): The agriculture_model value
Returns (list[list]): 2D list [param_names, fitted_values, std_errors], or error string.
Examples
Example 1: Demo case 1
Inputs:
| agriculture_model | xdata | ydata |
|---|---|---|
| bleasdale_nelder_yield_density | 0.1 | 0.5672982383388386 |
| 1.3250000000000002 | 0.33957893215370566 | |
| 2.5500000000000003 | 0.07329429756158326 | |
| 3.7750000000000004 | 0.012377205194408224 | |
| 5 | 0.013794171321237347 |
Excel formula:
=AGRICULTURE("bleasdale_nelder_yield_density", {0.1;1.3250000000000002;2.5500000000000003;3.7750000000000004;5}, {0.5672982383388386;0.33957893215370566;0.07329429756158326;0.012377205194408224;0.013794171321237347})
Expected output:
"non-error"
Example 2: Demo case 2
Inputs:
| agriculture_model | xdata | ydata |
|---|---|---|
| bleasdale_nelder_simplified | 0.1 | 0.5516374948796566 |
| 1.3250000000000002 | 0.4493055231416069 | |
| 2.5500000000000003 | 0.3839515385505842 | |
| 3.7750000000000004 | 0.3333955941114058 | |
| 5 | 0.3065391490538524 |
Excel formula:
=AGRICULTURE("bleasdale_nelder_simplified", {0.1;1.3250000000000002;2.5500000000000003;3.7750000000000004;5}, {0.5516374948796566;0.4493055231416069;0.3839515385505842;0.3333955941114058;0.3065391490538524})
Expected output:
"non-error"
Example 3: Demo case 3
Inputs:
| agriculture_model | xdata | ydata |
|---|---|---|
| farazdaghi_harris_competition | 0.1 | 0.3645280967136649 |
| 1.3250000000000002 | 0.23084459235849314 | |
| 2.5500000000000003 | 0.12735361747704974 | |
| 3.7750000000000004 | 0.06958788363231085 | |
| 5 | 0.05160629269753579 |
Excel formula:
=AGRICULTURE("farazdaghi_harris_competition", {0.1;1.3250000000000002;2.5500000000000003;3.7750000000000004;5}, {0.3645280967136649;0.23084459235849314;0.12735361747704974;0.06958788363231085;0.05160629269753579})
Expected output:
"non-error"
Example 4: Demo case 4
Inputs:
| agriculture_model | xdata | ydata |
|---|---|---|
| holliday_yield_density_quadratic | 0.1 | 0.35168646655190283 |
| 1.3250000000000002 | 0.14611622513801112 | |
| 2.5500000000000003 | 0.0644988821745923 | |
| 3.7750000000000004 | 0.02673172343382443 | |
| 5 | 0.021830092073556524 |
Excel formula:
=AGRICULTURE("holliday_yield_density_quadratic", {0.1;1.3250000000000002;2.5500000000000003;3.7750000000000004;5}, {0.35168646655190283;0.14611622513801112;0.0644988821745923;0.02673172343382443;0.021830092073556524})
Expected output:
"non-error"
Example 5: Demo case 5
Inputs:
| agriculture_model | xdata | ydata |
|---|---|---|
| holliday_modified_rational | 0.1 | 2.476514135825012 |
| 1.3250000000000002 | 0.5593798396545494 | |
| 2.5500000000000003 | 0.22005645510585548 | |
| 3.7750000000000004 | 0.055582501026831814 | |
| 5 | 0.07375803414954989 |
Excel formula:
=AGRICULTURE("holliday_modified_rational", {0.1;1.3250000000000002;2.5500000000000003;3.7750000000000004;5}, {2.476514135825012;0.5593798396545494;0.22005645510585548;0.055582501026831814;0.07375803414954989})
Expected output:
"non-error"
Example 6: Demo case 6
Inputs:
| agriculture_model | xdata | ydata |
|---|---|---|
| nelder_fertilizer_response | 0.1 | 0.22776420617719842 |
| 1.3250000000000002 | 0.1787121171937119 | |
| 2.5500000000000003 | 0.14815038131711614 | |
| 3.7750000000000004 | 0.12726844779262309 | |
| 5 | 0.10676484833455836 |
Excel formula:
=AGRICULTURE("nelder_fertilizer_response", {0.1;1.3250000000000002;2.5500000000000003;3.7750000000000004;5}, {0.22776420617719842;0.1787121171937119;0.14815038131711614;0.12726844779262309;0.10676484833455836})
Expected output:
"non-error"
Example 7: Demo case 7
Inputs:
| agriculture_model | xdata | ydata |
|---|---|---|
| yield_fertilizer_exponential_decay | 0.1 | 3.7475442808523565 |
| 1.3250000000000002 | 3.223161367719532 | |
| 2.5500000000000003 | 2.9896743124843193 | |
| 3.7750000000000004 | 2.8859095042201393 | |
| 5 | 2.7988484749968507 |
Excel formula:
=AGRICULTURE("yield_fertilizer_exponential_decay", {0.1;1.3250000000000002;2.5500000000000003;3.7750000000000004;5}, {3.7475442808523565;3.223161367719532;2.9896743124843193;2.8859095042201393;2.7988484749968507})
Expected output:
"non-error"
Example 8: Demo case 8
Inputs:
| agriculture_model | xdata | ydata |
|---|---|---|
| yield_fertilizer_natural_exponential | 0.01 | 3.7582088335464605 |
| 2.0075 | 2.747280997232976 | |
| 4.005 | 2.762931508104057 | |
| 6.0024999999999995 | 2.7804082427601458 | |
| 8 | 2.7453249815611165 |
Excel formula:
=AGRICULTURE("yield_fertilizer_natural_exponential", {0.01;2.0075;4.005;6.0024999999999995;8}, {3.7582088335464605;2.747280997232976;2.762931508104057;2.7804082427601458;2.7453249815611165})
Expected output:
"non-error"
Python Code
import numpy as np
from scipy.optimize import curve_fit as scipy_curve_fit
import math
def agriculture(xdata, ydata, agriculture_model):
"""
Fits agriculture models to data using scipy.optimize.curve_fit. See https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html for details.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html
This example function is provided as-is without any representation of accuracy.
Args:
xdata (list[list]): The xdata value
ydata (list[list]): The ydata value
agriculture_model (str): The agriculture_model value Valid options: Bleasdale Nelder Yield Density, Bleasdale Nelder Simplified, Farazdaghi Harris Competition, Holliday Yield Density Quadratic, Holliday Modified Rational, Nelder Fertilizer Response, Yield Fertilizer Exponential Decay, Yield Fertilizer Natural Exponential.
Returns:
list[list]: 2D list [param_names, fitted_values, std_errors], or error string.
"""
def _validate_data(xdata, ydata):
"""Validate and convert both xdata and ydata to numpy arrays."""
for name, arg in [("xdata", xdata), ("ydata", ydata)]:
if not isinstance(arg, list) or len(arg) < 2:
raise ValueError(f"{name}: must be a 2D list with at least two rows")
vals = []
for i, row in enumerate(arg):
if not isinstance(row, list) or len(row) == 0:
raise ValueError(f"{name} row {i}: must be a non-empty list")
try:
vals.append(float(row[0]))
except Exception:
raise ValueError(f"{name} row {i}: non-numeric value")
if name == "xdata":
x_arr = np.asarray(vals, dtype=np.float64)
else:
y_arr = np.asarray(vals, dtype=np.float64)
if x_arr.shape[0] != y_arr.shape[0]:
raise ValueError("xdata and ydata must have the same number of rows")
return x_arr, y_arr
# Model definitions dictionary
models = {
'bleasdale_nelder_yield_density': {
'params': ['a', 'b', 'c', 'f'],
'model': lambda x, a, b, c, f: np.power(a + b * np.power(x, f), -1.0 / c),
'guess': lambda xa, ya: (1.0, 1.0, 1.0, 1.0),
},
'bleasdale_nelder_simplified': {
'params': ['a', 'b', 'c'],
'model': lambda x, a, b, c: np.power(a + b * x, -1.0 / c),
'guess': lambda xa, ya: (1.0, 1.0, 1.0),
},
'farazdaghi_harris_competition': {
'params': ['a', 'b', 'c'],
'model': lambda x, a, b, c: np.power(a + b * np.power(x, c), -1.0),
'guess': lambda xa, ya: (1.0, 1.0, 1.0),
},
'holliday_yield_density_quadratic': {
'params': ['a', 'b', 'c'],
'model': lambda x, a, b, c: np.power(a + b * x + c * np.square(x), -1.0),
'guess': lambda xa, ya: (1.0, 1.0, 0.1),
},
'holliday_modified_rational': {
'params': ['a', 'b', 'c'],
'model': lambda x, a, b, c: a / (1.0 + b * x + c * np.square(x)),
'guess': lambda xa, ya: (float(np.max(ya) if np.max(ya) else 1.0), 0.1, 0.01),
},
'nelder_fertilizer_response': {
'params': ['a', 'b0', 'b1', 'b2'],
'model': lambda x, a, b0, b1, b2: (x + a) / (b0 + b1 * (x + a) + b2 * np.square(x + a)),
'guess': lambda xa, ya: (1.0, 1.0, 0.1, 0.01),
'maxfev': 100000,
},
'yield_fertilizer_exponential_decay': {
'params': ['a', 'b', 'r'],
'model': lambda x, a, b, r: a + b * np.power(r, x),
'guess': lambda xa, ya: (float(np.min(ya)), float(np.ptp(ya) if np.ptp(ya) else 1.0), 0.5),
'bounds': ([-np.inf, -np.inf, 0.0], [np.inf, np.inf, 1.0]),
},
'yield_fertilizer_natural_exponential': {
'params': ['a', 'b', 'k'],
'model': lambda x, a, b, k: a + b * np.exp(-k * x),
'guess': lambda xa, ya: (float(np.min(ya)), float(np.ptp(ya) if np.ptp(ya) else 1.0), 0.5),
'bounds': ([-np.inf, -np.inf, 0.0], np.inf),
}
}
# Validate model parameter
if agriculture_model not in models:
return f"Invalid model: {str(agriculture_model)}. Valid models are: {', '.join(models.keys())}"
model_info = models[agriculture_model]
# Validate and convert input data
try:
x_arr, y_arr = _validate_data(xdata, ydata)
except ValueError as e:
return f"Invalid input: {e}"
# Perform curve fitting
try:
p0 = model_info['guess'](x_arr, y_arr)
bounds = model_info.get('bounds', (-np.inf, np.inf))
maxfev = model_info.get('maxfev', 10000)
if bounds == (-np.inf, np.inf):
popt, pcov = scipy_curve_fit(model_info['model'], x_arr, y_arr, p0=p0, maxfev=maxfev)
else:
popt, pcov = scipy_curve_fit(model_info['model'], x_arr, y_arr, p0=p0, bounds=bounds, maxfev=maxfev)
fitted_vals = [float(v) for v in popt]
for v in fitted_vals:
if math.isnan(v) or math.isinf(v):
return "Fitting produced invalid numeric values (NaN or inf)."
except ValueError as e:
return f"Initial guess error: {e}"
except Exception as e:
return f"curve_fit error: {e}"
# Calculate standard errors
std_errors = None
try:
if pcov is not None and np.isfinite(pcov).all():
std_errors = [float(v) for v in np.sqrt(np.diag(pcov))]
except Exception:
pass
return [model_info['params'], fitted_vals, std_errors] if std_errors else [model_info['params'], fitted_vals]