<jupyter_start><jupyter_text>0.0. Understanding the problem --Goal:        --1.0 Predict the first destination that the new user will choose        --Why?        --What is the business model of Airbnb?            --Marketplace (connect people who offer acomodation to whom are seeking a place)            --Offer                --Portfolio size                --Portfolio diversity and density                --Average price                            --Demand                --Number of users                --LTV (lifetime value)                --CAC (client acquisition cost)                                Gross Revenue = (Fee*Number of clients) - CAC                --Solution:        --Predictive model for the first destination of new user    --1.0 Prediction save in a database    --2.0 API        --Input: User and features        --Output: User and feature with destination prediction          Module 1  0.0. Imports  0.1. Helper Functions<jupyter_code>!pip install keras
!pip install tensorflow
!pip install scikit-plot
import random
import pickle
import seaborn as sns
import numpy   as np
import pandas  as pd
 
from sklearn    import metrics         as m
from sklearn    import model_selection as ms
from sklearn    import preprocessing   as pp
from scikitplot import metrics         as mt

from keras import models as ml
from keras import layers as l<jupyter_output><empty_output><jupyter_text>0.2. Loading Data<jupyter_code>df_raw = pd.read_csv('dataset/train_users_2.csv', low_memory=True)
df_raw.shape
df_sessions = pd.read_csv('dataset/sessions.csv', low_memory=True)
df_sessions.shape<jupyter_output><empty_output><jupyter_text>1.0. Data Description<jupyter_code>df1 = df_raw.copy()<jupyter_output><empty_output><jupyter_text>1.1. Data Dimensions<jupyter_code>print('Number of rows: {}'.format(df1.shape[0]))
print('Number of columns: {}'.format(df1.shape[1]))
print('Number of rows: {}'.format(df_sessions.shape[0]))
print('Number of columns: {}'.format(df_sessions.shape[1]))<jupyter_output>Number of rows: 10567737
Number of columns: 6<jupyter_text>1.2. Data Type<jupyter_code>df1.dtypes
df_sessions.dtypes<jupyter_output><empty_output><jupyter_text>1.3. NA Check<jupyter_code>df1.isna().sum()/len(df1)
df_sessions.isna().sum()/len(df_sessions)
#remove missing data
#df1 = df1.dropna()

#date_first_booking
date_first_booking_max = pd.to_datetime(df1['date_first_booking']).max().strftime('%Y-%m-%d')
df1['date_first_booking'] = df1['date_first_booking'].fillna(date_first_booking_max)

#age
avg_age = df1['age'].mean()
df1['age'] = df1['age'].fillna(avg_age)

#first_affiliate_tracked
df1 = df1[~df1['first_affiliate_tracked'].isna()]

#user_id
df_sessions = df_sessions[~df_sessions['user_id'].isna()]

#action
df_sessions = df_sessions[~df_sessions['action'].isna()]

#action_type
df_sessions = df_sessions[~df_sessions['action_type'].isna()]

#action_detail
df_sessions = df_sessions[~df_sessions['action_detail'].isna()]

#secs_elapsed
df_sessions = df_sessions[~df_sessions['secs_elapsed'].isna()]<jupyter_output><empty_output><jupyter_text>1.4. Change Data Type<jupyter_code>#date_account_created
df1['date_account_created'] = pd.to_datetime(df1['date_account_created'])

#timestamp_first_active
df1['timestamp_first_active'] = pd.to_datetime(df1['timestamp_first_active'], format='%Y%m%d%H%M%S')

#date_first_booking
df1['date_first_booking'] = pd.to_datetime(df1['date_first_booking'])

#age
df1['age'] = df1['age'].astype(int)<jupyter_output><empty_output><jupyter_text>1.5. Change Balanced Data<jupyter_code>df1['country_destination'].value_counts(normalize=True)<jupyter_output><empty_output><jupyter_text>2.0. Data Filtering<jupyter_code>df2 = df1.copy()<jupyter_output><empty_output><jupyter_text>2.1. Filtering Rows  2.2. Columns Selection  3.0. Data Preparation<jupyter_code>df3 = df2.copy()
#dummy variable
df3_dummy = pd.get_dummies(df3.drop(['id','country_destination'], axis=1))

