<jupyter_start><jupyter_text>Introduction ![airbnb.png](attachment:airbnb.png) We will be developing different machine learning models to predict prices of Boston Airbnb rentals and then do a comparison between them. ![boston.jpg](attachment:boston.jpg)  Business Understanding1. Comparison of price prediction model on Boston Airbnb dataset.<jupyter_code>%matplotlib inline
import pandas as pd
import numpy as np
import seaborn as sns
import plotly.graph_objects as go
from plotly.offline import init_notebook_mode, iplot
import matplotlib.pyplot as plt

import warnings
warnings.filterwarnings("ignore")

from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score,mean_squared_error
from sklearn.neighbors import KNeighborsRegressor
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Lasso,LassoCV
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import Ridge, RidgeCV
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from xgboost import XGBRegressor<jupyter_output><empty_output><jupyter_text>Data UnderstandingIn this part we will load the data, check for missing values, and then clean the data for analysis if needed.<jupyter_code>#Reading the csv file
df_list = pd.read_csv('listings.csv')
df_list.head()
df_list.columns
df_list.dtypes<jupyter_output><empty_output><jupyter_text>Data PreparationWe will be performing data processing in this part. This includes cleaning, type converting and other data manipulations.<jupyter_code>#We will be using this class for data preprocessing
class Data_Handle:
    def __init__(self,df):
        super(Data_Handle,self).__init__()
        self.df = df
        
    def remove_columns(self,df,drop_cols):
        '''
        INPUT:
        df - the pandas dataframe from which columns has to be dropped
        drop_cols = list of column names that's need to be dropped
        
        OUTPUT:
        df - dataframe with the specified columns removed
        '''
        self.df = df.drop(drop_cols,axis=1)
        return self.df
    
    def print_top_x_missing_percent_cols(self,df,top_x):
        '''
        INPUT:
        df - the pandas dataframe whose percentage of missing value for each column has
        to be printed
        top_x = top x number of columns with most missing value percentage will be
        printed
        
        '''
        null_df = df.isnull().sum().sort_values(ascending=False)
        percent = (df.isnull().sum()/df.isnull().count()).sort_values(ascending=False)
        missing_data = pd.concat([null_df, percent], axis=1, keys=['Total', 'Percent'])
        print(missing_data.head(top_x))
        return
    
    def extract_numeric(self,df,columns):
        '''
        INPUT:
        df - the pandas dataframe from which numeric values need to be
        extracted from the specified columns having comma separated cell
        values.
        columns = list of column names from which values have to be 
        extracted
        
        OUTPUT:
        df - dataframe with numeric value extracted.
        '''
        remove_commas = lambda x:''.join(str(x).split(','))
        for col in columns:
            self.df[col] = df[col].apply(remove_commas).str.extract(r'(\d+)').astype(float)
        return self.df
    
    def convert_to_binary(self,df,columns):
        '''
        INPUT:
        df - the pandas dataframe from which columns has to be converted
        to binary
        
        OUTPUT:
        df - dataframe with the specified columns converted to binary
        '''
        for col in columns:
            self.df[col] = df[col].apply(lambda x: 1 if str(x)=='t' else 0 )
        return self.df
    
    def fill_missing_col(self,df,columns,method):
        '''
        INPUT:
        df - the pandas dataframe in which the specified column's
        missing values will be filled
        columns = list of column names that's need to be filled
        method = method used to fill the missing values.
        (median,mean,mode)
        OUTPUT:
        df - dataframe with the specified columns filled.
        '''
        for col in columns:
            if method=='mode':
                self.df[col] = df[col].fillna(df[col].mode()[0])
            elif method=='median':
                self.df[col] = df[col].fillna(df[col].median()[0])
            elif method=='mean':
                self.df[col] = df[col].fillna(df[col].mean())
        
        return self.df
    
    def convert_to_category(self,df,columns):
        '''
        INPUT:
        df - the pandas dataframe in which  the columns specified
        will be converted to category variables
        columns = list of column names that's need to be converted
        
        OUTPUT:
        df - dataframe with the specified columns converted to 
        categorical variables.
        '''
        for col in columns:
            df = pd.concat([df.drop(col,axis=1),pd.get_dummies(df[col],drop_first=False)],axis=1)
        self.df = df.copy()
        return self.df
    
    def list_feature_to_count(self,df,column_name,new_column_name):
        '''
        INPUT:
        df - the pandas dataframe from which the specifed column
        will be converted.
        Here a column having values as lists will be converted to
        count of values in the list
        For Ex column value x =['a','b'] this value will converted to 2
        column_name = single column name
        new_column_name = column name for the new values.
        
        OUTPUT:
        df - dataframe with the specified column converted.
        '''
        count_items_in_list = lambda x : len(x.split(',')) 
        self.df[new_column_name] = df[column_name].apply(count_items_in_list)
        self.df = df.drop(columns=[column_name])
        return self.df
            
    
    def remove_rows_missing_col(self,df,columns):
        '''
        INPUT:
        df - the pandas dataframe from which rows will be removed
        which have missing values in the specified columns
        columns = list of column names that's need to be checked
        for missing values.
        
        OUTPUT:
        df - dataframe with the rows removed
        '''
        for col in columns:
            self.df = df.dropna(col)
        return self.df
