🌐 Ch 14, Pattern recognition and machine learning, Christopher M. Bishop (2006).

🌐 Ch 9, The element of statistical learning by T. Hastie, R. Tibshirani & J. Friedman (2008).

By the end of this section, you should be able to:

average loss function.
Regression Function

# Pseudo Code for Fine Tuning k:
# ------------------------------
Inputs: Training data, Maximum neighbors M, Number of folds K
Initialize performance list = []
For k = 2 to M:
temp_score = 0
For fold = 1 to K:
Partition data into training_fold and validation_fold
model <- KNN(neighbors = k)
model.fit(training_fold)
score = model.score(validation_fold)
temp_score = temp_score + score
End For
Append (temp_score / K) to performance
End ForWhat to Watch Out Before Training KNN


Parameters vs Hyperparameters

import numpy as np
import pandas as pd
data = pd.read_csv(path_heart)
quan_vars = ['age','trestbps','chol','thalach','oldpeak']
qual_vars = ['sex','cp','fbs','restecg','exang','slope','ca','thal','target']
# Convert to correct types
for i in quan_vars:
data[i] = data[i].astype('float')
for i in qual_vars:
data[i] = data[i].astype('category')
# Train test split
from sklearn.model_selection import train_test_split
X, y = data.iloc[:,:-1], data.iloc[:,-1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
from sklearn.preprocessing import MinMaxScaler, StandardScaler
scaler = MinMaxScaler()
# OnehotEncoding and Scaling
X_train_cat = pd.get_dummies(X_train.select_dtypes(include="category"), drop_first=True)
X_train_encoded = scaler.fit_transform(np.column_stack([X_train.select_dtypes(include="number").to_numpy(), X_train_cat]))
X_test_cat = pd.get_dummies(X_test.select_dtypes(include="category"), drop_first=True)
X_test_encoded = scaler.transform(np.column_stack([X_test.select_dtypes(include="number").to_numpy(), X_test_cat]))
# KNN
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=5)
knn = knn.fit(X_train_encoded, y_train)
y_pred = knn.predict(X_test_encoded)
from sklearn.metrics import roc_auc_score, accuracy_score, precision_score, recall_score, f1_score, confusion_matrix, ConfusionMatrixDisplay
test_perf = pd.DataFrame(
data={'Accuracy': accuracy_score(y_test, y_pred),
'Precision': precision_score(y_test, y_pred),
'Recall': recall_score(y_test, y_pred),
'F1-score': f1_score(y_test, y_pred)},
columns=["Accuracy", "Precision", "Recall", "F1-score"],
index=["5NN"])
test_perf| Accuracy | Precision | Recall | F1-score | |
|---|---|---|---|---|
| 5NN | 0.868293 | 0.861111 | 0.885714 | 0.873239 |
python.GridSearchCV from sklearn.model_selection module.knn = KNeighborsClassifier()
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import f1_score, make_scorer
scorer = make_scorer(f1_score, pos_label=1)
param_grid = {'n_neighbors': list(range(1,21))}
knn = KNeighborsClassifier()
grid_search = GridSearchCV(
knn, param_grid, cv=10,
scoring=scorer,
n_jobs=-1,
return_train_score=True)
grid_search.fit(X_train_encoded, y_train)
knn = KNeighborsClassifier(n_neighbors=grid_search.best_params_['n_neighbors'])
knn = knn.fit(X_train_encoded, y_train)
y_pred = knn.predict(X_test_encoded)
test_perf = pd.concat([test_perf, pd.DataFrame(
data={'Accuracy': accuracy_score(y_test, y_pred),
'Precision': precision_score(y_test, y_pred),
'Recall': recall_score(y_test, y_pred),
'F1-score': f1_score(y_test, y_pred)},
columns=["Accuracy", "Precision", "Recall", "F1-score"],
index=[f"{grid_search.best_params_['n_neighbors']}NN"])], axis=0)
test_perf| Accuracy | Precision | Recall | F1-score | |
|---|---|---|---|---|
| 5NN | 0.868293 | 0.861111 | 0.885714 | 0.873239 |
| 1NN | 1.000000 | 1.000000 | 1.000000 | 1.000000 |