#join id and country destination
df3 = pd.concat([df3[['id','country_destination']], df3_dummy], axis=1)<jupyter_output><empty_output><jupyter_text>4.0. Feature Seleciotn<jupyter_code>cols_drop = ['date_account_created', 'timestamp_first_active', 'date_first_booking']
df4 = df3.drop(cols_drop, axis=1)
X = df4.drop(['id', 'country_destination'], axis=1)
y = df4['country_destination'].copy()
#split dataset into train and test
X_train, X_test, y_train, y_test = ms.train_test_split(X, y, test_size=0.2, random_state=32)<jupyter_output><empty_output><jupyter_text>5.0. Machine Learning  5.1. Baseline Model<jupyter_code>country_destination_list = df1['country_destination'].drop_duplicates().sort_values().tolist()
k_num = y_test.shape[0]
country_destination_weights = df1['country_destination'].value_counts(normalize=True).sort_index().tolist()

yhat_random = random.choices(population=country_destination_list, 
                             weights=country_destination_weights,
                             k=k_num)
len(yhat_random)<jupyter_output><empty_output><jupyter_text>5.1.1. Baseline Performance<jupyter_code>#accuracy
acc_random = m.accuracy_score(y_test, yhat_random)
print('Accuracy: {}'.format(acc_random))

#balanced accuracy
balanced_acc_random = m.balanced_accuracy_score(y_test, yhat_random)
print('Balanced Accuracy: {}'.format(balanced_acc_random))

#Kappa metrics
kappa_random = m.cohen_kappa_score(y_test, yhat_random)
print('Kappa Accuracy: {}'.format(kappa_random))

#confusion matrix
mt.plot_confusion_matrix(y_test, yhat_random, normalize=False, figsize=(12,12))<jupyter_output>Accuracy: 0.4294565793914846
Balanced Accuracy: 0.08200215041189667
Kappa Accuracy: 0.005444481838312032<jupyter_text>5.2. Neural Network - MLP<jupyter_code>ohe = pp.OneHotEncoder()
y_train_nn = ohe.fit_transform(y_train.values.reshape(-1, 1)).toarray()
#model definition
model = ml.Sequential()
model.add(l.Dense(128, input_dim=X_train.shape[1], activation='relu'))
model.add(l.Dense(12, activation='softmax'))

#model compile
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

model.fit(X_train, y_train_nn, epochs=10)<jupyter_output>Epoch 1/10
5185/5185 [==============================] - 7s 1ms/step - loss: 1.2956 - accuracy: 0.5723
Epoch 2/10
5185/5185 [==============================] - 6s 1ms/step - loss: 1.1707 - accuracy: 0.6043
Epoch 3/10
5185/5185 [==============================] - 6s 1ms/step - loss: 1.1315 - accuracy: 0.6113
Epoch 4/10
5185/5185 [==============================] - 6s 1ms/step - loss: 1.1031 - accuracy: 0.6177
Epoch 5/10
5185/5185 [==============================] - 7s 1ms/step - loss: 1.0896 - accuracy: 0.6194
Epoch 6/10
5185/5185 [==============================] - 6s 1ms/step - loss: 1.0860 - accuracy: 0.6219
Epoch 7/10
5185/5185 [==============================] - 6s 1ms/step - loss: 1.0834 - accuracy: 0.6219
Epoch 8/10
5185/5185 [==============================] - 6s 1ms/step - loss: 1.0826 - accuracy: 0.6228
Epoch 9/10
5185/5185 [==============================] - 6s 1ms/step - loss: 1.0841 - accuracy: 0.6215
Epoch 10/10
5185/5185 [==============================] - 7s 1ms/step - loss: 1.085[...]<jupyter_text>5.2.1. NN Performance<jupyter_code>#prediction
pred_nn = model.predict(X_test)

#invert prediction
yhat_nn = ohe.inverse_transform(pred_nn)

