"""
## Applied Machine Learning in Python - Notebook 1

### Module 1: Simple classification task

"""
# Importing required modules

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.model_selection import train_test_split
# Loading data
fruits = pd.read_csv('../input/fruits/fruits.csv')
# Visualizing data
fruits.head()
"""
The features available for each entry are the mass, height, and width of mandarins, oranges, lemons and apples. Heights are measured along the core and widths are the widest measurment perpendicular to the core.
"""
# Creating dictionary with fruit labels as keys and names as values
fruit_name = dict(zip(fruits.fruit_label.unique(), fruits.fruit_name.unique()))
fruit_name
"""
### Examing the data
"""
# lists with features and labels
X = fruits[['height', 'width', 'mass', 'color_score']]
y = fruits['fruit_label']

# Splitting in train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# plotting a scatter matrix
from matplotlib import cm
from pandas.plotting import scatter_matrix

cmap = cm.get_cmap('gnuplot')
scatter = scatter_matrix(X_train, c= y_train, marker = 'o', s=40, hist_kwds={'bins':15}, figsize=(7,7), cmap=cmap)
# plotting a 3D scatter plot
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
ax.scatter(X_train['width'], X_train['height'], X_train['color_score'], c = y_train, marker = 'o', s=100)
ax.set_xlabel('width')
ax.set_ylabel('height')
ax.set_zlabel('color_score')
plt.show()
"""
### Creating a K-nearest neighbors classifier object
"""
# Choosing features
X = fruits[['mass', 'width', 'height']]
y = fruits['fruit_label']

# Tran test split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors = 5)

# Training
knn.fit(X_train, y_train)

# Estimating accuracy using test data
knn.score(X_test, y_test)
"""
### Classifying unseen data
"""
# first example: a small fruit with mass 20g, width 4.3 cm, height 5.5 cm
fruit_prediction = knn.predict([[20, 4.3, 5.5]])
fruit_name[fruit_prediction[0]]
"""
### Plotting k-NN classifier decision boundaries
"""
## Code by Shahul Es stack overflow

import matplotlib.cm as cm
from matplotlib.colors import ListedColormap, BoundaryNorm
import matplotlib.patches as mpatches
import matplotlib.patches as mpatches


def plot_fruit_knn(X, y, n_neighbors, weights):
    X_mat = X[['height', 'width']].values
    y_mat = y.values
# Create color maps
    cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#FCBF56','#FFFD6B'])
    cmap_bold  = ListedColormap(['#FF0000', '#00FF00', '#FFA100','#E8E500'])
    clf = KNeighborsClassifier(n_neighbors, weights=weights)
    clf.fit(X_mat, y_mat)
# Plot the decision boundary by assigning a color in the color map
    # to each mesh point.

    mesh_step_size = .01  # step size in the mesh
    plot_symbol_size = 50

    x_min, x_max = X_mat[:, 0].min() - 1, X_mat[:, 0].max() + 1
    y_min, y_max = X_mat[:, 1].min() - 1, X_mat[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, mesh_step_size),
                         np.arange(y_min, y_max, mesh_step_size))
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
# Put the result into a color plot
    Z = Z.reshape(xx.shape)
    plt.figure()
    plt.pcolormesh(xx, yy, Z, cmap=cmap_light, shading='auto')
# Plot training points
    plt.scatter(X_mat[:, 0], X_mat[:, 1], s=plot_symbol_size, c=y, 
                cmap=cmap_bold, edgecolor = 'black')
    plt.xlim(xx.min(), xx.max())
    plt.ylim(yy.min(), yy.max())
    patch0 = mpatches.Patch(color='#FF0000', label='apple')
    patch1 = mpatches.Patch(color='#00FF00', label='mandarin')
    patch2 = mpatches.Patch(color='#FFA100', label='orange')
    patch3 = mpatches.Patch(color='#E8E500', label='lemon')
    plt.legend(handles=[patch0, patch1, patch2, patch3])

#plt.title("4-Class classification (k = %i, weights = '%s')" % (n_neighbors, weights))    

plot_fruit_knn(X_train, y_train, 5, 'uniform')
plt.xlabel('height (cm)')
plt.ylabel('width (cm)')
plt.show()
"""
### Checking k-NN accuracy sensitivity to the k parameter
"""
k_range = range(1,20)
scores = []

for k in k_range:
    knn = KNeighborsClassifier(n_neighbors = k)
    knn.fit(X_train, y_train)
    scores.append(knn.score(X_test, y_test))

plt.figure()
plt.xlabel('k')
plt.ylabel('accuracy')
plt.scatter(k_range, scores)
plt.xticks([0,5,10,15,20]);
"""
### Checking k-NN accuracy sensitivity to the train/test split proportion
"""
t = [0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2]

knn = KNeighborsClassifier(n_neighbors = 5)

plt.figure()

for s in t:

    scores = []
    for i in range(1,1000):
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 1-s)
        knn.fit(X_train, y_train)
        scores.append(knn.score(X_test, y_test))
    plt.plot(s, np.mean(scores), 'bo')

plt.xlabel('Training set proportion (%)')
plt.ylabel('accuracy');