data = Data_Handle(df_list) #create of object of the class
#First we will fix numeric columns to be of int or float type
numeric_cols = ['extra_people','host_response_rate','host_acceptance_rate','price','monthly_price','weekly_price','security_deposit','cleaning_fee']
df_list = data.extract_numeric(df_list,numeric_cols)
df_list.dtypes
# this function prints percent of missing values of top m columns
data.print_top_x_missing_percent_cols(df_list,60)
# We will drop columns that have more than 30% data missing, columns 
# that have textual content like reviews, urls etc.
# drop columns
drop_cols=['listing_url','scrape_id','jurisdiction_names','license','thumbnail_url','medium_url',
           'picture_url','xl_picture_url','host_thumbnail_url','host_picture_url','state','has_availability',
           'neighbourhood_group_cleansed','notes','smart_location','country','country_code',
           'transit','latitude','longitude','last_scraped','access','interaction','neighborhood_overview',
           'host_about','house_rules','space','square_feet','last_review','first_review','host_id','host_url',
           'calendar_last_scraped','experiences_offered','id','monthly_price','weekly_price',
            'security_deposit']
df_list = data.remove_columns(df_list,drop_cols)
data.print_top_x_missing_percent_cols(df_list,60)<jupyter_output>Total   Percent
cleaning_fee                       1107  0.308787
review_scores_accuracy              823  0.229568
review_scores_location              822  0.229289
review_scores_value                 821  0.229010
review_scores_checkin               820  0.228731
review_scores_cleanliness           818  0.228173
review_scores_communication         818  0.228173
review_scores_rating                813  0.226778
reviews_per_month                   756  0.210879
neighbourhood                       543  0.151464
host_acceptance_rate                471  0.131381
host_response_rate                  471  0.131381
host_response_time                  471  0.131381
host_neighbourhood                  339  0.094561
summary                             143  0.039888
zipcode                              38  0.010600
market                               14  0.003905
bathrooms                            14  0.003905
host_location                        11  0.003068
[...]<jupyter_text>Some columns need to be converted to binary(0-1) as they hold either t(true) or f(false)<jupyter_code>#convert to binary columns
boolean_cols = ['host_is_superhost','host_has_profile_pic','host_identity_verified','is_location_exact',
                'requires_license','instant_bookable','require_guest_profile_picture',
                'require_guest_phone_verification']
