# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python [conda env:571]
#     language: python
#     name: conda-env-571-py
# ---

import os
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import altair as alt
from sklearn import datasets
from sklearn.compose import ColumnTransformer, make_column_transformer
from sklearn.dummy import DummyRegressor
from sklearn.ensemble import RandomForestRegressor
from catboost import CatBoostRegressor
from sklearn.impute import SimpleImputer
from sklearn.linear_model import Ridge, RidgeCV, Lasso
from sklearn.svm import SVC, SVR
from sklearn.metrics import r2_score, mean_squared_error
from sklearn.ensemble import VotingRegressor
from sklearn.ensemble import StackingRegressor
from sklearn.model_selection import (
 cross_val_score,
 cross_validate,
 train_test_split,
 GridSearchCV,
 RandomizedSearchCV
)
from sklearn.pipeline import Pipeline, make_pipeline
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder, StandardScaler, LabelEncoder
from sklearn.tree import DecisionTreeRegressor, export_graphviz
from xgboost import XGBRegressor
from catboost import CatBoostRegressor
from lightgbm.sklearn import LGBMRegressor
import shap
# Save a vega-lite spec and a PNG blob for each plot in the notebook
alt.renderers.enable('mimetype')


# ### Transform data 

X_train = pd.read_csv("../data/raw/X_train.csv", parse_dates=['year'])
X_train['year'] = X_train['year'].dt.year
y_train = pd.read_csv("../data/raw/y_train.csv")
train_df = X_train.join(y_train.set_index('carID'), on = "carID")

train_df.head()

train_df.info()

drop_features = ["carID"]
categorical_features = ["brand", "model", "transmission", "fuelType"]
ordinal_features = ["year"]
target = "price"
numeric_features = list(
    set(train_df.columns)
    - set(drop_features)
    - set(categorical_features)
    - set(ordinal_features)
    - set([target])
)
assert train_df.columns.shape[0] == len(
    drop_features
    + categorical_features
    + numeric_features
    + ordinal_features
    + [target]
)

preprocessor = make_column_transformer(
    (StandardScaler(), numeric_features),
    (OneHotEncoder(handle_unknown="ignore", dtype="int"), categorical_features),
    (OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=np.nan), ordinal_features),
    ("drop", drop_features))

X_train, y_train = train_df.drop(columns=[target]), train_df[target]

scoring_metrics = {
    "neg RMSE": "neg_root_mean_squared_error",
    "r2": "r2"}

preprocessor.fit(X_train)


# + [markdown] tags=[]
# ### Models
# -

# #### baseline

def mean_std_cross_val_scores(model, X_train, y_train, **kwargs):
    """
    Returns mean and std of cross validation

    Parameters
    ----------
    model :
        scikit-learn model
    X_train : numpy array or pandas DataFrame
        X in the training data
    y_train :
        y in the training data

    Returns
    ----------
        pandas Series with mean scores from cross_validation
    """

    scores = cross_validate(model, X_train, y_train, **kwargs)

    mean_scores = pd.DataFrame(scores).mean()
    std_scores = pd.DataFrame(scores).std()
    out_col = []

    for i in range(len(mean_scores)):
        out_col.append((f"%0.3f (+/- %0.3f)" % (mean_scores[i], std_scores[i])))

    return pd.Series(data=out_col, index=mean_scores.index)


results ={}

dummy = DummyRegressor()
results["Dummy"] = mean_std_cross_val_scores(
    dummy, X_train, y_train, return_train_score=True, scoring=scoring_metrics
)

pd.DataFrame(results)

# +
pipe_lr = make_pipeline(
    preprocessor, Ridge(random_state=123)
)

pipe_ls = make_pipeline(
    preprocessor, Lasso(random_state=123)
)

pipe_rf = make_pipeline(
    preprocessor, RandomForestRegressor(random_state=123)
)

pipe_catboost = make_pipeline(
    preprocessor, CatBoostRegressor(random_state=123, verbose = 0)
)
# -

models = {
    "linear regression": pipe_lr,
    "lasso": pipe_ls,
    "random forest": pipe_rf,
    "CatBoost": pipe_catboost
}

for (name, model) in models.items():
    results[name] = mean_std_cross_val_scores(
        model, X_train, y_train, return_train_score=True, scoring=scoring_metrics
    )

pd.DataFrame(results)

pipe_catboost.fit(X_train, y_train)

plt.scatter(y_train, pipe_catboost.predict(X_train), alpha=0.3)
grid = np.linspace(y_train.min(), y_train.max(), 1000)
plt.plot(grid, grid, "--k")
plt.xlabel("True Price")
plt.ylabel("Predicted Price");

preprocessor.fit(X_train, y_train)

feature_names = (
    numeric_features
    + list(
        pipe_lr.named_steps["columntransformer"]
        .named_transformers_["onehotencoder"]
        .get_feature_names_out()
    )
    + ordinal_features)

X_train_encode = pd.DataFrame(
    data=preprocessor.transform(X_train).toarray(),
    columns=feature_names,
    index=X_train.index,
)
X_train_encode.head()

pipe_catboost.fit(X_train, y_train)

catboost_explainer = shap.TreeExplainer(pipe_catboost.named_steps["catboostregressor"])
train_catboost_shap_values = catboost_explainer.shap_values(X_train_encode)

shap.summary_plot(train_catboost_shap_values, X_train_encode, plot_type="bar")

shap.summary_plot(train_catboost_shap_values, X_train_encode)

X_test = pd.read_csv("../data/raw/X_test.csv", parse_dates=['year'])
X_test['year'] = X_test['year'].dt.year
y_test = pd.read_csv("../data/raw/y_test.csv")

X_test_encode = pd.DataFrame(
    data=preprocessor.transform(X_test).toarray(),
    columns=feature_names,
    index=X_test.index,
)

test_catboost_shap_values = catboost_explainer.shap_values(X_test_encode)

X_test_encode = X_test_encode.round(2)

shap.force_plot(
    catboost_explainer.expected_value,
    test_catboost_shap_values[8],
    X_test_encode.loc[8, :],
    matplotlib=True,
)

y_predict = pipe_catboost.predict(X_test)

y_predict

r2_score(y_test['price'], y_predict)

StarcoderdataJupyterScriptsDedupFiltered