import numpy as np 
import pandas as pd 
import sklearn

import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler
%matplotlib inline


# Ignore useless warnings
import warnings
warnings.filterwarnings(action="ignore")
!ls ../input/
"""
# Get the Data
"""
train = pd.read_csv('../input/house-prices-advanced-regression-techniques/train.csv')
test = pd.read_csv('../input/house-prices-advanced-regression-techniques/test.csv')

train.shape, test.shape
train.info()
train.head()
train = train.drop("Id", axis=1)
plt.figure(figsize=(9,8))
sns.distplot(train['SalePrice'], color='g', bins=100);
list(set(train.dtypes.tolist()))
train_num = train.select_dtypes(include = ['float64', 'int64'])
train_cat = train.select_dtypes(include = ['O'])
"""
# **Numerics Features - Univariate Distribution, Missing Values, and Correlations**
"""
#univariate distributions
num_dist = train_num.describe(percentiles=[0.01,0.05,0.10,0.25,0.50,0.75,0.90,0.95,0.99]).T
num_dist = num_dist.rename(columns={"count": "non-missing count"})

#missing values
missing_ = train_num.isnull().sum().to_frame(name = "missing count")
missing_["missing pct"] = missing_["missing count"] / len(train)

#correlations
corr_matrix = train_num.corr()
corr_matrix["abs SalePrice Corr"] = abs(corr_matrix["SalePrice"])
corr_ = corr_matrix[["SalePrice","abs SalePrice Corr"]]
corr_ = corr_.rename(columns={"SalePrice": "SalePrice Corr"})

#Concatenate
num_dist = pd.concat([corr_, missing_, num_dist], 
                     axis=1).sort_values(by='abs SalePrice Corr', ascending=False)

num_dist.style.format({'missing pct':"{:.2%}",
                       'mean':"{:.1f}",
                       'std':"{:.1f}",
                       '5%':"{:.1f}",
                       '10%':"{:.1f}",
                       '25%':"{:.1f}",
                       '50%':"{:.1f}",
                       '75%':"{:.1f}",
                       '90%':"{:.1f}",
                       '95%':"{:.1f}",
                       '99%':"{:.1f}",
                       'min':"{:.1f}",
                       'max':"{:.1f}",
                       'SalePrice Corr':"{:.2f}",
                       'abs SalePrice Corr':"{:.2f}",
                       'missing count':"{:.0f}",
                       'non-missing count':"{:.0f}"
                      })

missing_[missing_["missing pct"] > 0].sort_values(by="missing pct",ascending=False)
num_dist[num_dist["abs SalePrice Corr"] > 0.5]
highCorr = num_dist[num_dist["abs SalePrice Corr"] > 0.5].T
cols = list(highCorr.columns)

sns.pairplot(train_num[cols], height = 3, corner=True)
plt.show();
for i in range(0, len(train_num.columns),5):
    sns.pairplot(data=train_num,
                x_vars=train_num.columns[i:i+5],
                y_vars=['SalePrice']
                )
"""
# Categorical Features - Univariate Analysis & Data Quality
"""
cat = list(train.select_dtypes(include = ['O']).columns)

def bp(x, y, **kwargs):
    sns.boxplot(x=x, y=y)
    x=plt.xticks(rotation=90)
    
f = pd.melt(train, id_vars=['SalePrice'], value_vars=cat)
g = sns.FacetGrid(f, col="variable",  col_wrap=3, sharex=False, sharey=False, size=5)
g = g.map(bp, "value", "SalePrice")

train_cat = train.select_dtypes(include = ['O'])

missing_cat = train_cat.isna().sum().to_frame(name = "missing count")
missing_cat["missing pct"] = missing_cat["missing count"] / len(train)

missing_cat[missing_cat["missing pct"] > 0].sort_values(by="missing pct",ascending=False)
"""
# Data Cleansing
"""
train["PoolQC"] = train["PoolQC"].fillna("None")
train["MiscFeature"] = train["MiscFeature"].fillna("None")
train["Alley"] = train["Alley"].fillna("None")
train["Fence"] = train["Fence"].fillna("None")
train["FireplaceQu"] = train["FireplaceQu"].fillna("None")

train["LotFrontage"] = train.groupby("Neighborhood")["LotFrontage"].transform(lambda x: x.fillna(x.median()))