#We will fill missing values in the binary columns with most frequent value(mode)
#add missing values to binary columns with mode method
df_list = data.fill_missing_col(df_list,boolean_cols,'mode')
data.print_top_x_missing_percent_cols(df_list,60)
#convert to binary
df_list = data.convert_to_binary(df_list,boolean_cols)
data.print_top_x_missing_percent_cols(df_list,60)
df_list.dtypes
#Now we will convert some columns into category
#category columns
cat_cols = ['host_response_time','property_type','room_type', 'bed_type','cancellation_policy','neighbourhood_cleansed']
#First we will fill the missing columns with mode method
df_list = data.fill_missing_col(df_list,cat_cols,'mode')
data.print_top_x_missing_percent_cols(df_list,60)
#convert to category
df_list = data.convert_to_category(df_list,cat_cols)
data.print_top_x_missing_percent_cols(df_list,60)
#convert amenities to number of amenities
df_list = data.list_feature_to_count(df_list,'amenities','num_amenities')
df_list.select_dtypes(include=['object']).dtypes
drop_columns_missing = ['name','summary','description',
                        'host_name','host_since','host_location','host_neighbourhood','host_verifications',
                        'street','neighbourhood','city','zipcode','market','calendar_updated']

df_list = data.remove_columns(df_list,drop_columns_missing)
data.print_top_x_missing_percent_cols(df_list,60)
fill_with_mean_cols = ['cleaning_fee','reviews_per_month','review_scores_rating','bathrooms']
fill_with_mode_cols = ['review_scores_accuracy','review_scores_location','review_scores_value',
                       'review_scores_communication','review_scores_cleanliness','review_scores_checkin',
                       'host_acceptance_rate','host_response_rate','bedrooms','beds']

df_list = data.fill_missing_col(df_list,fill_with_mean_cols,'mean')
df_list = data.fill_missing_col(df_list,fill_with_mode_cols,'mode')
data.print_top_x_missing_percent_cols(df_list,60)
#Lets analyze the heatmap
fig, ax = plt.subplots(figsize=(10,10)) 
sns.heatmap(df_list.corr())<jupyter_output><empty_output><jupyter_text>Modelling Now we will implement machine learning models1. Liner regression 2. Lasso regression 3. Ridge regression4. Decision tree5. Random Forest6. XGBoost7. Neural Network<jupyter_code>y = df_list['price']
X = df_list.drop(['price','requires_license'],axis=1)
def normalize(df):
    result = df.copy()
    for feature_name in df.columns:
        max_value = df[feature_name].max()
        min_value = df[feature_name].min()
        result[feature_name] = (df[feature_name] - min_value) / (max_value - min_value)
    return result

X=normalize(X)
y= (y-min(y))/(max(y)-min(y))
X.dtypes
#Splitting the data into train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=10)<jupyter_output><empty_output><jupyter_text>1. Linear Regression<jupyter_code>linear_model = LinearRegression(normalize=True)
linear_model.fit(X_train,y_train)
y_linear_predict = linear_model.predict(X_test)
print("Mean squared error: ",mean_squared_error(y_linear_predict,y_test))
print("r^2 score: ",r2_score(y_test, y_linear_predict))<jupyter_output>Mean squared error:  0.000496103219518046
r^2 score:  0.5158007423784016<jupyter_text>2. Lasso Regression<jupyter_code>lasso_model=LassoCV(normalize=True,cv=5)
lasso_model.fit(X_train,y_train)
y_lasso_predict = lasso_model.predict(X_test)
print("Mean squared error: ",mean_squared_error(y_lasso_predict,y_test))
print("r^2 score: ",r2_score(y_test, y_lasso_predict))
ridge_model=RidgeCV(normalize=True,cv=5)
ridge_model.fit(X_train,y_train)
y_ridge_predict = ridge_model.predict(X_test)
print("Mean squared error: ",mean_squared_error(y_ridge_predict,y_test))
print("r^2 score: ",r2_score(y_test, y_ridge_predict))<jupyter_output>Mean squared error:  0.0007652672707212559
r^2 score:  0.25309526367252244<jupyter_text>2. Decision Trees<jupyter_code>dtree_model=DecisionTreeRegressor(criterion="mse")
dtree_model.fit(X_train,y_train)
y_dtree_predict = dtree_model.predict(X_test)
print("Mean squared error: ",mean_squared_error(y_dtree_predict,y_test))
print("r^2 score: ",r2_score(y_test, y_dtree_predict))
rforest_model = RandomForestRegressor(random_state=12)
rforest_model.fit(X_train,y_train)
y_rforest_predict = rforest_model.predict(X_test)
print("Mean squared error: ",mean_squared_error(y_rforest_predict,y_test))
print("r^2 score: ",r2_score(y_test, y_rforest_predict))<jupyter_output>Mean squared error:  0.00042786064687108584
r^2 score:  0.5824058392893765<jupyter_text>XGBoost<jupyter_code>xgboost_model = XGBRegressor(objective='reg:squarederror')
xgboost_model.fit(X_train, y_train)
y_xgboost_predict = xgboost_model.predict(X_test)
print("Mean squared error: ",mean_squared_error(y_xgboost_predict,y_test))
print("r^2 score: ",r2_score(y_test, y_xgboost_predict))<jupyter_output>Mean squared error:  0.0005539598694179121
r^2 score:  0.45933235872791234<jupyter_text>Neural Network<jupyter_code>import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LeakyReLU,PReLU,ELU
from keras.layers import Dropout
nn_model = Sequential()

