Spaces:
Runtime error
Runtime error
Upload 6 files
Browse files- app.py +30 -0
- predict_yield.py +75 -0
- random_forest_model.joblib +3 -0
- requirements.txt +11 -0
- scaler.joblib +3 -0
- sidama_data_2020_2024_combined.csv +6 -0
app.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
from flask import Flask, request, render_template
|
| 3 |
+
from predict_yield import predict_yield
|
| 4 |
+
import os
|
| 5 |
+
|
| 6 |
+
app = Flask(__name__)
|
| 7 |
+
|
| 8 |
+
@app.route('/', methods=['GET', 'POST'])
|
| 9 |
+
def predict():
|
| 10 |
+
if request.method == 'POST':
|
| 11 |
+
year = int(request.form['year'])
|
| 12 |
+
hectares = float(request.form['hectares'])
|
| 13 |
+
|
| 14 |
+
# Predict yield using the predict_yield function
|
| 15 |
+
result = predict_yield(year, hectares)
|
| 16 |
+
|
| 17 |
+
# Round values for display
|
| 18 |
+
result['predicted_yield_per_ha_kg'] = round(result['predicted_yield_per_ha_kg'], 2)
|
| 19 |
+
result['total_predicted_yield_kg'] = round(result['total_predicted_yield_kg'], 2)
|
| 20 |
+
result['confidence_interval_per_ha_lower'] = round(result['confidence_interval_per_ha_lower'], 2)
|
| 21 |
+
result['confidence_interval_per_ha_upper'] = round(result['confidence_interval_per_ha_upper'], 2)
|
| 22 |
+
result['total_confidence_interval_lower'] = round(result['total_confidence_interval_lower'], 2)
|
| 23 |
+
result['total_confidence_interval_upper'] = round(result['total_confidence_interval_upper'], 2)
|
| 24 |
+
|
| 25 |
+
return render_template('predict.html', result=result)
|
| 26 |
+
|
| 27 |
+
return render_template('predict.html', result=None)
|
| 28 |
+
|
| 29 |
+
if __name__ == '__main__':
|
| 30 |
+
app.run(debug=True, host='0.0.0.0', port=5000)
|
predict_yield.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
import joblib
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
# Load the trained model
|
| 8 |
+
rf_model = joblib.load(os.path.join(os.path.dirname(__file__), 'random_forest_model.joblib'))
|
| 9 |
+
|
| 10 |
+
# Load historical data
|
| 11 |
+
data_path = os.path.join(os.path.dirname(__file__), 'sidama_data_2020_2024_combined.csv')
|
| 12 |
+
df_merged = pd.read_csv(data_path)
|
| 13 |
+
|
| 14 |
+
# Define features
|
| 15 |
+
features = [
|
| 16 |
+
'ndvi_mean_mean_flowering', 'ndvi_mean_mean_fruit', 'ndvi_mean_max_season',
|
| 17 |
+
'soil_moisture_mean_mean_season', 'Rainfall_mean_fruit', 'Humidity_mean_season',
|
| 18 |
+
'elevation_mean'
|
| 19 |
+
]
|
| 20 |
+
|
| 21 |
+
# Get the feature values for the most recent year (2024)
|
| 22 |
+
features_2024 = df_merged[df_merged['year'] == 2024][features].iloc[0].to_dict()
|
| 23 |
+
|
| 24 |
+
def get_features(year):
|
| 25 |
+
# If the year is in the historical data (2020�2024), use the actual features
|
| 26 |
+
if year in df_merged['year'].values:
|
| 27 |
+
feature_values = df_merged[df_merged['year'] == year][features].iloc[0].to_dict()
|
| 28 |
+
else:
|
| 29 |
+
# For future years, use the 2024 feature values
|
| 30 |
+
feature_values = features_2024.copy()
|
| 31 |
+
return feature_values
|
| 32 |
+
|
| 33 |
+
def predict_yield(year, hectares):
|
| 34 |
+
# Get feature values for the year
|
| 35 |
+
feature_values = get_features(year)
|
| 36 |
+
|
| 37 |
+
# Create a DataFrame for the input
|
| 38 |
+
input_data = pd.DataFrame([feature_values.values()], columns=features)
|
| 39 |
+
|
| 40 |
+
# Predict yield per hectare
|
| 41 |
+
yield_per_ha = rf_model.predict(input_data)[0]
|
| 42 |
+
|
| 43 |
+
# Calculate total yield
|
| 44 |
+
total_yield_kg = yield_per_ha * hectares
|
| 45 |
+
|
| 46 |
+
# Compute confidence interval (per hectare)
|
| 47 |
+
lower_bound = yield_per_ha - 1.96 * 173.0
|
| 48 |
+
upper_bound = yield_per_ha + 1.96 * 173.0
|
| 49 |
+
|
| 50 |
+
# Compute total yield confidence interval
|
| 51 |
+
total_lower_bound = lower_bound * hectares
|
| 52 |
+
total_upper_bound = upper_bound * hectares
|
| 53 |
+
|
| 54 |
+
return {
|
| 55 |
+
'year': year,
|
| 56 |
+
'hectares': hectares,
|
| 57 |
+
'predicted_yield_per_ha_kg': yield_per_ha,
|
| 58 |
+
'total_predicted_yield_kg': total_yield_kg,
|
| 59 |
+
'confidence_interval_per_ha_lower': lower_bound,
|
| 60 |
+
'confidence_interval_per_ha_upper': upper_bound,
|
| 61 |
+
'total_confidence_interval_lower': total_lower_bound,
|
| 62 |
+
'total_confidence_interval_upper': total_upper_bound
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
# Make sure function is exposed at module level
|
| 66 |
+
__all__ = ['predict_yield']
|
| 67 |
+
|
| 68 |
+
if __name__ == "__main__":
|
| 69 |
+
year = 2025
|
| 70 |
+
hectares = 2.5
|
| 71 |
+
result = predict_yield(year, hectares)
|
| 72 |
+
print(f"Predicted coffee yield for {result['year']} (per hectare): {result['predicted_yield_per_ha_kg']:.2f} kg/ha")
|
| 73 |
+
print(f"Total predicted yield for {result['hectares']} hectares: {result['total_predicted_yield_kg']:.2f} kg")
|
| 74 |
+
print(f"95% Confidence Interval (per hectare): {result['confidence_interval_per_ha_lower']:.2f} � {result['confidence_interval_per_ha_upper']:.2f} kg/ha")
|
| 75 |
+
print(f"95% Confidence Interval (total): {result['total_confidence_interval_lower']:.2f} � {result['total_confidence_interval_upper']:.2f} kg")
|
random_forest_model.joblib
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1e4408d86ce00696e920667ec1d02f76cbc1231cddb9e7f55eb02b1bf58423c0
|
| 3 |
+
size 47697
|
requirements.txt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
requirements == """
|
| 2 |
+
flask==2.0.1
|
| 3 |
+
pandas==1.3.3
|
| 4 |
+
numpy==1.21.2
|
| 5 |
+
joblib==1.0.1
|
| 6 |
+
scikit-learn==0.24.2
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
with open('C:/Users/abrsh/Desktop/coffee-yield-forecast/requirements.txt', 'w') as f:
|
| 10 |
+
f.write(requirements)
|
| 11 |
+
print("Verified requirements.txt saved to C:/Users/abrsh/Desktop/coffee-yield-forecast/requirements.txt")
|
scaler.joblib
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c66bfb927960a32dea5dead6a9b5711d55642bef312559f65d63086fee7a2c26
|
| 3 |
+
size 1263
|
sidama_data_2020_2024_combined.csv
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
year,ndvi_mean_mean_flowering,ndvi_mean_mean_fruit,ndvi_mean_mean_season,ndvi_mean_max_season,ndvi_mean_cumulative,savi_mean_mean_flowering,savi_mean_mean_fruit,savi_mean_mean_season,savi_mean_max_season,savi_mean_cumulative,soil_moisture_mean_mean_flowering,soil_moisture_mean_mean_fruit,soil_moisture_mean_mean_season,Temperature_mean_flowering,Temperature_mean_fruit,Temperature_mean_season,Rainfall_mean_flowering,Rainfall_mean_fruit,Rainfall_mean_season,Humidity_mean_flowering,Humidity_mean_fruit,Humidity_mean_season,elevation_mean,elevation_std,slope_mean,slope_std,aspect_mean,aspect_std,avg coffee per ha,pred_Lasso,pred_Lasso_lower,pred_Lasso_upper
|
| 2 |
+
2020,0.5114366366666667,0.6084905225,0.5764185,0.65906394,4.611348,0.3294853666666666,0.4171660749999999,0.38616434,0.4431254,3.08931472,0.2488196233333333,0.337285184,0.3085071433333333,18.137647333333334,15.772772400000004,16.58355311111111,142.508442,199.626298,181.74356844444443,66.80198333333333,84.18788359999999,77.82554422222222,1966.221186457876,373.3100156857391,88.15892523354667,12.71320593463941,182.6789522494477,103.90809212906944,1000.0,,,
|
| 3 |
+
2021,0.4077966566666666,0.586967066,0.5346921,0.6540036,4.8122289,0.2571289233333333,0.390451542,0.3506453866666666,0.432164,3.15580848,0.17874539,0.264335624,0.2380096655555555,18.497446666666665,15.9279544,16.813293,76.63168933333334,163.205536,144.05179866666666,53.74330766666666,79.88531679999998,70.68398677777776,1966.221186457876,373.3100156857391,88.15892523354667,12.71320593463941,182.6789522494477,103.90809212906944,2380.2477865353035,,,
|
| 4 |
+
2022,0.4137612266666666,0.3184998283,0.3843878212777778,0.62570757,3.4594903915,0.2604969866666666,0.21193168142,0.2507059252333333,0.41520396,2.2563533271,0.1855147333333333,0.25322498,0.2373916333333333,18.769156,16.012478800000004,16.912175,92.3024472,135.975716,133.87645128888892,52.19039899999999,77.87862799999999,69.64808744444446,1966.221186457876,373.3100156857391,88.15892523354667,12.71320593463941,182.6789522494477,103.90809212906944,4633.619186051816,2300.724849304567,1961.6448493045673,2639.804849304567
|
| 5 |
+
2023,0.44695832,0.6152574900000001,0.55420073125,0.66013736,4.43360585,0.2788233466666667,0.4214298125,0.36771591125,0.45794463,2.94172729,0.2467204666666667,0.316343136,0.2949235533333333,17.811889,16.4684134,16.93645888888889,163.61518766666666,180.9834152,189.2520598888889,60.196447,80.42513799999999,73.79878344444444,1966.221186457876,373.3100156857391,88.15892523354667,12.71320593463941,182.6789522494477,103.90809212906944,4307.926741014413,1858.6794612788965,1519.5994612788966,2197.7594612788967
|
| 6 |
+
2024,0.5331305833333334,0.5964691049999999,0.5336815262500001,0.6489582,4.269452210000001,0.3420106766666667,0.4077839774999999,0.3548163625,0.44712922,2.8385309,0.2125396066666666,0.23417856,0.2331274988888889,19.00443866666667,16.557173799999997,17.314031444444442,150.631798,193.514534,194.1288237777778,63.87316233333333,81.9836072,76.28384477777777,1966.221186457876,373.3100156857391,88.15892523354667,12.71320593463941,182.6789522494477,103.90809212906944,983.3836728699142,711.228050405372,372.148050405372,1050.308050405372
|