Skip to content

Sowing Success: How Machine Learning Helps Farmers Select the Best Crops

Measuring essential soil metrics such as nitrogen, phosphorous, potassium levels, and pH value is an important aspect of assessing soil condition. However, it can be an expensive and time-consuming process, which can cause farmers to prioritize which metrics to measure based on their budget constraints.

Farmers have various options when it comes to deciding which crop to plant each season. Their primary objective is to maximize the yield of their crops, taking into account different factors. One crucial factor that affects crop growth is the condition of the soil in the field, which can be assessed by measuring basic elements such as nitrogen and potassium levels. Each crop has an ideal soil condition that ensures optimal growth and maximum yield.

A farmer reached out to you as a machine learning expert for assistance in selecting the best crop for his field. They've provided you with a dataset called soil_measures.csv, which contains:

  • "N": Nitrogen content ratio in the soil
  • "P": Phosphorous content ratio in the soil
  • "K": Potassium content ratio in the soil
  • "pH" value of the soil
  • "crop": categorical values that contain various crops (target variable).

Each row in this dataset represents various measures of the soil in a particular field. Based on these measurements, the crop specified in the "crop" column is the optimal choice for that field.

In this project, you will build multi-class classification models to predict the type of "crop" and identify the single most importance feature for predictive performance.

# All required libraries are imported here for you.
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn import metrics

# Load the dataset
crops = pd.read_csv("soil_measures.csv")

# Write your code here

MY Observation

crops.head(50)
crops.sample(50)
crops.info()

so there is no missing values

so now we try to visualize the soil data to undestand the distribution of soil data

import matplotlib.pyplot as plt
import seaborn as sns
# 1. Distribution plots
fig, axs = plt.subplots(3, 2, figsize=(20, 25))
fig.suptitle('Soil Measurements and Crop Distribution', fontsize=16)

# Distribution of Crops
sns.countplot(x='crop', data=crops, ax=axs[0, 0])
axs[0, 0].set_title('Distribution of Crops')
axs[0, 0].set_xlabel('Crop Type')
axs[0, 0].set_ylabel('Count')
axs[0, 0].tick_params(axis='x', rotation=45)

# Distribution of Soil Measurements
for i, column in enumerate(['N', 'P', 'K', 'ph']):
    row, col = divmod(i+1, 2)
    sns.histplot(crops[column], kde=True, ax=axs[row, col])
    axs[row, col].set_title(f'Distribution of {column}')
    axs[row, col].set_xlabel(column)
    axs[row, col].set_ylabel('Count')

fig.delaxes(axs[2, 1])  # Remove the empty subplot
plt.tight_layout()
plt.subplots_adjust(top=0.95)
plt.show()

# 2. Box plots for soil measurements by crop
fig2, ax2 = plt.subplots(figsize=(20, 10))
sns.boxplot(x='crop', y='value', hue='variable', 
            data=pd.melt(crops, id_vars=['crop'], value_vars=['N', 'P', 'K', 'ph']), 
            ax=ax2)
ax2.set_title('Soil Measurements by Crop Type')
ax2.set_xlabel('Crop')
ax2.set_ylabel('Value')
plt.xticks(rotation=45)
plt.legend(title='Measurement', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()

# 3. Correlation Heatmap
plt.figure(figsize=(10, 8))
soil_measurements = crops[['N', 'P', 'K', 'ph']]
correlation_matrix = soil_measurements.corr()
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', vmin=-1, vmax=1, center=0)
plt.title('Correlation Heatmap of Soil Measurements')
plt.tight_layout()
plt.show()

# 4. Pairplot
sns.pairplot(crops, vars=['N', 'P', 'K', 'ph'], hue='crop', height=3)
plt.suptitle('Pairplot of Soil Measurements by Crop Type', y=1.02)
plt.tight_layout()
plt.show()

# 5. Radar chart for average soil measurements by crop
from math import pi
import matplotlib.pyplot as plt

# Calculate average soil measurements for each crop
avg_measurements = crops.groupby('crop')[['N', 'P', 'K', 'ph']].mean()

# Number of variables
categories = list(avg_measurements.columns)
N = len(categories)

# Create a figure and polar axes
fig, ax = plt.subplots(figsize=(10, 10), subplot_kw=dict(projection='polar'))

# Plot for each crop
for i, crop in enumerate(avg_measurements.index):
    values = avg_measurements.loc[crop].values.flatten().tolist()
    values += values[:1]  # Repeat the first value to close the polygon
    
    # Calculate angle for each category
    angles = [n / float(N) * 2 * pi for n in range(N)]
    angles += angles[:1]  # Repeat the first angle to close the polygon
    
    # Plot the polygon and add crop name
    ax.plot(angles, values, linewidth=1, linestyle='solid', label=crop)
    ax.fill(angles, values, alpha=0.1)

# Set the angle labels
plt.xticks(angles[:-1], categories)

# Add legend
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))

plt.title("Average Soil Measurements by Crop")
plt.tight_layout()
plt.show()

so we can't select a single feature after visualizing all the feature. so we have to try for another method.

# check for crop types

crops['crop'].unique()

Split the data

# Features and target variables

X = crops.drop(columns = 'crop')
y = crops['crop']

Evaluate feature performance