Skip to content
Fresh from the field — visit Elibeth Farms, the farm EliBeth Green Haven Ltd in Ghana. Visit elibethfarms.com
Prince.Quansah

Regression · Decision Support

Crop Recommendation

Which staple crop will perform best under your climate and inputs?

GitHub
0.98
R² score
101
Countries
10
Staple crops
28k+
Training records

Overview

Choosing what to plant is the single most consequential decision on a farm, yet it is still often made on habit rather than evidence. This tool compares the expected yield (hg/ha) of ten staple crops — maize, cassava, rice, potatoes, sorghum, soybeans, sweet potatoes, wheat, yams and plantains — for a given country, year and set of climate and input conditions.

The model learns from 23 years (1990–2013) of country-level production records combined with average annual rainfall, average temperature and pesticide usage. A farm manager, extension officer or investor can enter local conditions and immediately see which crop the data favours.

The problem

Smallholder and commercial farmers lack a simple, data-driven way to compare how different staple crops are likely to perform under their specific rainfall, temperature and input conditions.

Objectives

1

Quantify how rainfall, temperature and pesticide use drive yield across ten staple crops

2

Benchmark linear and non-linear regression models on a large multi-country dataset

3

Deploy the best model as a free, browser-based decision-support tool

Methodology

  1. 01

    Cleaned and merged FAO yield, rainfall, temperature and pesticide records (28,242 rows, 101 countries)

  2. 02

    Exploratory analysis of yield distributions by crop and country

  3. 03

    Standard-scaled numeric features and one-hot encoded country and crop

  4. 04

    Compared Linear, Lasso, Ridge, K-Nearest Neighbors, Decision Tree and Random Forest regressors

  5. 05

    Selected Random Forest (R² ≈ 0.98) for stability and deployed it with Streamlit

Dataset

FAO / World Bank crop yield dataset — 28,242 records covering 101 countries and 10 staple crops (1990–2013), with yield (hg/ha), average annual rainfall (mm), pesticide use (tonnes) and average temperature (°C).

https://crop-recommendation-elibethfarms.streamlit.app/

Loading the live app…

Free-tier apps sleep when idle. If it takes more than a few seconds, click “Wake up” inside the app or open it in a new tab.

Interactive app hosted on Streamlit Community Cloud. Your inputs are not stored by this website.

GentleKing112233/crop-recommendation

Public repository · branch

Explorer

import pandas as pd
import numpy as np
import streamlit as st
import joblib
import os
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestRegressor

st.set_page_config(
    page_title="Crop Yield Prediction",
    page_icon="\U0001F331",
    layout="wide"
)

st.markdown("""
<style>
.title {
    text-align: center;
    font-size: 34px;
    font-weight: bold;
    color: #111111;
    margin-bottom: 15px;
}
.input-panel {
    background-color: #858585;
    padding: 20px;
    border-radius: 5px;
}
.stButton > button {
    background-color: #ed4141;
    color: white;
    width: 100%;
    height: 45px;
    border: none;
    border-radius: 7px;
    font-size: 17px;
}
.stButton > button:hover {
    background-color: #d93232;
    color: white;
}
</style>
""", unsafe_allow_html=True)

CSV_FILE = "yield_df.csv"
MODEL_FILE = "rfr.pkl"
PREPROCESSOR_FILE = "preprocessor.pkl"

COLUMNS = [
    'Year', 'average_rain_fall_mm_per_year', 'pesticides_tonnes',
    'avg_temp', 'Area', 'Item', 'hg/ha_yield'
]


@st.cache_resource
def load_artifacts():
    if os.path.exists(MODEL_FILE) and os.path.exists(PREPROCESSOR_FILE):
        model = joblib.load(MODEL_FILE)
        preprocessor = joblib.load(PREPROCESSOR_FILE)
        return model, preprocessor, True
    return None, None, False


@st.cache_data
def load_data(path):
    return pd.read_csv(path)


@st.cache_resource
def train_model(df):
    data = df[COLUMNS].copy()
    X = data.drop(['hg/ha_yield'], axis=1)
    y = data['hg/ha_yield']
    X_train, _, y_train, _ = train_test_split(
        X, y, test_size=0.2, random_state=0, shuffle=True
    )
    ohe = OneHotEncoder(drop='first')
    scaler = StandardScaler()
    preprocessor = ColumnTransformer(
        transformers=[
            ('standardscale', scaler, [0, 1, 2, 3]),
            ('oneHotencode', ohe, [4, 5]),
        ],
        remainder='passthrough'
    )
    X_train_dummy = preprocessor.fit_transform(X_train)
    model = RandomForestRegressor(n_estimators=100, random_state=42)
    model.fit(X_train_dummy, y_train)
    joblib.dump(model, MODEL_FILE)
    joblib.dump(preprocessor, PREPROCESSOR_FILE)
    return model, preprocessor


df = load_data(CSV_FILE)
areas = sorted(df["Area"].dropna().unique().tolist())
crops = sorted(df["Item"].dropna().unique().tolist())

model, preprocessor, loaded = load_artifacts()
if not loaded:
    model, preprocessor = train_model(df)
    loaded = True
    st.info("Model trained from the dataset and saved for future runs.")

st.markdown(
    '<div class="title">Crop Yield Prediction Per Country</div>',
    unsafe_allow_html=True
)
st.markdown('<div class="input-panel">', unsafe_allow_html=True)
st.markdown(
    "<h3 style='text-align:center;color:white;'>Input All Features Here</h3>",
    unsafe_allow_html=True
)

with st.form("crop_prediction_form"):
    col1, col2 = st.columns(2)
    with col1:
        year = st.number_input("Year", min_value=1900, max_value=2100, value=2013, step=1)
        pesticides = st.number_input("Pesticides (tonnes)", min_value=0.0, value=0.0, step=1.0)
        area = st.selectbox("Area", areas)
    with col2:
        rainfall = st.number_input("Average Rainfall (mm/year)", min_value=0.0, value=1000.0, step=10.0)
        temperature = st.number_input("Average Temperature (\u00b0C)", value=25.0, step=0.5)
        item = st.selectbox("Item", crops)
    submitted = st.form_submit_button("Predict", use_container_width=True)

if submitted:
    input_data = pd.DataFrame([{
        "Year": year,
        "average_rain_fall_mm_per_year": rainfall,
        "pesticides_tonnes": pesticides,
        "avg_temp": temperature,
        "Area": area,
        "Item": item
    }])
    try:
        transformed_data = preprocessor.transform(input_data)
        prediction_hg_ha = model.predict(transformed_data)[0]
        prediction_tonnes_ha = prediction_hg_ha / 10000
        st.success("Prediction completed successfully!")
        st.metric(
            label="Predicted Crop Yield",
            value=f"{prediction_tonnes_ha:.2f} tonnes per hectare"
        )
    except Exception as e:
        st.error(f"Prediction failed: {e}")

st.markdown("</div>", unsafe_allow_html=True)

Showing a saved copy of the main file — browse the full repository on GitHub.

Chat on WhatsApp Send an email Code on GitHub Elibeth Farms