<jupyter_start><jupyter_text>EDA<jupyter_code>%%capture
import sys

# If you're on Colab:
if 'google.colab' in sys.modules:
    DATA_PATH = 'https://raw.githubusercontent.com/Air-BnB-2-BW/data-science/master/airbnb_bw.csv'
    !pip install category_encoders==2.*
    !pip install eli5
    !pip install pdpbox
    !pip install shap
import pandas as pd

df = pd.read_csv(DATA_PATH, index_col=0)

print(df.shape)

df

df['Bedrooms'].value_counts()
df['Zipcode'].value_counts()
df['Price'].describe()
df['Square Feet'].describe()
df.info()
# is the target symmetric - it is skewed right
%matplotlib inline
import seaborn as sns
sns.distplot(df['Price']);
pd.options.display.float_format = '{:,.0f}'.format
df['Price'].describe()<jupyter_output><empty_output><jupyter_text>Mean Baseline<jupyter_code>guess = df['Price'].mean()
guess
errors = guess - df['Price']
errors
mean_absolute_error = errors.abs().mean()
print(f'If we just guessed every Airbnb cost ${guess:,.0f},')
print(f'we would be off by ${mean_absolute_error:,.0f} on average.')<jupyter_output>If we just guessed every Airbnb cost $200,
we would be off by $113 on average.<jupyter_text>Set features / target<jupyter_code>from sklearn.model_selection import train_test_split
train, test= train_test_split(df, test_size=0.20)

# Arrange data into X features matrix and y target vector
features = ['Zipcode', 'Square Feet', 'Bedrooms', 'Bathrooms', 'Review Scores Rating', 'Accommodates', 'Cleaning Fee', 'Free Parking', 'Wireless Internet', 'Cable TV', 'Prop_encoded', 'cancel_encoded']
target = 'Price'
X_train = train[features]
y_train = train[target]
X_test = test[features]
y_test = test[target]
row = X_train.iloc[[1]]
row
# What does the model predict for this Airbnb?
model.predict(row)<jupyter_output><empty_output><jupyter_text>Linear Regression<jupyter_code>from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

model = LinearRegression()
model.fit(X_train, y_train)
y_pred_train = model.predict(X_train)
print("MAE(Train):$",mean_absolute_error(y_train, y_pred_train))<jupyter_output>MAE(Train):$ 65.71765315411817<jupyter_text>Random Forest<jupyter_code>from scipy.stats import randint, uniform
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestRegressor
from sklearn.pipeline import make_pipeline
import category_encoders as ce
from sklearn.preprocessing import StandardScaler

pipeline = make_pipeline(
    ce.TargetEncoder(), 
    SimpleImputer(),
    StandardScaler(), 
    RandomForestRegressor(random_state=42)
)

param_distributions = {
    'targetencoder__min_samples_leaf': randint(1, 1000),     
    'simpleimputer__strategy': ['mean', 'median'], 
    'randomforestregressor__n_estimators': randint(50, 500), 
    'randomforestregressor__max_depth': [5, 10, 15, 20, None], 
    'randomforestregressor__max_features': uniform(0, 1), 
}

# If you're on Colab, decrease n_iter & cv parameters
search = RandomizedSearchCV(
    pipeline, 
    param_distributions=param_distributions, 
    n_iter=100, 
    cv=10, 
    scoring='neg_mean_absolute_error', 
    verbose=10, 
    return_train_score=True, 
    n_jobs=-1
)

search.fit(X_train, y_train);
print('Best hyperparameters', search.best_params_)
print('Cross-validation MAE', -search.best_score_)
model = search.best_estimator_<jupyter_output>Best hyperparameters {'randomforestregressor__max_depth': 20, 'randomforestregressor__max_features': 0.35856215261376856, 'randomforestregressor__n_estimators': 264, 'simpleimputer__strategy': 'median', 'targetencoder__min_samples_leaf': 759}
Cross-validation MAE 61.84941498061594<jupyter_text>XGBoost<jupyter_code>from xgboost import XGBRegressor
pipeline = make_pipeline(
    ce.TargetEncoder(), 
    SimpleImputer(),
    StandardScaler(), 
    XGBRegressor(random_state=42,n_jobs=-1)
)
param_distributions = {
    'targetencoder__min_samples_leaf': randint(1, 1000),     
    'simpleimputer__strategy': ['mean', 'median'],
    'xgbregressor__learning_rate': [.03, 0.05, .07 ,0.13,0.2],
    'xgbregressor__max_depth': [5, 6, 7],}

# If you're on Colab, decrease n_iter & cv parameters
search = RandomizedSearchCV(
    pipeline, 
    param_distributions=param_distributions, 
    n_iter=100, 
    cv=10, 
    scoring='neg_mean_absolute_error', 
    verbose=10, 
    return_train_score=True, 
    n_jobs=-1
)
search.fit(X_train, y_train);
print('XG Boost MAE:', -search.best_score_)<jupyter_output>XG Boost MAE: 60.51901280101125<jupyter_text>Permutation Importances<jupyter_code>from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer

pipeline = make_pipeline(
    ce.OrdinalEncoder(), 
    SimpleImputer(strategy='median'), 
    RandomForestClassifier(n_estimators=20, 
                           random_state=42, 
                           n_jobs=-1)
)

# Fit on train, score on val
pipeline.fit(X_train, y_train);
# Get feature importances
rf = pipeline.named_steps['randomforestclassifier']
importances = pd.Series(rf.feature_importances_, X_train.columns)

# Plot feature importances
%matplotlib inline
import matplotlib.pyplot as plt