#prediction prepare
y_test_nn = y_test.to_numpy()
yhat_nn = yhat_nn.reshape(1, -1)[0]
#accuracy
acc_nn = m.accuracy_score(y_test_nn, yhat_nn)
print('Accuracy: {}'.format(acc_nn))

#balanced accuracy
balanced_acc_nn = m.balanced_accuracy_score(y_test_nn, yhat_nn)
print('Balanced Accuracy: {}'.format(balanced_acc_nn))

#Kappa metrics
kappa_nn = m.cohen_kappa_score(y_test_nn, yhat_nn)
print('Kappa Accuracy: {}'.format(kappa_nn))

#confusion matrix
mt.plot_confusion_matrix(y_test_nn, yhat_nn, normalize=False, figsize=(12,12))<jupyter_output>Accuracy: 0.6259221756111674
Balanced Accuracy: 0.10488516996770543
Kappa Accuracy: 0.2209162063255159<jupyter_text>5.2.3. NN Performance - Cross-Validation<jupyter_code># generate k-fold
num_folds = 5
kfold = ms.StratifiedKFold(n_splits=num_folds, shuffle=True, random_state=32)

balanced_acc_list = []
kappa_acc_list = []

i = 1

for train_ix, val_ix in kfold.split(X_train, y_train):
    print('Fold Number: {}/{}'.format(i, num_folds))
    
    #get fold
    x_train_fold = X_train.iloc[train_ix]
    y_train_fold = y_train.iloc[train_ix]
    
    x_val_fold = X_train.iloc[val_ix]
    y_val_fold = y_train.iloc[val_ix]
    
    #target hot-enconding
    ohe = pp.OneHotEncoder()
    y_train_fold_nn = ohe.fit_transform(y_train_fold.values.reshape(-1,1)).toarray()
    
    #model definition
    model = ml.Sequential()
    model.add(l.Dense(256, input_dim=X_train.shape[1], activation='relu'))
    model.add(l.Dense(12, activation='softmax'))
    
    #compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    
    #training model
    model.fit(x_train_fold, y_train_fold_nn, epochs=100, batch_size=32, verbose=0)
    
    #prediction
    pred_nn = model.predict(x_val_fold)
    yhat_nn = ohe.inverse_transform(pred_nn)
    
    #prepare data
    y_test_nn = y_val_fold.to_numpy()
    yhat_nn = yhat_nn.reshape(1, -1)[0]
    
    #metrics
    ##Balanced Accuracy
    baanced_acc_nn = m.balanced_accuracy_score(y_test_nn, yhat_nn)
    balanced_acc_list.append(balanced_acc_nn)
    
    ##Kappa Metrics
    kappa_acc_nn = m.cohen_kappa_score(y_test_nn, yhat_nn)
    kappa_acc_list.append(kappa_acc_nn)
    
    i+=1

pickle.dump(balanced_acc_list, open('balanced_acc_list.pkl','wb'))
pickle.dump(kappa_acc_list, open('kappa_acc_list.pkl','wb'))
print('Avg Balanced Accuracy: {} +/- {}'.format(np.round(np.mean(balanced_acc_list),2),
                                                np.round(np.std(balanced_acc_list),4)))
print('Avg Kappa Accuracy: {} +/- {}'.format(np.round(np.mean(kappa_acc_list),2),
                                             np.round(np.std(kappa_acc_list)),4))<jupyter_output>Avg Balanced Accuracy: 0.1 +/- 0.0
Avg Kappa Accuracy: 0.22 +/- 0.0
{'fraction_non_alphanumeric': 0.1589866347496509, 'fraction_numerical': 0.05016955914621983, 'mean_word_length': 4.856892523364486, 'pattern_counts': {'":': 0, '<': 60, '<?xml version=': 0, '>': 60, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '264504', 'license': 'MIT', 'n_tokens_mistral': 3998, 'n_tokens_neox': 3658, 'n_words': 628, 'path': 'm03_airbnb.ipynb', 'repo_name': 'HenriqueCR1291/airbnb_prediction', 'size': '10026'}