import pandas as pd

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix

# 1. LOAD DATASET

df = pd.read_csv("StudentPerformanceFactors.csv")

print(df.head())
print(df.isnull().sum())

# 2. SELECT FEATURES

features = ["Attendance", "Hours_Studied", "Previous_Scores"]

df = df.dropna(subset=features + ["Exam_Score"])

X = df[features]

# 3. DEFINE PERFORMANCE CATEGORIES

df["Performance"] = pd.cut(

    df["Exam_Score"],
    bins=[0, 60, 75, 1000],
    labels=["Low", "Medium", "High"], include_lowest=True
)

y = df["Performance"]

print("Class Distribution:\n", y.value_counts())

# 4. TRAIN-TEST SPLIT AND SCALING

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

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

# 5. TRAIN KNN FOR DIFFERENT K VALUES

for k in [3, 5, 7]:

    model = KNeighborsClassifier(n_neighbors=k)
    model.fit(X_train, y_train)

    # 6. PREDICT UNSEEN STUDENT CATEGORIES

    y_pred = model.predict(X_test)

    print("\nK =", k)
    print("Predictions:", y_pred[:10])

    # 7. EVALUATE MODEL

    print("Accuracy:", accuracy_score(y_test, y_pred))
    print("Precision:", precision_score(y_test, y_pred, average="weighted",
zero_division=0))
    print("Recall:", recall_score(y_test, y_pred, average="weighted",

zero_division=0))
    print("Confusion Matrix:\n", confusion_matrix(y_test, y_pred))


# ENHANCED: Training academic-category distribution
import matplotlib.pyplot as plt
y_train.value_counts().sort_index().plot(kind="bar")
plt.ylabel("Training students")
plt.title("Training Performance Categories")
plt.show()
