# This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g.| pd.read_csv)
import seaborn as sns
import matplotlib.pyplot as plt
# Input data files are available in the read-only "../input/" directory
# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory
import os
for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using "Save & Run All" 
# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session
pd.set_option('display.max_columns', None)
"""
# Merging Train and Test
We are merging the train and test data so that we don't have to do seperate data cleaning for the train and test data and after that we will separate them into train and test.
"""
train_data = pd.read_csv("../input/house-prices-advanced-regression-techniques/train.csv", index_col="Id")
test_data = pd.read_csv("../input/house-prices-advanced-regression-techniques/test.csv", index_col="Id")
print("Length of train dataset is", len(train_data))
print("Length of train dataset is", len(test_data))
#The columns in the dataset
print(train_data.columns)
dataset = pd.concat([train_data, test_data])
print("The lenght of combined data is", len(dataset))
#detail info of the dataset
dataset.info()
# null values columns in dataset
dataset.isnull().sum()
dataset.describe()
"""
# Ordinal Features CONVERSION
There are few categorical feature in the dataset that can be converted into the mathematical numbers. For eg. The Garage quality score from 0(lowest) to 5 (highest).
"""
# categorical features that can be turn into numerical features.
rate_features = ["GarageCond","GarageQual", "FireplaceQu", "KitchenQual","PoolQC",
                 "HeatingQC", "BsmtCond", "BsmtQual", "ExterQual", "ExterCond"]
dataset.loc[:, rate_features] = dataset.loc[:, rate_features].fillna("NA")
rate_label = ["Ex", "Gd", "TA", "Fa", "Po", "NA"]
rate_value = [5, 4, 3, 2, 1, 0]
dataset[rate_features] = dataset[rate_features].replace(rate_label, rate_value)

# BsmtExposure
dataset.BsmtExposure.fillna("NA", inplace = True)
dataset["BsmtExposure"].replace({"Gd" : 4, "Av" : 3, "Mn" : 2, "No" : 1, "NA" : 0}, inplace=True)

#Fence
dataset.Fence.fillna("NA", inplace = True)
dataset.Fence.replace({"GdPrv":4, "MnPrv":3, "GdWo":2, "MnWw":1, "NA":0}, inplace=True)

#LotShape
dataset["LotShape"].replace({"Reg": 3, "IR1": 2, "IR2": 1, "IR3": 0}, inplace = True)

# CentralAir
dataset["CentralAir"].replace({"Y":1, "N":0 }, inplace=True)

#GarageFinish
dataset.GarageFinish.fillna("NA", inplace = True)
dataset["GarageFinish"].replace({"Fin":3, "RFn":2, "Unf":1, "NA":0}, inplace=True )

#PavedDrive
dataset["PavedDrive"].replace({"Y":2, "P":1, "N":0}, inplace=True )

#Functional
fun = {"Typ":7, "Min1":6, "Min2":5, "Mod":4, "Maj1":3, "Maj2":2, "Sev":1, "Sal":0}
dataset.Functional.replace(fun, inplace=True)
dataset.Functional.fillna(dataset.Functional.mode()[0], inplace=True)

#BsmtFinType1 and BsmtFinType2
dataset["BsmtFinType1"].fillna("NA", inplace = True)
dataset["BsmtFinType2"].fillna("NA", inplace = True)
bsmt_label = ["GLQ", "ALQ", "BLQ", "Rec", "LwQ", "Unf", "NA"]
bsmt_values = [6, 5, 4, 3, 2, 1, 0]
dataset[["BsmtFinType1", "BsmtFinType2"]].replace(bsmt_label, bsmt_label, inplace=True)

#LandSlope
dataset.LandSlope.replace({"Glt":2, "Mod":1, "Sev":0}, inplace=True)
#MSSubClass as Categorical feature
dataset['MSSubClass'] = dataset['MSSubClass'].astype('O')
"""
# Handling missing values
Handling missing value for categorical data can be done by replacing the None value with the NA for new categorical features.
"""
#MiscFeature replacing the Nan values with NA
dataset.MiscFeature.fillna("NA", inplace=True)
dataset.Alley.fillna("NA", inplace=True)

#MasVnrType and MasVnrArea
# The id 2611 of dataset has of the masvnrArea has 198 and the type of "None" on the MasVnrType
dataset.MasVnrType.fillna("NA", inplace=True)
dataset.MasVnrArea.fillna(0, inplace=True)

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

# SalesType
dataset["SaleType"].fillna(dataset["SaleType"].mode()[0], inplace=True)