for col in ('GarageType', 'GarageFinish', 'GarageQual', 'GarageCond'):
    train[col] = train[col].fillna('None')
for col in ('GarageYrBlt', 'GarageArea', 'GarageCars'):
    train[col] = train[col].fillna(0)

for col in ('BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF','TotalBsmtSF', 'BsmtFullBath', 'BsmtHalfBath'):
    train[col] = train[col].fillna(0)
for col in ('BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2'):
    train[col] = train[col].fillna('None')
      
train["MasVnrType"] = train["MasVnrType"].fillna("None")
train["MasVnrArea"] = train["MasVnrArea"].fillna(0)

train['MSZoning'] = train['MSZoning'].fillna(train['MSZoning'].mode()[0])

train["Functional"] = train["Functional"].fillna("Typ")
train['Electrical'] = train['Electrical'].fillna(train['Electrical'].mode()[0])
train['KitchenQual'] = train['KitchenQual'].fillna(train['KitchenQual'].mode()[0])
train['Exterior1st'] = train['Exterior1st'].fillna(train['Exterior1st'].mode()[0])
train['Exterior2nd'] = train['Exterior2nd'].fillna(train['Exterior2nd'].mode()[0])
train['SaleType'] = train['SaleType'].fillna(train['SaleType'].mode()[0])
train['MSSubClass'] = train['MSSubClass'].fillna("None")

"""
# Tranform Categorical Variables into dummy variables 
"""
cat_col = list(train.select_dtypes(include = ['O']).columns)
train = pd.get_dummies(train, columns = cat_col)
"""
# Regression
"""
train_X = train.drop("SalePrice", axis=1) # drop labels for training set
train_Y = train["SalePrice"].copy()
from sklearn.linear_model import LinearRegression

lin_reg = LinearRegression()
lin_reg.fit(train_X, train_Y)

from sklearn.metrics import mean_squared_error

homevalue_predictions = lin_reg.predict(train_X)
lin_mse = mean_squared_error(train_Y, homevalue_predictions)
lin_rmse = np.sqrt(lin_mse)

from sklearn.metrics import mean_absolute_error
lin_mae = mean_absolute_error(train_Y, homevalue_predictions)

lin_rmse, lin_mae
from sklearn.model_selection import cross_val_score

scores = cross_val_score(lin_reg, train_X, train_Y, scoring="neg_mean_squared_error", cv=10)
pd.Series(np.sqrt(-scores)).describe()
"""
# Random Forest
"""
from sklearn.ensemble import RandomForestRegressor

forest_reg = RandomForestRegressor(n_estimators=100, random_state=42)
forest_reg.fit(train_X, train_Y)

homevalue_predictions = forest_reg.predict(train_X)
forest_mse = mean_squared_error(train_Y, homevalue_predictions)
forest_rmse = np.sqrt(forest_mse)
forest_rmse
from sklearn.model_selection import cross_val_score

forest_scores = cross_val_score(forest_reg, train_X, train_Y,
                                scoring="neg_mean_squared_error", cv=10)
forest_rmse_scores = np.sqrt(-forest_scores)
display_scores(forest_rmse_scores)
"""
# Support Vector Regression
"""
from sklearn.svm import SVR

svm_reg = SVR(kernel="linear")
svm_reg.fit(train_X, train_Y)
homevalue_predictions = svm_reg.predict(train_X)
svm_mse = mean_squared_error(train_Y, homevalue_predictions)
svm_rmse = np.sqrt(svm_mse)
svm_rmse
"""
# Fine Tune Model - Grid Search
"""
from sklearn.model_selection import GridSearchCV

param_grid = [
    # try 12 (3×4) combinations of hyperparameters
    {'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]},
    # then try 6 (2×3) combinations with bootstrap set as False
    {'bootstrap': [False], 'n_estimators': [3, 10], 'max_features': [2, 3, 4]},
  ]

forest_reg = RandomForestRegressor(random_state=42)
# train across 5 folds, that's a total of (12+6)*5=90 rounds of training 
grid_search = GridSearchCV(forest_reg, param_grid, cv=5,
                           scoring='neg_mean_squared_error',
                           return_train_score=True)
grid_search.fit(train_X, train_Y)
grid_search.best_params_
grid_search.best_estimator_
cvres = grid_search.cv_results_
for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):
    print(np.sqrt(-mean_score), params)
"""
# To be Continued...
"""