# 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)

# 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 20GB 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
"""
# Understanding the data
"""
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
fish=pd.read_csv("/kaggle/input/fish-market/Fish.csv")
fish.head(5)
fish.info()
fish.describe()
round(fish.isnull().sum()/len(fish),2)
fish.drop_duplicates(inplace=True)
"""
# EDA
"""
plt.figure(figsize=(20,15))
sns.pairplot(fish)
plt.show()
plt.figure(figsize=(20,15))
plt.subplot(1,2,1)
sns.boxplot(x='Species',y='Weight',data=fish)
plt.figure(figsize=(20,15))
sns.heatmap(fish.corr())
plt.show()
"""
### Creating Dummy Variables
"""
Species=pd.get_dummies(fish['Species'],drop_first=True)
fish=pd.concat([fish,Species],axis=1)
fish.drop(['Species'],axis=1,inplace=True)
fish.head(5)
"""
# train test split and feature scaling
"""
from sklearn.model_selection import train_test_split
np.random.seed(0)
df_train,df_test=train_test_split(fish,test_size=0.2,random_state=42)
df_train.shape
df_test.shape
from sklearn.preprocessing import MinMaxScaler
scaler=MinMaxScaler()
num_vars=['Weight','Length1','Length2','Length3','Height','Width']
df_train[num_vars]=scaler.fit_transform(df_train[num_vars])
df_test[num_vars]=scaler.transform(df_test[num_vars])
plt.figure(figsize=(20,15))
sns.heatmap(df_train.corr())
plt.show()
df_train.head(5)
"""
# Feature selection and model buliding using statsmodels api
"""
y_train=df_train.pop('Weight')
X_train=df_train
from sklearn.linear_model import LinearRegression
from sklearn.feature_selection import RFE
lm=LinearRegression()
lm.fit(X_train,y_train)
rfe=RFE(lm,7)
rfe.fit(X_train,y_train)
list(zip(X_train.columns,rfe.support_,rfe.ranking_))
col=X_train.columns[rfe.support_]
col
X_train_rfe=X_train[col]
import statsmodels.api as sm
X_train_sm1=sm.add_constant(X_train_rfe)
lm1=sm.OLS(y_train,X_train_sm1).fit()
print(lm1.summary())
# Calculate the VIFs for the model
from statsmodels.stats.outliers_influence import variance_inflation_factor

vif = pd.DataFrame()
X = X_train_rfe
vif['Features'] = X.columns
vif['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
vif['VIF'] = round(vif['VIF'], 2)
vif = vif.sort_values(by = "VIF", ascending = False)
vif
X_train_new = X_train_rfe.drop(["Length3"], axis = 1)
X_train_sm2 = sm.add_constant(X_train_new)

# Create a first fitted model
lr2 = sm.OLS(y_train, X_train_sm2).fit()
print(lr2.summary())
X_train_new = X_train_new.drop(["Height"], axis = 1)
X_train_sm3 = sm.add_constant(X_train_new)

# Create a first fitted model
lr3 = sm.OLS(y_train, X_train_sm3).fit()
print(lr3.summary())
X_train_new = X_train_new.drop(["Length1"], axis = 1)
X_train_sm4 = sm.add_constant(X_train_new)

# Create a first fitted model
lr4 = sm.OLS(y_train, X_train_sm4).fit()
print(lr4.summary())
# Calculate the VIFs for the final model
from statsmodels.stats.outliers_influence import variance_inflation_factor

vif = pd.DataFrame()
X = X_train_new
vif['Features'] = X.columns
vif['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
vif['VIF'] = round(vif['VIF'], 2)
vif = vif.sort_values(by = "VIF", ascending = False)
vif
"""
### Observations
- This model looks good, as there are VERY LOW Multicollinearity between the predictors and the p-values for all the predictors seems to be significant. For now, we will consider this as our final model (unless the Test data metrics are not significantly close to this number).
"""
"""
# Checking Assumptions
"""
"""
1.Error terms are normally distributed with mean zero (not X, Y)
"""
y_train_pred=lr4.predict(X_train_sm4)
res = y_train-y_train_pred
# Plot the histogram of the error terms
fig = plt.figure()
sns.distplot((res), bins = 20)
fig.suptitle('Error Terms', fontsize = 20)                  # Plot heading 
plt.xlabel('Errors', fontsize = 18) ;
"""
From the above histogram, we could see that the Residuals are normally distributed. Hence our assumption for our model is valid.
"""
"""
# Making prediction on test data set
"""
y_test=df_test.pop('Weight')
X_test=df_test
X_test_new=sm.add_constant(X_test)
#Selecting the variables that were part of final model.
col1=X_train_new.columns
X_test=X_test[col1]
# Adding constant variable to test dataframe
X_test_lm4 = sm.add_constant(X_test)
X_test_lm4.info()
y_test_pred=lr4.predict(X_test_lm4)
"""
# Model Evaluation
"""
from sklearn.metrics import r2_score
r2_score(y_train,y_train_pred)
from sklearn.metrics import r2_score
r2_score(y_test,y_test_pred)
"""
we have got a better accuracy around 94% on test data set.
"""
"""
## Conclusion

- If you have any suggestions or suggestions, please write to me. I wil be happy to help.

- Thank you for your suggestion and votes ;)
"""