# Utilities
dataset["Utilities"].fillna(dataset["Utilities"].mode()[0], inplace=True)

#MSZoning
dataset["MSZoning"].fillna(dataset["MSZoning"].mode()[0], inplace=True)

#Exterior1st and Exterior2nd
dataset["Exterior1st"].fillna(dataset["Exterior1st"].mode()[0], inplace=True)
dataset["Exterior2nd"].fillna(dataset["Exterior2nd"].mode()[0], inplace=True)

##Electrical
dataset["Electrical"].fillna(dataset["Electrical"].mode()[0], inplace=True)

"""
<h3> Garage</h3>
"""
#GarageYrBlt
dataset.GarageYrBlt = dataset.apply(
    lambda row: row['YrSold'] if np.isnan(row['GarageYrBlt']) 
    else row['GarageYrBlt'], axis=1)

#GarageType
dataset.GarageType.fillna("NA", inplace=True)

#GarageCars
dataset.GarageCars = dataset.apply( lambda row: 0 if row['GarageCond'] == 0
    else row['GarageCars'], axis=1)

#GarageArea
dataset.GarageArea = dataset.apply( lambda row: 0 if row['GarageCond'] == 0
    else row['GarageArea'], axis=1)

"""
<h3> Basement</h3>
"""
#Basement
dataset.loc[dataset.BsmtFullBath.isnull()== True]
dataset.BsmtFullBath.fillna(0, inplace=True)
dataset.BsmtFinSF2.fillna(0, inplace=True)
dataset.BsmtUnfSF.fillna(0, inplace=True)
dataset.BsmtFinSF1.fillna(0, inplace=True)
dataset.BsmtHalfBath.fillna(0, inplace=True)
dataset.TotalBsmtSF.fillna(0, inplace=True)
"""
**Date Features**
"""
#year sold vs sales price graph
plt.figure()
temp =  dataset.loc[dataset.SalePrice > 0].copy()
temp.groupby("YrSold")["SalePrice"].median()
sns.lineplot(data=temp, x="YrSold", y="SalePrice")
date_features = ["YearBuilt", "GarageYrBlt", "YrSold", "YearRemodAdd"]
for feature in date_features:
     if feature!='YrSold':
        temp = dataset.loc[dataset.SalePrice > 0].copy()
        temp.loc[:, feature] = temp['YrSold'] - temp[feature]
        ## We will capture the difference between year variable and year the house was sold for
        plt.scatter(temp[feature] , temp['SalePrice'])
        plt.xlabel(feature)
        plt.ylabel('SalePrice')
        plt.show()
for col in date_features:
    if col !='YrSold':
        dataset[col] = dataset['YrSold'] -  dataset[feature]

"""
# Continous Features Handling
"""
categorical_features = [feature for feature in dataset.columns if dataset[feature].dtypes == 'O']
print(categorical_features)
# list of numerical variables
numerical_features = [feature for feature in dataset.columns if dataset[feature].dtypes != 'O']
print(numerical_features)
#descrete features
discrete_feature=[feature for feature in numerical_features if len(dataset[feature].unique())<25 and feature not in date_features]
print(discrete_feature)
#continous features
continuous_feature=[feature for feature in numerical_features if feature not in discrete_feature + date_features +['Id']]
print(continuous_feature)
for feature in continuous_feature:
    if 0 in list(dataset[feature]):
        pass
    else :
        dataset[feature] = np.log(dataset[feature])
"""
# GRAPHICAL REPRESENTATION
"""
# plot categorical variables
fcols = 3
frows = np.ceil(len(categorical_features)/fcols)
plt.figure(figsize=(15,4*frows))

for i,col in enumerate(categorical_features):
    plt.subplot(frows,fcols,i+1)
    sns.violinplot(dataset[col],dataset['SalePrice'])
# Descrete parameters
fcols = 3
frows = np.ceil(len(discrete_feature)/fcols)
plt.figure(figsize=(15,4*frows))

for i,col in enumerate(discrete_feature):
    plt.subplot(frows,fcols,i+1)
    sns.violinplot(dataset[col],dataset['SalePrice'])
# continous features
from scipy import stats
temp = dataset.loc[dataset.SalePrice > 0].copy()
fcols = 2
frows = len(continuous_feature)
plt.figure(figsize=(5*fcols,4*frows))

