# Ignore the warnings
import warnings
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
# data visualisation and manipulation
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
from matplotlib.legend_handler import HandlerBase
import seaborn as sns
#configure
# sets matplotlib to inline and displays graphs below the corressponding cell.
%matplotlib inline
style.use('fivethirtyeight')
sns.set(style='whitegrid',color_codes=True)
#model selection
from sklearn.model_selection import train_test_split, KFold
from sklearn.preprocessing import MinMaxScaler, StandardScaler
#encoding
from sklearn.preprocessing import LabelEncoder
#Statistical
from scipy import stats
from scipy.stats import norm, skew
TRAIN_DATA_PATH = 'dataset\\train.csv'
TEST_DATA_PATH = 'dataset\\test.csv'
EXPORTED_TRAIN_DATA_PATH = 'dataset\\preprocessed_train.v3.csv'
EXPORTED_TEST_DATA_PATH = 'dataset\\preprocessed_test.v3.csv'
## reading the training and testing data
train = pd.read_csv(TRAIN_DATA_PATH)
test = pd.read_csv(TEST_DATA_PATH)
print(train.shape)
print(test.shape)
df=train.copy()
#df.head(10)
df.shape
## Keeping the id column
## as they need to exported with the data after preprocessing
train_id = train['Id']
test_id = test['Id']
## Dropping the 'Id' columns as the DataFrames are already indexed.
df.drop(['Id'],axis=1,inplace=True)
test.drop(['Id'],axis=1,inplace=True)
df.head()
df.isnull().sum().sort_values(ascending = False)[:20]
cat_df = df.select_dtypes(include=[np.object])
cat_df.head(10)
cat_df.shape
cat_df.columns
# list of the categorical columns.
num_df=df.select_dtypes(include=[np.number])
num_df.shape
num_df.columns
nan_df=df.loc[:, df.isnull().any()]
nan_df.columns
all_data = pd.concat([train,test])
print(all_data.shape)
all_data = all_data.reset_index(drop=True)
all_data.head(10)
# Dropping the SalePrice column from the merged dataframe
all_data.drop(['SalePrice'],axis=1,inplace=True)
all_data.shape
## analyzing the target variable ie 'Saleprice'
## This analysis gives a overall view of the data distribution
sns.distplot(a=df['SalePrice'],color='#ff4125',axlabel=False).set_title('Sale Price')
## Get also the qq-plot (the quantile-quantile plot)
## The quantile-quantile (q-q) plot is a graphical technique
## for determining if two data sets come from populations with a common distribution.
fig = plt.figure()
res = stats.probplot(train['SalePrice'], plot=plt)
plt.show()
Skewness: The skewness is greater than 1(positively skewed), so the data are highly skewed.
Kurtosis: Distribution is longer, tails are fatter. Peak is higher and sharper (Kurtosis > 3), which means that data are heavy-tailed or profusion of outliers.
Skewness: It is the degree of distortion from the symmetrical bell curve or the normal distribution. It measures the lack of symmetry in data distribution. It differentiates extreme values in one versus the other tail. A symmetrical distribution will have a skewness of 0.
Kurtosis: Kurtosis is all about the tails of the distribution — not the peakedness or flatness. It is used to describe the extreme values in one versus the other tail. It is actually the measure of outliers present in the distribution.
Reference :
[1] https://codeburst.io/2-important-statistics-terms-you-need-to-know-in-data-science-skewness-and-kurtosis-388fef94eeaa
[2] https://www.itl.nist.gov/div898/handbook/eda/section3/eda33o.htm
df['SalePrice']=np.log1p(df['SalePrice'])
# now gain see the distribution.
sns.distplot(a=df['SalePrice'],color='#ff4125',axlabel=False).set_title('log(1+SalePrice)')
## Understanding the correlation here.
## Before taking any decision the correlation needs to be understood
## which value effect the target the most needs to be known
cor_mat= df[:].corr()
cor_with_tar=cor_mat.sort_values(['SalePrice'],ascending=False)
print("The most relevant features (numeric) for the target are :")
cor_with_tar.SalePrice
It can be seen the some of the features have really high corelation with the target. These features are really significant.
Of these, the features with corelation value > 0.5 are really significant. Some features like GrLivArea etc.. are even more important.
We will consider these features (i.e. GrLivArea,OverallQual) etc. in more detail in subsequent sections for preprocessing.
## using a corelation map to visualize features with high corelation.
## The columns were selected based on the correlation values
## corelation matrix.
cor_mat= df[['OverallQual','GrLivArea','GarageCars','GarageArea','TotalBsmtSF','1stFlrSF','FullBath',
'YearBuilt','YearRemodAdd','GarageYrBlt','TotRmsAbvGrd','SalePrice']].corr()
mask = np.array(cor_mat)
mask[np.tril_indices_from(mask)] = False
fig=plt.gcf()
fig.set_size_inches(30,12)
sns.heatmap(data=cor_mat,mask=mask,square=True,annot=True,cbar=True)
# some inference section.
In this section I have performed the univariate analysis. Particularly on those features which have very high correlation with the the Target variable as these are quite important.
For the numeric features I have used a 'distplot' and 'boxplot' to analyze the distribution. Similarly for categorical features the most reasonable way to visualize the distribution is to use a 'countplot' which shows the counts for each category or class.
def plot_num(feature):
fig,axes=plt.subplots(1,2)
sns.boxplot(data=df,x=feature,ax=axes[0])
sns.distplot(a=df[feature],ax=axes[1],color='#ff4125')
fig.set_size_inches(15,5)
plot_num('GrLivArea')
plot_num('GarageArea')
plot_num('TotalBsmtSF')
plot_num('1stFlrSF')
Reference: http://onlinestatbook.com/mobile/transformations/box-cox.html
def plot_cat(feature):
plt.figure(figsize=(15,5))
sns.countplot(data=df,x=feature)
ax=sns.countplot(data=df,x=feature)
plot_cat('OverallQual')
plot_cat('FullBath')
plot_cat('YearBuilt')
plot_cat('TotRmsAbvGrd')
# most of the houses have 5-7 rooms above the grd floor.
plot_cat('GarageCars')
sns.factorplot(data=df,x='Neighborhood',kind='count',size=10,aspect=2.5)
fig, ax = plt.subplots()
ax.scatter(x = df['GrLivArea'], y = df['SalePrice'])
plt.ylabel('SalePrice')
plt.xlabel('GrLivArea')
plt.show()
df = df.drop(df[(df['GrLivArea']>4000) & (df['SalePrice']<13)].index)
# removing some outliers on lower right side.
# again checking
fig, ax = plt.subplots()
ax.scatter(x = df['GrLivArea'], y = df['SalePrice'])
plt.ylabel('SalePrice')
plt.xlabel('GrLivArea')
plt.show()
# garage area
fig, ax = plt.subplots()
ax.scatter(x =(df['GarageArea']), y = df['SalePrice'])
plt.ylabel('SalePrice')
plt.xlabel('GarageArea')
plt.show()
# can try to remove the points with gargae area > than 1200.
# basment area
fig, ax = plt.subplots()
ax.scatter(x =(df['TotalBsmtSF']), y = df['SalePrice'])
plt.ylabel('SalePrice')
plt.xlabel('TotalBsmtSF')
plt.show()
# can try to remove the points with basementarea > than 3000.
# 1st floor area
fig, ax = plt.subplots()
ax.scatter(x =(df['1stFlrSF']), y = df['SalePrice'])
plt.ylabel('SalePrice')
plt.xlabel('1stFlrSF')
plt.show()
# can try to remove the points with 1st floor area > than 2600.
#overall qual
sns.factorplot(data=df,x='OverallQual',y='SalePrice',kind='box',size=5,aspect=2.5)
#garage cars
sns.factorplot(data=df,x='GarageCars',y='SalePrice',kind='box',size=5,aspect=2.5)
#no of rooms
sns.factorplot(data=df,x='TotRmsAbvGrd',y='SalePrice',kind='bar',size=5,aspect=2.5)
#neighborhood
sns.factorplot(data=df,x='Neighborhood',y='SalePrice',kind='box',size=10,aspect=1.5)
#sale conditioin
sns.factorplot(data=df,x='SaleCondition',y='SalePrice',kind='box',size=10,aspect=2.5)
nan_all_data = (all_data.isnull().sum())
nan_all_data= nan_all_data.drop(nan_all_data[nan_all_data== 0].index).sort_values(ascending=False)
nan_all_data
miss_df = pd.DataFrame({'Missing Ratio' :nan_all_data})
miss_df
## delete features with very high number of missing values.
## imputing these values won't improve the performance
## rather it will make the decision biased
all_data.drop(['PoolQC','Alley','Fence','Id','MiscFeature'],axis=1,inplace=True)
test.drop(['PoolQC','Alley','Fence','MiscFeature'],axis=1,inplace=True)
df.drop(['PoolQC','Alley','Fence','MiscFeature'],axis=1,inplace=True)
all_data.drop(['FireplaceQu'],axis=1,inplace=True)
test.drop(['FireplaceQu'],axis=1,inplace=True)
df.drop(['FireplaceQu'],axis=1,inplace=True)
#Lot Frontage
print(df['LotFrontage'].dtype)
plt.scatter(x=np.log1p(df['LotFrontage']),y=df['SalePrice'])
cr=df.corr()
print(df['LotFrontage'].describe())
print("The corelation of the LotFrontage with the Target : " , cr.loc['LotFrontage','SalePrice'])
all_data['LotFrontage'].fillna(np.mean(all_data['LotFrontage']),inplace=True)
all_data['LotFrontage'].isnull().sum()
all_data['GarageYrBlt'].fillna(0,inplace=True)
print(all_data['GarageYrBlt'].isnull().sum())
all_data['GarageArea'].fillna(0,inplace=True)
print(all_data['GarageArea'].isnull().sum())
all_data['GarageCars'].fillna(0,inplace=True)
print(all_data['GarageCars'].isnull().sum())
all_data['GarageQual'].fillna('None',inplace=True) # creating a separate category 'none' which means no garage.
print(all_data['GarageQual'].isnull().sum())
all_data['GarageFinish'].fillna('None',inplace=True) # creating a separate category 'none' which means no garage.
print(all_data['GarageFinish'].isnull().sum())
all_data['GarageCond'].fillna('None',inplace=True) # creating a separate category 'none' which means no garage.
print(all_data['GarageCond'].isnull().sum())
all_data['GarageType'].fillna('None',inplace=True) # creating a separate category 'none' which means no garage.
print(all_data['GarageType'].isnull().sum())
# basement related features.
#missing values are likely zero for having no basement
for col in ('BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF','TotalBsmtSF', 'BsmtFullBath', 'BsmtHalfBath'):
all_data[col].fillna(0,inplace=True)
# for categorical features we will create a separate class 'none' as before.
for col in ('BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2'):
all_data[col].fillna('None',inplace=True)
print(all_data['TotalBsmtSF'].isnull().sum())
# MasVnrArea 0 and MasVnrType 'None'.
all_data['MasVnrArea'].fillna(0,inplace=True)
print(all_data['MasVnrArea'].isnull().sum())
all_data['MasVnrType'].fillna('None',inplace=True)
print(all_data['MasVnrType'].isnull().sum())
#MSZoning.
# Here nan does not mean no so I will with the most common one ie the mode.
all_data['MSZoning'].fillna(all_data['MSZoning'].mode()[0],inplace=True)
print(all_data['MSZoning'].isnull().sum())
# utilities
sns.factorplot(data=df,kind='box',x='Utilities',y='SalePrice',size=5,aspect=2.5)
all_data.drop(['Utilities'],axis=1,inplace=True)
#functional
# fill with mode
all_data['Functional'].fillna(all_data['Functional'].mode()[0],inplace=True)
print(all_data['Functional'].isnull().sum())
# other remaining columns are all categorical, like kitchen qual etc.. and so filled with mode.
for col in ['SaleType','KitchenQual','Exterior2nd','Exterior1st','Electrical']:
all_data[col].fillna(all_data[col].mode()[0],inplace=True)
print(all_data[col].isnull().sum())
nan_all_data = (all_data.isnull().sum())
nan_all_data= nan_all_data.drop(nan_all_data[nan_all_data== 0].index).sort_values(ascending=False)
nan_all_data
miss_df = pd.DataFrame({'Missing Ratio' :nan_all_data})
miss_df
all_data.shape
Now I am handling skewness of the features. For this I will take the log transform of the features with skewness > 0.5.
BoxCox transformation can also be tried here.
Reference: http://onlinestatbook.com/mobile/transformations/box-cox.html
numeric_feats = all_data.dtypes[all_data.dtypes != "object"].index
skewed_feats = train[numeric_feats].apply(lambda x: skew(x.dropna())) #compute skewness
skewed_feats = skewed_feats[skewed_feats > 0.50]
skewed_feats = skewed_feats.index
all_data[skewed_feats] = np.log1p(all_data[skewed_feats])
for col in all_data.columns:
if(all_data[col].dtype == 'object'):
le=LabelEncoder()
all_data[col]=le.fit_transform(all_data[col])
train= all_data[: 1460]
test = all_data[1460: ]
train['SalePrice']=df['SalePrice']
train['SalePrice'].fillna(np.mean(train['SalePrice']),inplace=True)
train.shape
print(train['SalePrice'].isnull().sum())
#train['Id'] = train.index
#test['Id'] = test.index
train.reset_index(inplace = True)
test.reset_index(inplace = True)
train = pd.concat([train_id, train], axis = 1)
test = pd.concat([test_id, test], axis = 1)
train.to_csv(EXPORTED_TRAIN_DATA_PATH, index= False)
test.to_csv(EXPORTED_TEST_DATA_PATH, index= False)
In this approach Extreme Gradient Boosting (XGBoost) regression algorithm and Lasso were used. Using Grid Search best parameters were tried to find out and with those parameters the regressors were trained and made prediction which was later submitted to kaggle.
# Ignore the warnings
import warnings
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
# data visualisation and manipulation
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
from matplotlib.legend_handler import HandlerBase
import seaborn as sns
#configure
# sets matplotlib to inline and displays graphs below the corressponding cell.
%matplotlib inline
style.use('fivethirtyeight')
sns.set(style='whitegrid',color_codes=True)
#import the necessary modelling algorithms from scikit-learn.
#regression
from sklearn.linear_model import LinearRegression, Lasso, BayesianRidge
from sklearn.svm import SVR
from xgboost import XGBRegressor as XGBR
#model selection
from sklearn.model_selection import train_test_split, GridSearchCV
#evaluation metrics for regression
from sklearn.metrics import mean_squared_log_error,mean_squared_error, r2_score,mean_absolute_error
TRAIN_DATA_PATH = 'dataset\\preprocessed_train.v3.csv'
TEST_DATA_PATH = 'dataset\\preprocessed_test.v3.csv'
## reading the training dataset here
## only the training dataset from kaggle will be used here for training & evaluation purpose
dataset = pd.read_csv(TRAIN_DATA_PATH)
label = dataset['SalePrice']
dataset.drop(['SalePrice'], axis = 1, inplace= True)
train_data, test_data , train_label, test_label = train_test_split(dataset, label, test_size = 0.2)
Principal component analysis (36 Components)
Reference:
## using standard scaler to normalize the training data
#Scaler = StandardScaler()
Scaler = MinMaxScaler()
## using principal component analysis to reduce the dimensionality of the features
## principal componenets taken 36
pca = PCA(n_components=36)
train_data = Scaler.fit_transform(train_data)
test_data = Scaler.transform(test_data)
train_data = pca.fit_transform(train_data)
test_data = pca.transform(test_data)
train_data.shape
def rmse(predictions, labels):
return np.sqrt(mean_squared_error(predictions,labels))
## Creating a dictionary of models.
## These models are referenced with their default parameters
## and checking how do they perform with their default parameters
## this gives a better understanding of parameter tuning
models = {
'XGBRegressor': XGBR(),
'LinearRegressor': LinearRegression(),
'NaiveBayes': BayesianRidge(),
'SVM': SVR(),
'Lasso': Lasso(),
}
## using the dictionary of models
## to predict data
## and saving the calculation in a dataframe
## for visualization
def predict_models(models, train_data, train_label, test_data, test_label):
row = 0
results = pd.DataFrame()
for name, model in models.items():
model.fit(train_data, train_label)
score = model.score(train_data, train_label)
predictions = model.predict(test_data)
results.loc[row, 'Model'] = name
results.loc[row, 'Score'] = score
results.loc[row, 'Log-RMSE'] = rmse(predictions, test_label)
results.loc[row, 'RMSE'] = rmse(np.expm1(predictions), np.expm1(test_label))
row += 1
return results
predict_models(models, train_data, train_label, test_data, test_label)
xgb1 = XGBR()
parameters = {
'objective':['reg:linear'],
'learning_rate': [.03, 0.05, .07],
'max_depth': [2, 3, 5, 6, 7],
'min_child_weight': [4],
'silent': [1],
'subsample': [i/10.0 for i in range(4,9)],
'colsample_bytree': [i/10.0 for i in range(4,9)],
'n_estimators': [500],
'gamma':[i/10.0 for i in range(3,6)],}
xgb_grid = GridSearchCV(xgb1,
parameters,
cv = 2,
n_jobs = 5,
verbose=True)
xgb_grid.fit(train_data, train_label)
prediction = xgb_grid.predict(test_data)
## Rmse score with best parameters
print('RMSE Score: ')
print(rmse(prediction, test_label))
## best score achieved in GridSearch
print('Best Score: ')
print(xgb_grid.best_score_)
## best parameters found by gridsearch
print('Best Parameters: ')
print(xgb_grid.best_params_)
params_dict = {
'alpha':[0.001, 0.005, 0.01,0.05,0.1,0.5,1]
}
reg_lasso_CV = GridSearchCV(estimator=Lasso(),
param_grid=params_dict,
scoring='neg_mean_squared_error',
cv=10)
reg_lasso_CV.fit(train_data,train_label)
prediction = reg_lasso_CV.predict(test_data)
print('RMSE Score: ')
print(rmse(prediction, test_label))
print('Best Score: ')
print(reg_lasso_CV.best_score_)
print('Best Parameters: ')
print(reg_lasso_CV.best_params_)
kfold = KFold(n_splits = 10, shuffle=True)
kfold_auc = list()
for train_index, test_index in kfold.split(dataset):
X_train, y_train = dataset.iloc[train_index], label.iloc[train_index]
X_test, y_test = dataset.iloc[test_index], label.iloc[test_index]
StdScaler = MinMaxScaler()
X_train = StdScaler.fit_transform(X_train)
X_test = StdScaler.transform(X_test)
model = XGBR(
colsample_bytree=0.4603,
gamma=0.0468,
learning_rate=0.05,
max_depth=3,
min_child_weight=1.7817,
n_estimators=2200,
reg_alpha=0.4640,
reg_lambda=0.8571,
subsample=0.5213,
silent=1,
random_state =7,
nthread = -1
)
#model = LinearRegression()
model.fit(X_train, y_train)
predict = model.predict(X_test)
kfold_auc.append(mean_squared_error(predict, y_test))
print(np.mean(kfold_auc))
original_train = pd.read_csv(TRAIN_DATA_PATH)
original_test = pd.read_csv(TEST_DATA_PATH)
original_label = original_train['SalePrice']
test_ID = original_test['Id']
StdScaler = StandardScaler()
#StdScaler = MinMaxScaler()
pca = PCA(n_components=36)
original_train = StdScaler.fit_transform(original_train)
original_test = StdScaler.transform(original_test)
original_train = pca.fit_transform(original_train)
original_test = pca.transform(original_test)
predict_models(models, original_train, original_label, original_train, original_label)
model = XGBR(
colsample_bytree=0.4603,
gamma=0.0468,
learning_rate=0.05,
max_depth=3,
min_child_weight=1.7817,
n_estimators=2200,
reg_alpha=0.4640,
reg_lambda=0.8571,
subsample=0.5213,
silent=1,
random_state =7,
nthread = -1
),
model.fit(original_train, original_label)
predict = model.predict(original_test)
submission = pd.DataFrame()
submission['Id'] = test_ID
submission['SalePrice'] = np.expm1(predict)
submission.to_csv('submission_xgb.csv' , index=False)
# Ignore the warnings
import warnings
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import tensorflow as tf
from sklearn import metrics
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.model_selection import train_test_split, KFold
# This is the default path for the dataset
TRAIN_DATA_PATH = 'dataset\\preprocessed_train.v3.csv'
TEST_DATA_PATH = 'dataset\\preprocessed_test.v3.csv'
## Reading the dataset here.
## There are two parts in the dataset.
## Training data is used to see how the model performs.
## Training data is splitted into 80% - 20%.
## For performance evaluation.
dataset = pd.read_csv(TRAIN_DATA_PATH)
test_dataset = pd.read_csv(TEST_DATA_PATH)
dataset = pd.get_dummies(dataset)
test_dataset = pd.get_dummies(test_dataset)
## Keeping the test_id for kaggle submission and then dropping it as it's not necessary in the dataset.
test_id = test_dataset['Id']
test_dataset.drop('Id' , axis = 1, inplace=True)
## Saleprice is the target value for the dataset. SalePrice is already log transformed in the preprocessing step.
Y = dataset['SalePrice']
## As the target values are saved, now we can drop it from the data
## Also the Id column as it's not necessary
dataset.drop(['Id', 'SalePrice'], axis = 1, inplace= True)
## Splitting the training dataset into 80-20 split
## Original test isn't used here. The training data provided by kaggle has been used
## The preprocessed training data will help us to evaluate the performance before feeding the original test data into it
#X_train, X_test , Y_train, Y_test = train_test_split(dataset, Y, test_size = 0.2)
## Normalizing the features before putting it into the neural network
## StandardScaler will normalize the features (each column of X)
## so that each column/feature/variable would have mean = 0 and standard deviation = 1.
#Scaler = MinMaxScaler()
#Scaler = StandardScaler()
#X_train = Scaler.fit_transform(X_train)
#X_test = Scaler.transform(X_test)
class Sequential_Model:
def __init__(self):
self.__current_layer = -1
self.__weights = list()
self.__biases = list()
self.__dropout = list()
self.__l2_regularizer = list()
self.__activation = list()
self.__training_cost = list()
self.__validation_cost = list()
self.__regularize = 0
self.__session = tf.Session()
def __del__(self):
self.__session.close()
def Add_Dense_layer(self, input_shape, output_shape, activation_function = 'leaky_relu', dropout_rate = 0.0):
"""
params:
input shape - dense layer's input shape
output shape - dense layer's output shape
activation_function - activation function for the layer (Default: leaky_relu)
dropout_rate - dropout rate of the layer (default 0.0 means no dropout)
"""
self.__current_layer = self.__current_layer + 1
self.__weights.append(tf.Variable(tf.random.truncated_normal([input_shape, output_shape], 0.1)))
self.__biases.append(tf.Variable(tf.ones([output_shape])))
self.__activation.append((self.__current_layer, activation_function))
self.__dropout.append((self.__current_layer , dropout_rate))
def Add_L2_Regularize(self, beta = 0.013):
"""
params:
beta - Beta value for L2 regularizer (Default 0.01)
"""
self.__l2_regularizer.append((self.__current_layer, beta))
def __rmse(self, predictions , label):
return tf.losses.mean_squared_error(predictions, label)
def __plot(self):
plt.plot(self.__training_cost)
plt.plot(self.__validation_cost)
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'validation'], loc='upper right')
plt.show()
def __train(self, train_data, train_label, validation_data, validation_label, epochs, batch_size, plot):
self.__x_train = tf.placeholder(tf.float32)
self.__y_train = tf.placeholder(tf.float32)
## Calculating for the first layer
self.__output = tf.add(tf.matmul(self.__x_train, self.__weights[0]) , self.__biases[0])
## Checking the activation function
## If no activation function found then
## Exception thrown
if self.__activation[0][1] == 'relu':
self.__output = tf.nn.relu(self.__output)
elif self.__activation[0][1] == 'leaky_relu':
self.__output = tf.nn.leaky_relu(self.__output)
elif self.__activation[0][1] == 'tanh':
self.__output = tf.nn.tanh(self.__output)
elif self.__activation[0][1] == 'sigmoid':
self.__output = tf.nn.sigmoid(self.__output)
else:
raise ValueError("Activation Function doesn't exist.")
## Checking for dropout.
## If any dropout rate is given rather than 0.0 then it's applied
## On the layer
if self.__dropout[0][1] != 0.0 :
self.__output = tf.layers.dropout(self.__output, self.__dropout[0][1])
## Using a loop to calculate the remaining layers
## With this loop calculations are done dynamically
## rather than doing it manually
## Because of this approach the model trains slower(!)
for i in range(1, self.__current_layer + 1):
## Multiplying weights with the previous output and adding the bias
self.__output = tf.add(tf.matmul(self.__output, self.__weights[i]) , self.__biases[i])
## Passing through an activation function as given
## while adding the layer.
if self.__activation[i][1] == 'relu':
self.__output = tf.nn.relu(self.__output)
elif self.__activation[0][1] == 'leaky_relu':
self.__output = tf.nn.leaky_relu(self.__output)
elif self.__activation[0][1] == 'tanh':
self.__output = tf.nn.tanh(self.__output)
elif self.__activation[0][1] == 'sigmoid':
self.__output = tf.nn.sigmoid(self.__output)
else:
raise ValueError("Activation Function doesn't exist.")
## Applying the dropout if any given
if self.__dropout[i][1] != 0.0 :
self.__output = tf.layers.dropout(self.__output, self.__dropout[i][1])
#for r in self.__l2_regularizer:
## L2 regularizing the weights and multiplying them with corresponding beta value
## then taking the sum of all the layers
#self.__regularize += (tf.nn.l2_loss(self.__weights[r[0]]) * r[1])
## Calculating the Root mean squared error
## for demonstration purpose I have kep only one function
## other type of functions can be added as per necessary
if self.__loss == 'rmse':
loss = self.__rmse(self.__output , self.__y_train)
else:
raise ValueError("Loss function doesn't exist.")
if self.__regularize is not None:
loss = tf.reduce_mean(loss + self.__regularize)
## Only two optimizers are demonstrated here
## Other optimizers can also be added.
if self.__optimizer == 'adam':
optimizer = tf.train.AdamOptimizer(learning_rate=self.__learning_rate).minimize(loss)
elif self.__optimizer == 'rmsprop':
optimizer = tf.train.RMSPropOptimizer(learning_rate=self.__learning_rate).minimize(loss)
else:
raise ValueError("Optimizer doesn't exist.")
## Initializing all the variables
init = tf.global_variables_initializer()
self.__session.run(init)
## Training the model for given number of epochs
for epoch in range(epochs+1):
avg_train_cost = 0.0
## dividing into batches as per user declared size
total_num_batch = train_data.shape[0]//batch_size
## collecting the data as per batches and feeding it to the model
for index, offset in enumerate(range(0, train_data.shape[0], batch_size)):
## xs denotes the training data batch and ys denotes the training label batch
xs, ys = train_data[offset: offset + batch_size], train_label[offset: offset + batch_size]
## running the optimizer and loss with the batch collected above.
_, cost = self.__session.run([optimizer, loss], feed_dict = {self.__x_train: xs, self.__y_train: np.reshape( ys, (-1, 1))})
## taking the average for the epoch for all batches under the epoch
avg_train_cost += (cost / total_num_batch)
## Checking the validation loss here
validation_cost = self.__session.run( self.__rmse(self.__output, self.__y_train),
feed_dict={self.__x_train: validation_data, self.__y_train: np.reshape(validation_label, (-1, 1))})
## Saving these costs for plotting
self.__training_cost.append(avg_train_cost)
self.__validation_cost.append(validation_cost)
#if epoch % 20 == 0:
print('Epoch -', (epoch), '||| Training loss: ', '{:.5f}'.format(avg_train_cost),
'||| Validation loss: ', '{:.5f}'.format(validation_cost))
if plot:
## plotting the loss values
self.__plot()
def compile(self, loss='rmse', optimizer='adam', learning_rate = 0.01):
"""
params:
loss: loss function default 'Rmse'
optimizer: default optimizer adam
learning_rate: default 0.01
"""
## taking the necessary inputs for the model to run
## these are the final inputs before the model starts training
self.__loss = loss
self.__optimizer = optimizer
self.__learning_rate = learning_rate
def fit(self, train_data, train_label, epochs = 100, batch_size = 24, plot = True, validation_data = (None, None), validation_size = 0.1):
"""
params:
train_data
train_label
epochs - default 100
batch_size - default 24
plot - default True : plots the loss of validation and training loss
validation data: default None. If no data given then a portion is created.
validation_size: default 0.1 (10%)
"""
## Checking if there is any validation data given
## If no validation data given then validation data is created by default size
if validation_data[0] == None or validation_data[1] == None:
train_data, validation_data, train_label, validation_label = train_test_split(train_data, train_label,
test_size = validation_size)
self.__train(train_data, train_label, validation_data, validation_label, epochs, batch_size, plot)
else:
## if validation data is given then it's directly feed to train method
self.__train(train_data, train_label, validation_data[0], validation_data[1], epochs, batch_size, plot)
def evaluate(self, test_data, test_label):
"""
param:
test_data, test_label
returns:
loss for test_data and test_label
"""
## For test data checking the models loss with known labels.
## rmse is used here as by default of my project.
testing_cost = self.__session.run( self.__rmse(self.__output , self.__y_train),
feed_dict={self.__x_train: test_data, self.__y_train: np.reshape(test_label, (-1, 1))})
print('Testing loss: ', '{:.5f}'.format(testing_cost))
def predict(self, test_data):
"""
param:
test_data - value to be predicted
returns:
predicted values
"""
## Taking the test data which the model will predict values of.
prediction = self.__session.run(self.__output, feed_dict={self.__x_train: test_data})
return prediction
def get_model():
model = Sequential_Model()
model.Add_Dense_layer(input_shape= X_train.shape[1] , output_shape=37,
activation_function='relu', dropout_rate=0.2)
## dropout rate is 0.3. It means that 30% of the neurons
## will be dropped randomly to prevent overfitting.
model.Add_L2_Regularize()
model.Add_Dense_layer(input_shape=37, output_shape=18,
activation_function='relu', dropout_rate=0.2)
model.Add_L2_Regularize()
model.Add_Dense_layer(input_shape=18, output_shape=6,
activation_function='relu', dropout_rate=0.2)
model.Add_L2_Regularize()
model.Add_Dense_layer(input_shape=6, output_shape=1,
activation_function='relu', dropout_rate=0.2)
model.compile(loss='rmse',optimizer='rmsprop',learning_rate=0.001)
return model
kfold = KFold(n_splits = 10, shuffle=True)
for train_index, test_index in kfold.split(dataset):
X_train, y_train = dataset.iloc[train_index], Y.iloc[train_index]
X_test, y_test = dataset.iloc[test_index], Y.iloc[test_index]
StdScaler = MinMaxScaler()
X_train = StdScaler.fit_transform(X_train)
X_test = StdScaler.transform(X_test)
model = get_model()
model.fit(train_data=X_train, train_label=y_train, epochs=25, batch_size=12)
model.evaluate(X_test, y_test)
## Reading the dataset here.
## There are two parts in the dataset.
## Training data is used to see how the model performs.
## Training data is splitted into 80% - 20%.
## For performance evaluation.
dataset = pd.read_csv(TRAIN_DATA_PATH)
test_dataset = pd.read_csv(TEST_DATA_PATH)
## Keeping the test_id for kaggle submission and then dropping it as it's not necessary in the dataset.
test_id = test_dataset['Id']
test_dataset.drop('Id' , axis = 1, inplace=True)
## Saleprice is the target value for the dataset. SalePrice is already log transformed in the preprocessing step.
Y = dataset['SalePrice']
## As the target values are saved, now we can drop it from the data
## Also the Id column as it's not necessary
dataset.drop(['Id', 'SalePrice'], axis = 1, inplace= True)
## Normalizing the features before putting it into the neural network
## StandardScaler will normalize the features (each column of X)
## so that each column/feature/variable would have mean = 0 and standard deviation = 1.
Scaler = StandardScaler()
X_train = Scaler.fit_transform(X_train)
X_test = Scaler.transform(test_dataset)
predicted = model.predict(X_test)
Throughout this approach the main target was to utilize the object oriented approach to make the model creation dynamic. Further changes can be made to make the model creation more robust. My main target was to make the model in a Keras style model creating system.
| Layer | Type | Shape |
|---|---|---|
| Layer_1 | Input | ( 74 , 37 ) |
| Activation_1 | Relu | Layer_1 |
| Dropout_1 | Rate - 0.2 | Layer_1 |
| L2_Regularization_1 | Beta - 0.013 | Layer_1 |
| Layer_2 | Dense | ( 37 , 18 ) |
| Activation_2 | Relu | Layer_2 |
| Dropout_2 | Rate - 0.2 | Layer_2 |
| L2_Regularization_2 | Beta - 0.013 | Layer_2 |
| Layer_3 | Dense | ( 18 , 6 ) |
| Activation_3 | Relu | Layer_3 |
| Dropout_1 | Rate - 0.2 | Layer_1 |
| L2_Regularization_3 | Beta - 0.013 | Layer_3 |
| Layer_4 | Output | ( 6 , 1 ) |
| Activation_4 | Relu | Layer_4 |
#### Dropout:
#### L2 Regularization (Beta):
* Comparing the above curves, It can be said that adding dropout and regularization improved the generalization of the model.
#### Activation Function:
#### Optimizers:
#### Epochs:
#### Batch Size:
submission = pd.DataFrame()
submission['Id'] = test_id
submission['SalePrice'] = np.expm1(predicted)
submission.to_csv('DNN_Optimal.csv', index=False)
# Ignore the warnings
import warnings
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
import numpy as np
import pandas as pd
import datetime
from sklearn.cross_validation import KFold
from sklearn.cross_validation import train_test_split
import time
from sklearn import preprocessing
from xgboost import XGBRegressor
from sklearn.ensemble import RandomForestRegressor, ExtraTreesRegressor, GradientBoostingRegressor
from sklearn.grid_search import GridSearchCV
from sklearn.cross_validation import ShuffleSplit
from sklearn.metrics import make_scorer, mean_squared_error
from sklearn.linear_model import Ridge, LassoCV,LassoLarsCV, ElasticNet
from sklearn.kernel_ridge import KernelRidge
from sklearn.neighbors import KNeighborsRegressor
from sklearn.preprocessing import StandardScaler, MinMaxScaler
TRAIN_DATA_PATH = 'dataset\\preprocessed_train.v3.csv'
TEST_DATA_PATH = 'dataset\\preprocessed_test.v3.csv'
def create_submission(prediction,score):
now = datetime.datetime.now()
sub_file = 'submission_'+str(score)+'_'+'.csv'
print ('Creating submission: ', sub_file)
pd.DataFrame({'Id': test['Id'].values, 'SalePrice': prediction}).to_csv(sub_file, index=False)
def mean_squared_error_(ground_truth, predictions):
return mean_squared_error(ground_truth, predictions) ** 0.5
RMSE = make_scorer(mean_squared_error_, greater_is_better=False)
class ensemble(object):
def __init__(self, n_folds, stacker, base_models):
self.n_folds = n_folds
self.stacker = stacker
self.base_models = base_models
def fit_predict(self,train,test,ytr):
X = train.values
y = ytr.values
T = test.values
folds = list(KFold(len(y), n_folds = self.n_folds, shuffle = True, random_state = 0))
S_train = np.zeros((X.shape[0],len(self.base_models)))
S_test = np.zeros((T.shape[0],len(self.base_models))) # X need to be T when do test prediction
for i,reg in enumerate(base_models):
print ("Fitting the base model...")
S_test_i = np.zeros((T.shape[0],len(folds))) # X need to be T when do test prediction
for j, (train_idx,test_idx) in enumerate(folds):
X_train = X[train_idx]
y_train = y[train_idx]
X_holdout = X[test_idx]
reg.fit(X_train,y_train)
y_pred = reg.predict(X_holdout)[:]
S_train[test_idx,i] = y_pred
S_test_i[:,j] = reg.predict(T)[:]
# S_test_i[:,j] = reg.predict(X)[:]
S_test[:,i] = S_test_i.mean(1)
print ("Stacking base models...")
param_grid = {
'alpha': [1e-3,5e-3,1e-2,5e-2,1e-1,0.2,0.3,0.4,0.5,0.8,1e0,3,5,7,1e1,2e1,5e1],
}
grid = GridSearchCV(estimator=self.stacker, param_grid=param_grid, n_jobs=1, cv=5, scoring=RMSE)
grid.fit(S_train, y)
try:
print('Param grid:')
print(param_grid)
print('Best Params:')
print(grid.best_params_)
print('Best CV Score:')
print(-grid.best_score_)
print('Best estimator:')
print(grid.best_estimator_)
print(message)
except:
pass
y_pred = grid.predict(S_test)[:]
return y_pred, -grid.best_score_
base_models = [
RandomForestRegressor(
n_jobs=1, random_state=0,
n_estimators=500, max_features=18, max_depth=11
),
ExtraTreesRegressor(
n_jobs=1, random_state=0,
n_estimators=500, max_features=20
),
GradientBoostingRegressor(
random_state=0,
n_estimators=500, max_features=10, max_depth=6,
learning_rate=0.05, subsample=0.8
),
XGBRegressor(
seed=0,
n_estimators=500, max_depth=7,
learning_rate=0.05, subsample=0.8, colsample_bytree=0.75
),
]
ensemebler = ensemble(
n_folds=5,
stacker=Ridge(),
base_models=base_models
)
dataset = pd.read_csv(TRAIN_DATA_PATH)
label = dataset['SalePrice']
dataset.drop(['Id', 'SalePrice'], axis = 1, inplace= True)
dataset= pd.get_dummies(dataset)
test_dataset = pd.read_csv(TEST_DATA_PATH)
test = test_dataset.copy()
test_id = test_dataset['Id']
test_dataset.drop('Id' , axis = 1, inplace=True)
test_dataset= pd.get_dummies(test_dataset)
print(dataset.shape)
print(label.shape)
print(test_dataset.shape)
set(dataset.columns) - set(test_dataset.columns)
y_pred, score = ensemebler.fit_predict(dataset,test_dataset,label)
create_submission(np.expm1(y_pred),score)
The best score achieved here was by Optimized DNN. DNN performed slightly better than the ensemble approach and very better than XGBoost. As I have tried to implement the deep neural network from scratch in a object oriented style, the models complexity arised. This can be improved further, making the model more robust. Adding dynamic regularizers will also improve the score of the model.