Skip to content
Project: Predictive Modeling for Agriculture
  • AI Chat
  • Code
  • Report
  • 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 apply machine learning to build a multi-class classification model to predict the type of "crop", while using techniques to avoid multicollinearity, which is a concept where two or more features are highly correlated.

    # All required libraries are imported here for you.
    import matplotlib.pyplot as plt
    import pandas as pd
    from sklearn.linear_model import LogisticRegression
    from sklearn.model_selection import train_test_split
    import seaborn as sns
    from sklearn.metrics import f1_score
    
    # Load the dataset
    crops = pd.read_csv("soil_measures.csv")
    
    # Write your code here
    
    # Some Compulsory Exploratory Data Analysis.
    
    # Print the Head of the Dataset
    print(crops.head())
    
    # Print the Tail of the Dataset
    print(crops.tail())
    
    # Get the Columns of the Data Frame
    
    column_names = list(crops.columns)
    
    print(column_names)
    
    
    # Get the Info sanpshot of the Data Frame
    
    print(crops.info())
    
    # iterate over the column names and find the number of unique values each column has.
    
    for col in column_names:
        print("The \'{}\' column has {} unique values.".format(col, crops[col].nunique()))
    
    # Read in soil_measures.csv as a pandas DataFrame and perform some data checks, 
    # such as determining the number of crops, checking for missing values, 
    # and verifying that the data in each potential feature column is numeric.
    number_of_corps = crops['crop'].nunique()
    print("Number Of Crops = ", number_of_corps)
    
    # List Out the Crop Names
    print("Crop Names:\n", crops['crop'].unique())
    
    # Selecting the Data Types of the features / columns
    
    print(crops.dtypes)
    
    # Selecting Only Numeric Data Types of the features / columns
    
    numeric_data_fields = crops.select_dtypes(include="number")
    print(numeric_data_fields)
    
    # We See that the four potential feature coulmns are numeric.
    # So we are good to go with a Logistic Regression with F1 Score greater than 0.50 or 50%
    
    # Extactring the Features
    
    crops_X = crops.drop(columns="crop")
    crops_y = crops["crop"]
    
    # Split the data into training and test sets, 
    # setting test_size equal to 20% 
    # and using a random_state of 42.
    
    # Creating the Train Test Split. We train the Model on 80% of the Data.
    X_train, X_test, y_train, y_test = train_test_split(crops_X, crops_y, test_size=0.2, random_state=42)
    
    
    # Creating an instance of the LogisticRegression Model Object.
    logreg = LogisticRegression(max_iter=2000, multi_class="multinomial", random_state=42)
    
    
    # Fit the model that is train the Model.
    logreg.fit(X_train, y_train)
    
    # Now after training the model is complete ask it to predict.
    y_pred = logreg.predict(X_test)
    
    # Get the F1_Score
    
    f1score = f1_score(y_test, y_pred, average="micro")
    
    print(f1score)
    
    print(column_names)
    
    if "crop" in column_names:
        column_names.remove('crop')
    
    for col in column_names:
        print("Taking \'{}\' as the feature.".format(col))
        crops_X = pd.DataFrame(crops[col])
        crops_y = crops["crop"]
        
        # Creating the Train Test Split. We train the Model on 80% of the Data.
        X_train, X_test, y_train, y_test = train_test_split(crops_X, crops_y, test_size=0.2, random_state=42)
        
        # Creating an instance of the LogisticRegression Model Object.
        logreg = LogisticRegression(max_iter=2000, random_state=42)
    
    
        # Fit the model that is train the Model.
        logreg.fit(X_train, y_train)
    
        # Now after training the model is complete ask it to predict.
        y_pred = logreg.predict(X_test)
    
        # Get the F1_Score
    
        f1score = f1_score(y_test, y_pred, average="weighted")
        
        print("F1 Score = ", f1score)
    # In order to avoid selecting two features that are highly correlated, 
    # perform a correlation analysis for each pair of features, enabling 
    # you to build a final model without the presence of multicollinearity.
    
    sns.heatmap(crops.corr(), annot=True)
    plt.show()      # K - Potassium and P - Phosphorus have high collinearity between themselves.
    
    # Thus we must avoid using both at the sametime. Use only one of K or P in the final model Training.
    # Reorganizing with ['N', 'K', 'ph']
    
    final_features = ['N', 'K', 'ph']
    
    crops_X = crops.drop(columns=["P", "crop"])
    
    crops_y = crops["crop"]
    
    # Creating the Train Test Split. We train the Model on 80% of the Data.
    
    X_train, X_test, y_train, y_test = train_test_split(crops_X, crops_y, test_size=0.2, random_state=123)
        
    # Creating an instance of the LogisticRegression Model Object.
    log_reg = LogisticRegression(max_iter=2000, multi_class="multinomial", random_state=42)
    
    
    # Fit the model that is train the Model.
    logreg.fit(X_train, y_train)
    
    # Now after training the model is complete ask it to predict.
    y_pred = logreg.predict(X_test)
    
    # Get the F1_Score
    
    f1score = f1_score(y_test, y_pred, average="weighted")
        
    print("F1 Score = ", f1score)
    
    model_performance = f1score