# K-Nearest Neighbour ( Non-Linear Classifier )

# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# Importing the dataset
dataset = pd.read_csv( 'data/Social_Network_Ads.csv' )

# Feature Selection
X = dataset.iloc[:, [2,3]].values
y = dataset.iloc[:, 4].values

# Splitting the dataset into Training and Test set
from sklearn.cross_validation import train_test_split

X_train, X_test, y_train, y_test = train_test_split( X, y, test_size = 0.25 )

# Feature Scaling
from sklearn.preprocessing import StandardScaler

sc_X = StandardScaler()
X_train = sc_X.fit_transform( X_train )
X_test = sc_X.transform( X_test )

# Fitting classifier to the Training set
from sklearn.neighbors import KNeighborsClassifier
# metric = minkowski and p = 2 for euclidean distance
# metric = minkowski and p = 1 for manhattan distance
# see documentation for more
nearestNeighbourClassifier = KNeighborsClassifier( n_neighbors = 5, metric = 'minkowski', p = 2 )

nearestNeighbourClassifier.fit( X_train, y_train )

# Predicting the Test set results
y_pred = nearestNeighbourClassifier.predict( X_test )

# Confusion Matrix
'''
    The principal diagonal shows correct classification
    and other shows incorrect classification
'''
from sklearn.metrics import confusion_matrix

confusionMatrix = confusion_matrix( y_test, y_pred )

# Visualing the Training set results
from matplotlib.colors import ListedColormap

X_set, y_set = X_train, y_train

X1, X2 = np.meshgrid( 
                        np.arange( start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01 ),
                        np.arange( start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01 ) 
                    )
                    
plt.contourf( X1, X2, nearestNeighbourClassifier.predict( np.array( [ X1.ravel(), X2.ravel() ] ).T).reshape( X1.shape ),
             alpha = 0.75, cmap = ListedColormap( ( 'red', 'green' ) ) )
plt.xlim( X1.min(), X1.max() )
plt.ylim( X2.min(), X2.max() )

for i, j in enumerate( np.unique( y_set ) ):
    plt.scatter( X_set[ y_set == j, 0 ], X_set[ y_set == j, 1 ], c = ListedColormap( ( 'red', 'green' ) )(i), label = j )
    
plt.title( 'K-Nearest Neighbour Classification ( Training Set ) ' )
plt.xlabel( 'Age' )
plt.ylabel( 'Estimated Salary' )
plt.legend()
plt.show()

# Visualing the Test set results
from matplotlib.colors import ListedColormap

X_set, y_set = X_test, y_test

X1, X2 = np.meshgrid( 
                        np.arange( start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01 ),
                        np.arange( start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01 ) 
                    )
                    
plt.contourf( X1, X2, nearestNeighbourClassifier.predict( np.array( [ X1.ravel(), X2.ravel() ] ).T).reshape( X1.shape ),
             alpha = 0.75, cmap = ListedColormap( ( 'red', 'green' ) ) )
plt.xlim( X1.min(), X1.max() )
plt.ylim( X2.min(), X2.max() )

for i, j in enumerate( np.unique( y_set ) ):
    plt.scatter( X_set[ y_set == j, 0 ], X_set[ y_set == j, 1 ], c = ListedColormap( ( 'red', 'green' ) )(i), label = j )
    
plt.title( 'K-Nearest Neighbour Classification ( Test Set ) ' )
plt.xlabel( 'Age' )
plt.ylabel( 'Estimated Salary' )
plt.legend()
plt.show()