"""
# KNN (K Neirest Neighbour) Algorithm Implementation on Cancer Dataset
"""
"""
## Content:

1. [Importing Dataset](#1)
1. [Getting Info About Dataset](#2)
1. [Dataset Visualization](#3)
1. [Meaning Of KNN Algorithm](#4)
1. [KNN with Sklearn](#5)
1. [Conclusion](#6)
"""
# This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt

# Input data files are available in the read-only "../input/" directory
# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory

import os
for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using "Save & Run All" 
# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session
"""
<a id = "1"></a>

## 1. Importing Dataset:
"""
dataset = pd.read_csv("/kaggle/input/breast-cancer-wisconsin-data/data.csv")
"""
> <a id = "2"></a>
# 2. Getting Info About Dataset
"""
"""
Dataset information:

* Dataset Characteristics: Multivariate
* Attribute Characteristics: Real
* Attribute Characteristics: Classification
* Number of Instances: 569
* Number of Attributes: 32
* Missing Values: No
"""
"""
Column names and meanings:
* id: ID number
* diagnosis: The diagnosis of breast tissues (M = malignant, B = benign)
* radius_mean: mean of distances from center to points on the perimeter
* texture_mean: standard deviation of gray-scale values
* perimeter_mean: mean size of the core tumor
* area_mean: area of the tumor
* smoothness_mean: mean of local variation in radius lengths
* compactness_mean: mean of perimeter^2 / area - 1.0
* concavity_mean: mean of severity of concave portions of the contour
* concave_points_mean: mean for number of concave portions of the contour
* symmetry_mean
* fractal_dimension_mean: mean for "coastline approximation" - 1
* radius_se: standard error for the mean of distances from center to points on the perimeter
* texture_se: standard error for standard deviation of gray-scale values
* perimeter_se
* area_se
* smoothness_se: standard error for local variation in radius lengths
* compactness_se: standard error for perimeter^2 / area - 1.0
* concavity_se: standard error for severity of concave portions of the contour
* concave_points_se: standard error for number of concave portions of the contour
* symmetry_se
* fractal_dimension_se: standard error for "coastline approximation" - 1
* radius_worst: "worst" or largest mean value for mean of distances from center to points on the perimeter
* texture_worst: "worst" or largest mean value for standard deviation of gray-scale values
* perimeter_worst
* area_worst
* smoothness_worst: "worst" or largest mean value for local variation in radius lengths
* compactness_worst: "worst" or largest mean value for perimeter^2 / area - 1.0
* concavity_worst: "worst" or largest mean value for severity of concave portions of the contour
* concave_points_worst: "worst" or largest mean value for number of concave portions of the contour
* symmetry_worst
* fractal_dimension_worst: "worst" or largest mean value for "coastline approximation" - 1
"""
dataset.head()
dataset.info()
"""
Now, let's get rid of "id" and "Unnamed: 32" features because we don't need to use them while diagnosing whether the patient has a cancer or not. 
"""
dataset = dataset.drop(["id"], axis = 1)
dataset = dataset.drop(["Unnamed: 32"], axis = 1)
dataset.head(3)
M = dataset[dataset.diagnosis == "M"]
M.head(5)
B = dataset[dataset.diagnosis == "B"]
B.head(5)
"""
<a id = "3"></a>
# 3. Dataset Visualization 
"""
plt.title("Malignant vs Benign Tumor")
plt.xlabel("Radius Mean")
plt.ylabel("Texture Mean")
plt.scatter(M.radius_mean, M.texture_mean, color = "red", label = "Malignant", alpha = 0.3)
plt.scatter(B.radius_mean, B.texture_mean, color = "lime", label = "Benign", alpha = 0.3)
plt.legend()
plt.show()
"""
<a id = "4"></a>
# 4. Meaning Of KNN Algorithm
"""
"""
1. Choose k value.
2. Find k points closest to the specified point.
3. Determine how mant of the class among the 3 closest points to the specified point.
4. Determine which class the point being tested belongs to.
"""
"""
For example:

Our point is x = 20, y = 30.

1. k = 3
2. We found 3 nearest neighbour.
3. 3 Malignant dots, 0 Benign dots.
4. Conclusion: our point belongs to the Malignant class.
"""
"""
<a id = "5"></a>
# 5. KNN with Sklearn
"""
dataset.diagnosis = [1 if i == "M" else 0 for i in dataset.diagnosis]
x = dataset.drop(["diagnosis"], axis = 1)
y = dataset.diagnosis.values
# Normalization:
x = (x - np.min(x)) / (np.max(x) - np.min(x))
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.3, random_state = 42)
from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors = 4)  # n_neighbors = k
knn.fit(x_train, y_train)

prediction = knn.predict(x_test)
prediction
print("KNN score: ", knn.score(x_test, y_test))
scores = []
for i in range(1,15):
    knn_ = KNeighborsClassifier(n_neighbors = i)
    knn_.fit(x_train, y_train)
    scores.append(knn_.score(x_test, y_test))
    
plt.plot(range(1,15), scores)
plt.xlabel("k values")
plt.ylabel("accuracy")
plt.show()
"""
<a id = "6"></a>
# 6. Conclusion
"""
"""
If our k value equals to 4, it gives best result.
"""