n = 12
plt.figure(figsize=(10,n/2))
plt.title(f'Top {n} features')
importances.sort_values()[-n:].plot.barh(color='grey');<jupyter_output><empty_output><jupyter_text>Partial Dependence Plot 1 feature<jupyter_code>from sklearn.metrics import r2_score
from xgboost import XGBRegressor

gb = make_pipeline(
    ce.OrdinalEncoder(), 
    XGBRegressor(n_estimators=200, objective='reg:squarederror', n_jobs=-1)
)

gb.fit(X_train, y_train)
y_pred = gb.predict(X_test)
print('Gradient Boosting R^2', r2_score(y_test, y_pred))
import matplotlib.pyplot as plt
plt.rcParams['figure.dpi'] = 72
from pdpbox.pdp import pdp_isolate, pdp_plot

feature = 'Square Feet'

isolated = pdp_isolate(
      model=gb,
      dataset=X_test,
      model_features=X_test.columns,
      feature=feature
)
pdp_plot(isolated, feature_name=feature)<jupyter_output><empty_output><jupyter_text>Partial Dependence Plot 2 features<jupyter_code>from pdpbox.pdp import pdp_interact, pdp_interact_plot

features = ['Bedrooms', 'Bathrooms']

interaction = pdp_interact(
    model=gb,
    dataset=X_train,
    model_features=X_train.columns,
    features=features
)
pdp_interact_plot
pdp_interact_plot(interaction, plot_type='grid', feature_names=features);<jupyter_output>findfont: Font family ['Arial'] not found. Falling back to DejaVu Sans.<jupyter_text>Shapley Force Plot<jupyter_code>from scipy.stats import randint, uniform
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import RandomizedSearchCV

param_distributions = { 
    'n_estimators': randint(50, 500), 
    'max_depth': [5, 10, 15, 20, None], 
    'max_features': uniform(0, 1), 
}

search = RandomizedSearchCV(
    RandomForestRegressor(random_state=42), 
    param_distributions=param_distributions, 
    n_iter=5, 
    cv=2, 
    scoring='neg_mean_absolute_error', 
    verbose=10, 
    return_train_score=True, 
    n_jobs=6, 
    random_state=42
)

search.fit(X_train, y_train);
print('Best hyperparameters', search.best_params_)
print('Cross-validation MAE', -search.best_score_)
model = search.best_estimator_
# Get an individual observation to explain.
# For example, the 5th row from the test set.
row = X_train.iloc[[5]]
row
# What was the actual price for this Airbnb?
y_test.iloc[[5]]
# What does the model predict for this Airbnb?
model.predict(row)
# Look at a Shapley Values Force Plot
import shap

explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(row)
shap.initjs()
shap.force_plot(
    base_value=explainer.expected_value,
    shap_values=shap_values,
    features=row
)<jupyter_output><empty_output><jupyter_text>Visualizations<jupyter_code>(df['cost_per_person'] > 0).value_counts()
(df['cost_per_person'] > 25).value_counts()
(df['cost_per_person'] > 50).value_counts()
(df['cost_per_person'] > 75).value_counts()
(df['cost_per_person'] > 100).value_counts()
(df['cost_per_person'] > 125).value_counts()
(df['cost_per_person'] > 150).value_counts()
(df['cost_per_person'] > 175).value_counts()
(df['cost_per_person'] > 200).value_counts()
# Engineer new feature to show cost per person
df['cost_per_person'] = ((df['Price'] + df['Cleaning Fee'])/(df['Accommodates'])).round(1)
df
import plotly.graph_objects as go

x = ['$0-25', '$25-50', '$50-75', '$75-100', '$100-125', '$125-150', '$150-175', '$175-200', '$200+']
y = [27, 272, 325, 125, 164, 93, 45, 22 ,13]

fig = go.Figure(data=[go.Bar(x=x, y=y)])


# Customize aspect
fig.update_traces(marker_color='rgb(158,202,225)', marker_line_color='rgb(8,48,107)',
                  marker_line_width=4.5, opacity=0.6)

fig.update_layout(title_text='Cost Per Person')
fig.show()
!pip install chart_studio
import chart_studio
import chart_studio.plotly as py
import chart_studio.tools as tls
username = 'egrinalds'
api_key = '<KEY>'
chart_studio.tools.set_credentials_file(username=username, api_key=api_key)
py.plot(fig, filename = 'Cost Per Person Analysis', auto_open=True)<jupyter_output>Requirement already satisfied: chart_studio in /usr/local/lib/python3.6/dist-packages (1.1.0)
Requirement already satisfied: requests in /usr/local/lib/python3.6/dist-packages (from chart_studio) (2.23.0)
Requirement already satisfied: retrying>=1.3.3 in /usr/local/lib/python3.6/dist-packages (from chart_studio) (1.3.3)
Requirement already satisfied: plotly in /usr/local/lib/python3.6/dist-packages (from chart_studio) (4.4.1)
Requirement already satisfied: six in /usr/local/lib/python3.6/dist-packages (from chart_studio) (1.15.0)
Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests->chart_studio) (3.0.4)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from requests->chart_studio) (1.24.3)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.6/dist-packages (from requests->chart_studio) (2020.6.20)
Requirement already satisfied: idna<3,>=2.5 in /u[...]
{'fraction_non_alphanumeric': 0.12727632620744259, 'fraction_numerical': 0.03820269200316706, 'mean_word_length': 5.800134589502019, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 57, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '544230', 'license': 'MIT', 'n_tokens_mistral': 3921, 'n_tokens_neox': 3600, 'n_words': 719, 'path': 'notebooks/unit_3_build.ipynb', 'repo_name': 'Air-BnB-2-BW/data-science', 'size': '10119'}