import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import precision_score, recall_score, f1_score, accuracy_score
from sklearn.datasets import load_iris
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import AdaBoostClassifier


# ===============================
# 1. Load Dataset
# ===============================

df = pd.read_csv("./tennis.csv")

print("\nFirst 5 Records")
print(df.head())

print("\nLast 5 Records")
print(df.tail())


# ===============================
# 2. Encode categorical values
# ===============================

le = LabelEncoder()

for col in df.columns:
    le = LabelEncoder()
    df[col] = le.fit_transform(df[col])

    # # print mapping
    # mapping = dict(zip(le.classes_, le.transform(le.classes_)))
    # print(f"\nMapping for {col}:")
    # print(mapping)

print("\nEncoded Dataset")
print(df)


encoded_df = pd.get_dummies(df)

print("\nOne-Hot Encoded Dataset")
print(encoded_df)

from sklearn.preprocessing import OneHotEncoder

encoder = OneHotEncoder(sparse_output=False)

# fit and transform
encoded_arr = encoder.fit_transform(df)

# convert to dataframe with column names
encoded_df = pd.DataFrame(
    encoded_arr,
    columns=encoder.get_feature_names_out()
)

print(encoded_df)



# ===============================
# 3. Split dataset (70/30)
# ===============================

X = df.drop("Play", axis=1)
y = df["Play"]

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

print("\nTraining size:", len(X_train))
print("Testing size:", len(X_test))


# ===============================
# 4. Hunt's Algorithm
# (Random split tree)
# ===============================

hunts_tree = DecisionTreeClassifier(criterion="gini")
hunts_tree.fit(X_train, y_train)

y_pred_hunts = hunts_tree.predict(X_test)


# ===============================
# 5. ID3 Algorithm
# (Entropy based)
# ===============================

id3_tree = DecisionTreeClassifier(criterion="entropy")
id3_tree.fit(X_train, y_train)

y_pred_id3 = id3_tree.predict(X_test)


# ===============================
# 6. Compare Actual vs Predicted
# ===============================

print("\nActual Values :", y_test.values)
print("Predicted ID3 :", y_pred_id3)


# ===============================
# 7. Evaluation Metrics
# ===============================

precision = precision_score(y_test, y_pred_id3)
recall = recall_score(y_test, y_pred_id3)
f1 = f1_score(y_test, y_pred_id3)

print("\nModel Evaluation (ID3)")
print("Precision:", precision)
print("Recall:", recall)
print("F1 Score:", f1)

# ===============================
# 1. Load Iris Dataset
# ===============================

iris = load_iris()
X = iris.data
y = iris.target

print("Dataset size:", X.shape)


# ===============================
# 2. Split Dataset (70% Train, 30% Test)
# ===============================

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

print("Training samples:", len(X_train))
print("Testing samples:", len(X_test))


# ===============================
# 3. Initialize Base Classifier
# ===============================

base_classifier = DecisionTreeClassifier()

# ===============================
# 4. Initialize Bagging Classifier
# ===============================

bagging_model = BaggingClassifier(
    estimator=base_classifier,
    n_estimators=10,
    random_state=42
)


# ===============================
# 5. Train the Model
# ===============================

bagging_model.fit(X_train, y_train)


# ===============================
# 6. Make Predictions
# ===============================

y_pred = bagging_model.predict(X_test)

print("\nPredicted values:", y_pred)


# ===============================
# 7. Evaluate Accuracy
# ===============================

accuracy = accuracy_score(y_test, y_pred)

print("\nAccuracy:", accuracy)


# ==================================
# 1. Load Dataset
# ==================================

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

# Select required columns
df = df[['age','sex','cp','trestbps','chol','fbs','target']]

print("First 5 rows")
print(df.head())


# ==================================
# 2. Handle Missing Values
# ==================================

df.replace('?', np.nan, inplace=True)
df.dropna(inplace=True)

df.fillna(df.mean(numeric_only=True), inplace=True)
df.fillna(df.median(numeric_only=True), inplace=True)
df.fillna(df.mode().iloc[0], inplace=True)

# df['age'].fillna(df['age'].mean(), inplace=True)
# df['chol'].fillna(df['chol'].median(), inplace=True)
# df['sex'].fillna(df['sex'].mode()[0], inplace=True)

# from sklearn.impute import SimpleImputer
# imputer = SimpleImputer(strategy='mean')

# df[['age','chol']] = imputer.fit_transform(df[['age','chol']])

# ==================================
# 3. Convert target to binary
# ==================================

df['target'] = df['target'].apply(lambda x: 1 if x > 0 else 0)
# le = LabelEncoder()
# df['target'] = le.fit_transform(df['target'])
# print(df['target'])

# ==================================
# 4. Split Features and Labels

# X = df.drop("target", axis=1)
# y = df["target"]

X = df.drop("target", axis=1).values
y = df["target"].values


# ==================================
# 5. Train Test Split (80 / 20)
# ==================================

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


# ==================================
# 6. Base Classifier
# ==================================

base_clf = DecisionTreeClassifier(max_depth=1)


# ==================================
# 7. AdaBoost Model (3 estimators)
# ==================================

ada_model = AdaBoostClassifier(
    estimator=base_clf,
    n_estimators=3,
    learning_rate=1,
    random_state=42
)


# ==================================
# 8. Train Model
# ==================================

ada_model.fit(X_train, y_train)


# ==================================
# 9. Alpha values of weak learners
# ==================================

print("\nAlpha values of weak learners:")
print(ada_model.estimator_weights_)


# ==================================
# 10. Training Accuracy of weak learners
# ==================================

print("\nTraining accuracy of weak learners:")

for i, tree in enumerate(ada_model.estimators_):
    y_pred_train = tree.predict(X_train)
    acc = accuracy_score(y_train, y_pred_train)
    print(f"Weak Learner {i+1} Accuracy:", acc)


# ==================================
# 11. Final Test Accuracy
# ==================================

y_pred = ada_model.predict(X_test)

final_accuracy = accuracy_score(y_test, y_pred)

print("\nFinal AdaBoost Test Accuracy:", final_accuracy)