i=0
for col in continuous_feature:
    i+=1
    ax=plt.subplot(frows,fcols,i)
    sns.regplot(x=col, y='SalePrice', data=temp, ax=ax, 
                scatter_kws={'marker':'.','s':3,'alpha':0.3},
                line_kws={'color':'k'});
    plt.xlabel(col)
    plt.ylabel('SalePrice')
    
    i+=1
    ax=plt.subplot(frows,fcols,i)
    sns.distplot(temp[col], kde=True, kde_kws={'bw':5}, fit=stats.norm)
    plt.xlabel(col)
"""
# Categorical feature Handling
"""
dataset = pd.get_dummies(dataset)
dataset.head()
"""
# TRAIN TEST SPLIT
"""
train = dataset.loc[dataset.SalePrice > 0].copy()
test = dataset.loc[np.isnan(dataset.SalePrice)]
test.drop(columns = ["SalePrice"], inplace=True)
y = train.loc[:, "SalePrice"]
train.drop(columns = ["SalePrice"], inplace=True)
from sklearn.decomposition import PCA
pca = PCA()
pca.fit(train, y)
cumsum = np.cumsum(pca.explained_variance_ratio_)*100
d = [n for n in range(len(cumsum))]
plt.figure()
plt.plot(d,cumsum, color = 'red',label='cumulative explained variance')
plt.title('Cumulative Explained Variance as a Function of the Number of Components')
plt.ylabel('Cumulative Explained variance')
plt.xlabel('Principal components')
plt.axhline(y = 95, color='k', linestyle='--', label = '95% Explained Variance')
plt.legend(loc='best')
#pca = PCA(.95, random_state=42)
#train = pca.fit_transform(train)
#test = pca.transform(test)
"""
<h2> NORMALIZATION<h2>
"""
from sklearn import preprocessing
normalizer = preprocessing.MinMaxScaler()
X_train_norm = normalizer.fit_transform(train)
X_test_norm = normalizer.transform(test)
from sklearn.model_selection import train_test_split
X_train, X_valid, y_train, y_valid = train_test_split(X_train_norm, y, test_size=0.2, random_state=42)
"""
# MODELS
"""
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_log_error
from sklearn import svm
"""
1. **LinearRegression**
"""
l_reg = LinearRegression().fit(X_train, y_train)
l_pred = l_reg.predict(X_valid)
print(np.sqrt(mean_squared_log_error(y_valid, l_pred)))
"""
2. **SVM**
"""
# Fit regression model
svr_rbf = svm.SVR(kernel='rbf', C=1000, gamma=1e-5, epsilon=.0001)
svr_rbf_pred = svr_rbf.fit(X_train, y_train).predict(X_valid)
print(np.sqrt(mean_squared_log_error(y_valid, svr_rbf_pred)))
svr_lin = svm.SVR(kernel='linear', C=100, gamma='auto', verbose=True)
svr_lin_pred = svr_lin.fit(X_train, y_train).predict(X_valid)
print(np.sqrt(mean_squared_log_error(y_valid, svr_lin_pred)))
svr_poly = svm.SVR(kernel='poly', C=100, gamma='auto', degree=2.5, epsilon=.001, coef0=3,  verbose=True)
svr_poly_pred = svr_poly.fit(X_train, y_train).predict(X_valid)
print(np.sqrt(mean_squared_log_error(y_valid, svr_poly_pred)))
l_svm = svm.SVR().fit(X_train, y_train)
l_svm_pred = l_svm.predict(X_valid)
print(np.sqrt(mean_squared_log_error(y_valid, l_svm_pred)))
"""
3. **Lasso**
"""
from sklearn import linear_model
lasso_mdl = linear_model.Lasso(alpha=1e-8, random_state=42, max_iter=500, tol=1e-10 )
lasso_mdl_pred = lasso_mdl.fit(X_train, y_train).predict(X_valid)
print(np.sqrt(mean_squared_log_error(y_valid, lasso_mdl_pred)))
"""
**CHOOSING THE BEST MODEL**
"""
"""
1. svm.SVR() --> 0.01169431908847552
2. svm.SVR(kernel='poly', C=100, gamma='auto', degree=3, epsilon=.1, coef0=1)  --> 0.009679333216715639
3. svm.SVR(kernel='linear', C=100, gamma='auto') --> 0.01021784718990282
4. l_reg  --> 3.2409014518222863
5. svm.SVR(kernel='rbf', C=100, gamma=0.1, epsilon=.1) --> 0.013872325368680405
"""
test_pred = svr_poly.predict(X_test_norm)
test_pred = pd.DataFrame({"Id":list(test_data.index), "SalePrice":  np.exp(test_pred) })
test_pred.to_csv("submit_2.csv", index=False)