Require Python 3.7 Scikit-learn version ...
import numpy as np
import matplotlib.pyplot as plt
from urllib.request import urlopen
from sklearn.model_selection import train_test_split
from sklearn import neighbors, tree
url="https://perso.univ-rennes1.fr/valerie.monbet/doc/cours/Biscuits.csv"
biscuits=np.loadtxt(urlopen(url),skiprows=1,delimiter=";")
Let us look at the spectra.
# Extraction de la colonne fat
fat=biscuits[:,0]
# Extraction des variables explicatives
X=biscuits[:,1:]
# Trace d'un spectre
plt.figure(1)
plt.plot(X[1,:])
plt.title("Un exemple de spectre")
# TIn the following plot, color is varying according to the fat percent
fat=fat/max(fat)
colors= plt.cm.inferno(fat)
plt.figure(2)
for i in range(len(fat)):
plt.plot(X[i,:],color=colors[i])
plt.title("Spectres NIR")
plt.ylabel("Absorbances")
plt.show()
For each value of the nearest neighbor numbers, Monte Carlo cross validation is run with aout 25% of the samples in the validation set. At each iteration de Mean Square Error is stored.
First block with uniform weights.
from sklearn import neighbors
nb_neighbors = [1,5,10,20]
B = 100 # number of samples for the cross validation
mse_knn= np.zeros((B,len(nb_neighbors)))
for b in range(0,B):
X_train, X_test, y_train, y_test = train_test_split(X,fat,test_size=9)
mk=np.mean(X_train,axis=0)
sk=np.maximum(np.std(X_train,axis=0),10*np.finfo(float).eps)
X_train, X_test = np.add(X_train,-mk), np.add(X_test,-mk)
X_train, X_test = np.multiply(X_train,1/sk),np.multiply(X_test,1/sk)
for i,k in enumerate(nb_neighbors):
knn = neighbors.KNeighborsRegressor(k, weights='uniform')
knn.fit(X_train,y_train)
y_pred = knn.predict(X_test)
mse_knn[b,i] = np.mean((y_pred-y_test)**2)
plt.boxplot(np.sqrt(mse_knn),labels=nb_neighbors)
plt.ylabel('Root mean square error')
plt.xlabel('Nb of neighbors')
print("Best RMSE of knn method: ",np.round(np.sqrt(np.min(np.mean(mse_knn,axis=0))),2))
First block with inverse (euclidean) distance weights
mse_knn= np.zeros((B,len(nb_neighbors)))
for b in range(0,B):
X_train, X_test, y_train, y_test = train_test_split(X,fat,test_size=9)
mk=np.mean(X_train,axis=0)
sk=np.maximum(np.std(X_train,axis=0),10*np.finfo(float).eps)
X_train, X_test = np.add(X_train,-mk), np.add(X_test,-mk)
X_train, X_test = np.multiply(X_train,1/sk),np.multiply(X_test,1/sk)
for i,k in enumerate(nb_neighbors):
knn = neighbors.KNeighborsRegressor(k, weights='distance')
knn.fit(X_train,y_train)
y_pred = knn.predict(X_test)
mse_knn[b,i] = np.mean((y_pred-y_test)**2)
plt.boxplot(np.sqrt(mse_knn),labels=nb_neighbors)
plt.ylabel('Root mean square error')
plt.xlabel('Nb of neighbors')
print("Best RMSE of knn method: ",np.round(np.sqrt(np.min(np.mean(mse_knn,axis=0))),2))
In the examples above, the cross validation procedure is detailled. But, scikit-learn provide some tools to perform it.
Shuffle split generate the B training and validation sets.
from sklearn.model_selection import GridSearchCV, cross_val_score
from sklearn.model_selection import ShuffleSplit
# Generation of the B training/validation sets
cv = ShuffleSplit(n_splits=B,
test_size=0.25,
random_state=0)
# Initialization of the regressor
knn = neighbors.KNeighborsRegressor()
param_grid = [{'n_neighbors': [1,5,10,20],
'weights': ['uniform','distance'],
'metric': ['euclidean','minkowski']}]
# Optimization of the hyperparameters
search = GridSearchCV(knn,
param_grid,
scoring="neg_mean_squared_error",
cv=cv,
n_jobs=-1)
search.fit(X,fat)
print("Mean test score (MSE) = ",np.round(-search.cv_results_["mean_test_score"],3))
print("Std test score = ",np.round(search.cv_results_["std_test_score"],3))
#print(search.best_estimator_)
print("Best set of parameters : ",search.best_params_)
print("Best RMSE : ",np.round(np.sqrt(-search.best_score_),3))
The performances of the nearest neighbor methods could be improved if the model were fit on a subset of selected variables.
p = X.shape[1]
rho = np.zeros(p)
for j in range(p):
rho[j] = np.corrcoef(X[:,j],fat)[0,1]
rho10 = np.sort(rho)[p-10]
keep = np.where(rho>=rho10)[0]
search.fit(X[:,keep],fat)
#print(search.best_estimator_)
print("Best set of parameters : ",search.best_params_)
print("Best RMSE : ",np.round(np.sqrt(-search.best_score_),3))
# Initialization of the regressor
tree = tree.DecisionTreeRegressor()
param_grid = [{'max_features': [10,50,100]}]
# Optimization of the hyperparameters
search = GridSearchCV(tree,
param_grid,
scoring="neg_root_mean_squared_error",
cv=cv,
n_jobs=-1)
search.fit(X,fat)
#print(search.best_estimator_)
print("Best set of parameters : ",search.best_params_)
print("Best RMSE : ",-np.round(search.best_score_,3))
res_cv = cross_val_score(tree, X, fat, scoring = "neg_root_mean_squared_error", cv=cv)
print(res_cv)
print("Mean RMSE for tree model = ",round(-np.mean(res_cv),3))
print("Std RMSE for tree model = ",round(np.std(res_cv),3))