nn_model.add(Dense(128, kernel_initializer='normal',input_dim = X_train.shape[1], activation='relu'))

# The Hidden Layers :
nn_model.add(Dense(256, kernel_initializer='normal',activation='relu'))
nn_model.add(Dense(256, kernel_initializer='normal',activation='relu'))
nn_model.add(Dense(256, kernel_initializer='normal',activation='relu'))

# The Output Layer :
nn_model.add(Dense(1, kernel_initializer='normal',activation='linear'))

nn_model.compile(loss='mean_squared_error', optimizer='adam', metrics=['mean_absolute_error'])
nn_model.summary()

model_history=nn_model.fit(X_train, y_train,validation_split=0.33, batch_size = 10, epochs = 100)
y_nn_predict=nn_model.predict(X_test)
print("Mean squared error: ",mean_squared_error(y_nn_predict,y_test))
print("r^2 score: ",r2_score(y_test, y_nn_predict))
axis_dims = (11.7, 8.27)
fig, ax = plt.subplots(figsize=axis_dims)

sns.distplot(y_linear_predict,rug=True, hist=False,label='linear',color='violet')
sns.distplot(y_lasso_predict,rug=True, hist=False,label='lasso',color='indigo')
sns.distplot(y_ridge_predict,rug=True, hist=False,label='ridge',color='blue')
sns.distplot(y_dtree_predict,rug=True, hist=False,label='dtree',color='green')
sns.distplot(y_rforest_predict,rug=True, hist=False,label='rforest',color='yellow')
sns.distplot(y_xgboost_predict,rug=True, hist=False,label='xgboost',color='orange')
sns.distplot(y_nn_predict,rug=True, hist=False,label='nn',color='red')
sns.distplot(y_test,rug=True, hist=False,label='actual',color='brown')


ax2 = plt.axes([0.5, 0.5, .4, .4], facecolor='white')
sns.distplot(y_linear_predict, ax=ax2,rug=True, hist=False,label='linear',color='violet')
sns.distplot(y_lasso_predict, ax=ax2,rug=True, hist=False,label='lasso',color='indigo')
sns.distplot(y_ridge_predict, ax=ax2,rug=True, hist=False,label='ridge',color='blue')
sns.distplot(y_dtree_predict, ax=ax2,rug=True, hist=False,label='dtree',color='green')
sns.distplot(y_rforest_predict, ax=ax2,rug=True, hist=False,label='rforest',color='yellow')
sns.distplot(y_xgboost_predict, ax=ax2,rug=True, hist=False,label='xgboost',color='orange')
sns.distplot(y_nn_predict, ax=ax2,rug=True, hist=False,label='nn',color='red')
sns.distplot(y_test, ax=ax2,rug=True, hist=False,label='actual',color='brown')

ax2.set_title('zoom')
ax2.set_xlim([0,.1])

plt.legend()
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10573325286662644, 'fraction_numerical': 0.02751961375980688, 'mean_word_length': 4.2522979397781295, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '516935', 'license': 'MIT', 'n_tokens_mistral': 5710, 'n_tokens_neox': 5285, 'n_words': 1103, 'path': 'Boston_ML.ipynb', 'repo_name': 'sanketg186/Airbnb_Boston_ML', 'size': '16570'}