Rimsha-Bashir/Crop-Yield-Prediction-App
0
1import pandas as pd
2import numpy as np
3import matplotlib.pyplot as plt
4import pickle
5import seaborn as sns
6import xgboost as xgb
7
8from sklearn.preprocessing import StandardScaler
9from sklearn.model_selection import train_test_split
10from sklearn.feature_extraction import DictVectorizer
11
12from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
13
14
15df = pd.read_csv('../data/yield_final.csv')
16
17
18
19categorical = ['country','crop', 'year']
20
21numerical = ['average_rain_fall_mm_per_year',
22 'pesticide_tonnes',
23 'avg_temp']
24
25eta = 0.1
26max_depth = 7
27min_child_weight = 5
28
29
30## Splitting dataset into train, test and validation
31
32print("Splitting Dataset... \n\n")
33
34df_full_train, df_test = train_test_split(df, test_size=0.2, random_state=1)
35df_train, df_val = train_test_split(df_full_train, test_size=0.25, random_state=1)
36
37df_full_train = df_full_train.reset_index(drop=True)
38df_train=df_train.reset_index(drop=True)
39df_test=df_test.reset_index(drop=True)
40df_val=df_val.reset_index(drop=True)
41
42y_full_train = df_full_train['yield_hg_ha'].values
43y_train = df_train.yield_hg_ha.values
44y_test = df_test.yield_hg_ha.values
45y_val = df_val.yield_hg_ha.values
46
47y_train_log = np.log1p(y_train)
48y_val_log = np.log1p(y_val)
49y_full_train_log = np.log1p(y_full_train)
50
51
52del df_full_train['yield_hg_ha']
53del df_train['yield_hg_ha']
54del df_test['yield_hg_ha']
55del df_val['yield_hg_ha']
56
57
58## Feature Engineering
59
60print("Performing Feature Engineering... \n\n")
61
62# Log-transform highly skewed numerical features
63skewed_features = ['pesticide_tonnes', 'average_rain_fall_mm_per_year']
64for col in skewed_features:
65 df_full_train[col] = np.log1p(df_full_train[col])
66 df_train[col] = np.log1p(df_train[col])
67 df_val[col] = np.log1p(df_val[col])
68 df_test[col] = np.log1p(df_test[col])
69
70
71scaler = StandardScaler()
72df_full_train[numerical] = scaler.fit_transform(df_full_train[numerical])
73df_train[numerical] = scaler.fit_transform(df_train[numerical])
74df_val[numerical] = scaler.transform(df_val[numerical])
75df_test[numerical] = scaler.transform(df_test[numerical])
76
77
78# XGBoost:
79
80
81# Train XGBoost
82
83print("Training XGBoost Model... \n\n")
84
85
86def xgb_train(df_train, df_val, y_train_log, y_val_log, eta,
87 num_boost_round, max_depth, min_child_weight):
88
89 dicts_train = df_train.to_dict(orient='records')
90 dicts_val = df_val.to_dict(orient='records')
91
92 dv = DictVectorizer(sparse=False)
93 X_train = dv.fit_transform(dicts_train)
94 X_val = dv.transform(dicts_val)
95
96 features = dv.get_feature_names_out().tolist()
97
98 dtrain = xgb.DMatrix(X_train, label=y_train_log, feature_names=features)
99 dval = xgb.DMatrix(X_val, label=y_val_log, feature_names=features)
100
101 watchlist = [(dtrain, 'train'), (dval, 'val')]
102
103 xgb_params = {
104 'eta': eta,
105 'max_depth': max_depth,
106 'min_child_weight': min_child_weight,
107 'objective': 'reg:squarederror',
108 'eval_metric':['rmse', 'mae'],
109 'nthreads':8,
110 'seed':1,
111 'verbosity':0
112 }
113
114
115 evals_result = {}
116
117 model = xgb.train(
118 params=xgb_params,
119 dtrain=dtrain,
120 num_boost_round=num_boost_round,
121 evals=watchlist,
122 evals_result=evals_result,
123 verbose_eval=False
124 )
125
126 # Predictions in log scale
127 y_train_pred_log = model.predict(dtrain)
128 y_val_pred_log = model.predict(dval)
129
130 # Convert back to original scale
131 y_train_pred = np.expm1(y_train_pred_log)
132 y_val_pred = np.expm1(y_val_pred_log)
133
134 # Compute metrics in original scale
135 df_metrics = pd.DataFrame({
136 'boost_round': range(num_boost_round),
137 'train_rmse': evals_result['train']['rmse'],
138 'val_rmse': evals_result['val']['rmse'],
139 'train_mae': evals_result['train']['mae'],
140 'val_mae': evals_result['val']['mae']
141 })
142
143
144 return dv, model, df_metrics
145
146
147
148# Predict function
149def xgb_predict(df, dv, model):
150 dicts = df.to_dict(orient='records')
151 X = dv.transform(dicts)
152
153 features = dv.get_feature_names_out().tolist()
154
155 d = xgb.DMatrix(X, feature_names=features)
156
157 y_pred = model.predict(d)
158
159 return y_pred
160
161
162
163def regression_metrics(y_actual, y_pred):
164 mse = mean_squared_error(y_actual, y_pred) # compare with y_val in original units
165 rmse = np.sqrt(mse)
166 mae = mean_absolute_error(y_actual, y_pred)
167 r2 = r2_score(y_actual, y_pred)
168
169 return rmse, mae, r2
170
171print("Evaluation Metrtics on Validation Dataset... \n\n")
172
173dv, model, df_metrics = xgb_train(
174 df_train, df_val, y_train_log, y_val_log,
175 eta=eta, num_boost_round=200, max_depth=max_depth, min_child_weight=min_child_weight
176 )
177
178
179y_pred_val_log = xgb_predict(df_val, dv, model)
180y_pred_val = np.expm1(y_pred_val_log)
181
182
183rmse, mae, r2_val = regression_metrics(y_val, y_pred_val)
184
185print(f"Validation RMSE:{rmse}")
186print(f"Validation MAE:{mae}")
187print(f"Validation R2:{r2_val}")
188
189
190
191def xgb_train_full(df_train, y_train_log, eta,
192 num_boost_round, max_depth, min_child_weight):
193
194 dicts_train = df_train.to_dict(orient='records')
195 dv = DictVectorizer(sparse=False)
196 X_train = dv.fit_transform(dicts_train)
197
198 features = dv.get_feature_names_out().tolist()
199
200 dtrain = xgb.DMatrix(X_train, label=y_train_log, feature_names=features)
201
202 xgb_params = {
203 'eta': eta,
204 'max_depth': max_depth,
205 'min_child_weight': min_child_weight,
206 'objective': 'reg:squarederror',
207 'eval_metric': ['rmse', 'mae'],
208 'nthreads': 8,
209 'seed': 1,
210 'verbosity': 0
211 }
212
213 evals_result = {}
214 watchlist = [(dtrain, 'train')]
215
216 model = xgb.train(
217 params=xgb_params,
218 dtrain=dtrain,
219 num_boost_round=num_boost_round,
220 evals=watchlist,
221 evals_result=evals_result,
222 verbose_eval=False
223 )
224
225 # Gather metrics
226 df_metrics = pd.DataFrame({
227 'boost_round': range(num_boost_round),
228 'train_rmse': evals_result['train']['rmse'],
229 'train_mae': evals_result['train']['mae']
230 })
231
232 return dv, model, df_metrics
233
234print("Training the full train dataframe... \n\n")
235
236dv, model, df_metrics = xgb_train_full(
237 df_full_train, y_full_train_log, eta=eta, num_boost_round=200,
238 max_depth=max_depth, min_child_weight=min_child_weight
239 )
240
241# Predict on test set
242y_pred_test_log = xgb_predict(df_test, dv, model)
243y_pred_test = np.expm1(y_pred_test_log) # convert back to original units
244
245print("Evaluation Metrics on Test... \n\n")
246
247# Evaluate metrics on test
248rmse, mae, r2 = regression_metrics(y_test, y_pred_test)
249
250print(f"Test RMSE:{rmse}")
251print(f"Test MAE:{mae}")
252print(f"Test R2:{r2}")
253
254print("Saving the final model in local folder... \n\n")
255
256output_file='../model/xgboost_eta=%s_depth=%s_minchild=%s_round=200.bin'%(eta, max_depth, min_child_weight)
257with open(output_file, 'wb') as f_out:
258 pickle.dump((model,dv), f_out)
259
260
261
262
263
264
265
266 