<jupyter_start><jupyter_text>--- K-Nearest Neighbours---Aim: produce a kNN model to identify gamma signals and separate them from the background hadron measurements. Data: Telescope datasetSource: https://www.kaggle.com/brsdincer/telescope-spectrum-gamma-or-hadron --- Data Dictionary---DATA FOR PREDICTION GAMMA OR HADRON- fLength -- major axis of ellipse (mm)- fWidth -- minor axis of ellipse (mm)- fSize -- 10-log of sum of content of all pixels (in phot)- fConc -- ratio of sum of two highest pixels over fSize (ratio)- fConc1 -- ratio of highest pixel over fSize (ratio)- fAsym -- distance from highest pixel to center, projected onto major axis (mm)- fM3Long -- 3rd root of third moment along major axis (mm)- fM3Trans -- 3rd root of third moment along minor axis (mm)- fAlpha -- angle of major axis with vector to origin (deg)- fDist -- distance from origin to center of ellipse (mm)- class -- gamma (signal), hadron (background)<jupyter_code>import numpy as np, pandas as pd, matplotlib.pyplot as plt, seaborn as sns
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
from sklearn.utils import resample
sns.set()<jupyter_output><empty_output><jupyter_text>--- Import & Inspect Data---<jupyter_code>data = pd.read_csv(r'telescope.csv')
data.info()
# Assign: Gamma = 1, Hadron = 0
target_assignments = {}
for i in enumerate(data['class']):
    if i[1] == 'g':
        j = 1
    elif i[1] == 'h':
        j = 0
    target_assignments.update({i[0]: j})
data['target'] = data.index.map(target_assignments)

# Check Balance of Classes
data['target'].value_counts()<jupyter_output><empty_output><jupyter_text>--- Prepare Data---<jupyter_code>scaler = MinMaxScaler()
scaler.fit(data.drop(data.columns[-2:], axis = 1))

features = scaler.transform(data.drop(data.columns[-2:], axis = 1))
features_df = pd.DataFrame(features, columns = data.columns[:-2])
features_df.describe().round(3)<jupyter_output><empty_output><jupyter_text>--- Oversample Minority Class---<jupyter_code>x = features_df
y = data[data.columns[-1]]

x_imbalanced = np.vstack((x[y == 1], x[y == 0]))
y_imbalanced = np.hstack((y[y == 1], y[y == 0]))

# Create oversampled minority class training dataset 
x_oversampled, y_oversampled = resample(x_imbalanced[y_imbalanced == 0], 
                                        y_imbalanced[y_imbalanced == 0],
                                        replace = True,
                                        n_samples = x_imbalanced[y_imbalanced == 1].shape[0],
                                        random_state = 123)

x_balanced = np.vstack((x[y == 1], x_oversampled))
y_balanced = np.hstack((y[y == 1], y_oversampled))<jupyter_output><empty_output><jupyter_text>--- Build Model---<jupyter_code>x_train, x_test, y_train, y_test = train_test_split(x_balanced, y_balanced, test_size = 0.2, random_state = 0)
kNN = KNeighborsClassifier(n_neighbors = 1, leaf_size = 32, weights = 'distance', algorithm = 'ball_tree')
kNN.fit(x_train, y_train)

y_pred = kNN.predict(x_test)<jupyter_output><empty_output><jupyter_text>--- Model Optimisation---<jupyter_code># Optimal Number of Neighbours
error_rate = []
test_range = range(1, int(round(len(y_test)/75, 0))) 

for i in test_range:
    kNN_test = KNeighborsClassifier(n_neighbors = i, leaf_size = 32, weights = 'distance', algorithm = 'ball_tree')
    kNN_test.fit(x_train, y_train)
    y_pred_test = kNN_test.predict(x_test)
    error_rate.append(np.mean(y_pred_test != y_test))

error_dict = {}
for i in enumerate(error_rate):
    j = int(i[0])
    k = i[1]
    error_dict.update({j: k})
    
error_df = pd.DataFrame(error_dict.values(), index = error_dict.keys()).reset_index().rename(columns = {'index': 'Optimal k', 0:'Error'})
optimal_kNN = error_df[error_df['Error'] == np.min(error_df['Error'])]
plt.figure(figsize = (8, 4))
plt.plot(test_range, error_rate)
plt.title('Optimal Number of Neighbours')
plt.xlabel('k')
plt.ylabel('Error Rate');

print('Min error:', optimal_kNN['Error'].values[0].round(3))
print('Optimal k-value: ', optimal_kNN['Optimal k'].values[0])<jupyter_output>Min error: 0.084
Optimal k-value:  38<jupyter_text>--- Re-run model with optimal k-value---<jupyter_code>kNN_optimal = KNeighborsClassifier(n_neighbors = optimal_kNN['Optimal k'].values[0], leaf_size = 32, weights = 'distance', algorithm = 'ball_tree')
kNN_optimal.fit(x_train, y_train)

y_pred_optimal = kNN_optimal.predict(x_test)

conf_matrix = confusion_matrix(y_test, y_pred_optimal)
report = classification_report(y_test, y_pred_optimal) 
# Plot Output 
sns.heatmap(conf_matrix, annot = True, xticklabels = ['False', 'True'], 
            yticklabels = ['False', 'True'], cbar = False, fmt = 'g').invert_yaxis()
plt.title('kNN Confusion Matrix')
plt.xlabel('Predicted')
plt.ylabel('Actual');
print(report)
x_final = data.iloc[:, :10]

scaler.fit(x_final)
x_features = scaler.transform(x_final)
x_features_df = pd.DataFrame(x_features, columns = x_final.columns)
features_df.describe().round(3)

pred_all = kNN_optimal.predict(x_features_df)

tele_type, f_class = {},{}
for i in enumerate(pred_all):
    if i[1] == 1:
        j = 'Gamma'
    elif i[1] == 0:
        j = 'Hadron'
    tele_type.update({i[0]: j})
    f_class.update({i[0]: i[1]})<jupyter_output><empty_output><jupyter_text>--- Final Results & Conclusions---<jupyter_code>data['kNN_pred'] = data.index.map(f_class)
data['kNN_type'] = data.index.map(tele_type)

accuracy_all = accuracy_score(data['target'], data['kNN_pred'])
conf_matrix2 = confusion_matrix(data['target'], data['kNN_pred'])
report2 = classification_report(data['target'], data['kNN_pred'])

sns.heatmap(conf_matrix2, annot = True, xticklabels = ['False', 'True'], 
            yticklabels = ['False', 'True'], cbar = False, fmt = 'g').invert_yaxis()

plt.title('kNN Confusion Matrix')
plt.xlabel('Predicted')
plt.ylabel('Actual');

print('Model accuracy: ', (100 * accuracy_all).round(1),'%\n')
plt.show()
print(report2)<jupyter_output>Model accuracy:  96.4 %
{'fraction_non_alphanumeric': 0.14834177421989872, 'fraction_numerical': 0.013723247835321027, 'mean_word_length': 4.6113657195233735, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '454348', 'license': 'MIT', 'n_tokens_mistral': 2255, 'n_tokens_neox': 2137, 'n_words': 474, 'path': 'Classification/k-Nearest Neighbours/KNN_telescope_oversample.ipynb', 'repo_name': 'sciDelta/Machine-Learning', 'size': '6121'}