| Accuracy | Precision | Recall | F1-score | |
|---|---|---|---|---|
| 5NN | 0.868293 | 0.861111 | 0.885714 | 0.873239 |
| 1NN | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
| 16NN_No_Dup | 0.885246 | 0.882353 | 0.909091 | 0.895522 |
N = 10
Ds = np.zeros(shape=(N*(N-1)//2, 8))
j = 0
for d in [1,10,100, 500, 1000, 5000, 10000, 50000]:
Xd = np.random.uniform(-5,5,size=(N,d))
i = 0
for s in range(1, N):
for k in range(s):
Ds[i,j] = np.linalg.norm(Xd[s,:] - Xd[k,:])
i += 1
j += 1
import plotly.express as px
df_dist = pd.DataFrame({'Ratio': np.round(Ds.max(axis=0)/Ds.min(axis=0), 2), 'Dim': ['1','10','100', '500', '1000', '5000', '10000', '50000']})
fig4 = px.line(df_dist, x='Dim', y="Ratio", text="Ratio")
fig4.update_layout(
width=300, height=480,
title="Max-min distance ratio at various dimension")
fig4.update_xaxes(title='Dimension')
fig4.update_yaxes(title='Max-Min Distance Ratio')
fig4.update_traces(textposition="top right")
fig4.show()Neighbors based on a distance between two points.Is there other way to define Neighbor?

| x1 | x2 | y |
|---|---|---|
| -0.752759 | 2.704286 | 1 |
| 1.935603 | -0.838856 | 0 |
| -0.546282 | -1.960234 | 0 |
| 0.952162 | -2.022393 | 0 |
| -0.955179 | 2.584544 | 1 |
| -2.458261 | 2.011815 | 1 |
| 2.449595 | -1.562629 | 0 |
| 1.065386 | -2.900473 | 0 |
| -0.793301 | 0.793835 | 1 |
| 2.015881 | 1.175845 | 0 |
| -0.016509 | -1.194730 | 0 |

Hyperparameters:
max_depthmax_featuresmin_samples_splitmin_samples_leafcriterion… [see explanation here]
GridsearchCV with \(K=10\) to search over the hyperparameters:
criterion)min_samples_leaf)max_features).data = pd.read_csv(path_heart)
quan_vars = ['age','trestbps','chol','thalach','oldpeak']
qual_vars = ['sex','cp','fbs','restecg','exang','slope','ca','thal','target']
# Convert to correct types
for i in quan_vars:
data[i] = data[i].astype('float')
for i in qual_vars:
data[i] = data[i].astype('category')
# Train test split
from sklearn.model_selection import train_test_split
data_no_dup = data.drop_duplicates()
X, y = data_no_dup.iloc[:,:-1], data_no_dup.iloc[:,-1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.metrics import roc_auc_score, accuracy_score, precision_score, recall_score, f1_score, confusion_matrix, ConfusionMatrixDisplay
clf = DecisionTreeClassifier()
param_grid = {'criterion': ['gini', 'entropy'],
'min_samples_leaf': [2, 5, 10, 16, 20, 25, 30],
'max_features': ['auto', 'sqrt', 'log2', 2, 5, 10, X_train.shape[1]] }
grid_search = GridSearchCV(
estimator=clf, param_grid=param_grid,
cv=10, scoring='accuracy', n_jobs=-1)
grid_search.fit(X_train, y_train)
best_model = grid_search.best_estimator_
y_pred = best_model.predict(X_test)
test_tr = pd.DataFrame(
data={'Accuracy': accuracy_score(y_test, y_pred),
'Precision': precision_score(y_test, y_pred),
'Recall': recall_score(y_test, y_pred),
'F1-score': f1_score(y_test, y_pred)},
columns=["Accuracy", "Precision", "Recall", "F1-score"],
index=["Tree"])
test_tr = pd.concat([test_tr, pd.DataFrame(
data={'Accuracy': 0.885246,
'Precision': 0.882353,
'Recall': 0.909091,
'F1-score': 0.909091},
columns=["Accuracy", "Precision", "Recall", "F1-score"],
index=["16-NN"])], axis=0)
print(f"Best hyperparameters: {grid_search.best_params_}")
test_trBest hyperparameters: {'criterion': 'gini', 'max_features': 13, 'min_samples_leaf': 5}
| Accuracy | Precision | Recall | F1-score | |
|---|---|---|---|---|
| Tree | 0.819672 | 0.823529 | 0.848485 | 0.835821 |
| 16-NN | 0.885246 | 0.882353 | 0.909091 | 0.909091 |
🥳 Yeahhhh 🥂!!!
Let’s take a break!
