import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# Load dataset
D = pd.read_csv("D:/4th Year/STAT – 405 Data Mining/2. Python Code/kNN Algorithm/Mymensingh.csv")

# Display the first few rows and the shape of the dataset
print(D.head())
print(D.shape)

# Check for missing values
print(D.isna().sum())

# Save a copy of the original dataset
D.to_csv("D:/4th Year/STAT – 405 Data Mining/2. Python Code/kNN Algorithm/Mymensingh_old.csv", index=False)

# Drop rows with missing values
D.dropna(how='any', inplace=True)

# Drop unnecessary columns
DT = D.drop(['ID', 'Station', 'Year', 'Month', 'T_RAN', 'A_RAIN'], axis=1)

# Define features and labels
Y = DT['RAN']
X = DT.drop(['RAN'], axis=1)

# Split data into training and testing sets
np.random.seed(201681)
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.25, random_state=100)

# Fit kNN classifier with k=8
KNN = KNeighborsClassifier(n_neighbors=8, metric='euclidean')
KNN.fit(X_train, Y_train)

# Predict on test data
P = KNN.predict(X_test)

# Evaluate accuracy
print("Accuracy:", accuracy_score(Y_test, P))
print("Confusion Matrix:\n", confusion_matrix(Y_test, P))
print("Classification Report:\n", classification_report(Y_test, P))

# Find optimal value of k
As = []
Es = []

# Calculating error for K values between 1 and 40
for i in range(1, 40):
    knn = KNeighborsClassifier(n_neighbors=i, metric='euclidean')
    knn.fit(X_train, Y_train)
    pred_i = knn.predict(X_test)
    As.append(accuracy_score(Y_test, pred_i))
    Es.append(1 - accuracy_score(Y_test, pred_i))

# Plot error rate for different k values
plt.figure(figsize=(9, 5))
plt.plot(range(1, 40), Es, color='red', linestyle='solid', marker='o', linewidth=2, markerfacecolor='blue', markersize=10)
plt.axvline(x=8, color='b', ls='--', linewidth=2)
plt.title('Error Rate for different k values')
plt.xlabel('Value of k')
plt.ylabel('Error Rate')
plt.savefig("D:/4th Year/STAT – 405 Data Mining/2. Python Code/kNN Algorithm/Error_Rate_for_k_values.jpg", dpi=500)
plt.show()

# Plot accuracy rate for different k values
plt.figure(figsize=(9, 5))
plt.plot(range(1, 40), As, color='red', linestyle='solid', marker='o', linewidth=2, markerfacecolor='blue', markersize=10)
plt.axvline(x=8, color='b', ls='--', linewidth=2)
plt.title('Accuracy Rate for different k values')
plt.xlabel('Value of k')
plt.ylabel('Accuracy Rate')
plt.savefig("D:/4th Year/STAT – 405 Data Mining/2. Python Code/kNN Algorithm/Accuracy_Rate_for_k_values.jpg", dpi=500)
plt.show()

# Fit kNN classifier with optimal k (8)
KNN1 = KNeighborsClassifier(n_neighbors=8, metric='euclidean')
KNN1.fit(X_train, Y_train)
P1 = KNN1.predict(X_test)

# Evaluate accuracy for optimal k
print("Accuracy with optimal k:", accuracy_score(Y_test, P1))
print("Confusion Matrix:\n", confusion_matrix(Y_test, P1))
print("Classification Report:\n", classification_report(Y_test, P1))
