<jupyter_start><jupyter_text>BEER TYPE PREDICTION - ALL Variables  1. Load Packages<jupyter_code># Load the packages needed for Logistic Regression Modelling upfront
import pandas as pd
import numpy as np
#from chart_studio import plotly as plt
#import seaborn as sns
import category_encoders as ce
#from numpy import array

#from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler, OneHotEncoder
#from sklearn.preprocessing import LabelBinarizer
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV

#from sklearn.metrics import mean_squared_error as mse
#from sklearn.metrics import mean_absolute_error as mae
from sklearn.metrics import roc_auc_score
from sklearn.metrics import accuracy_score

from joblib import dump<jupyter_output><empty_output><jupyter_text>2. Load the data<jupyter_code># Load the training data set
data = pd.read_csv('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/raw/beer_reviews.csv')<jupyter_output><empty_output><jupyter_text>3. Explore the Data<jupyter_code># check rows and columns of the training set
data.shape
data.head()
data.info()
data.columns
data.describe()
# count the beer types in the data set
data['beer_style'].nunique()
# check the spread of observations
data['beer_style'].value_counts()<jupyter_output><empty_output><jupyter_text>4. Transform the Data  4.1 Create a copy of the raw dataset<jupyter_code># create a copy of dataset for transformations
df = data.copy()

df.head()<jupyter_output><empty_output><jupyter_text>4.2 Drop the 2 Identifier columns and save in the interim folder<jupyter_code>df.drop(columns=['brewery_id', 'beer_beerid'], axis = 1, inplace=True)

df.head()
#df.to_csv('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/interim/beer_reviews_noIDcolumns.csv', index=False)<jupyter_output><empty_output><jupyter_text>4.3 Convert float columns to Int that are actually numeric<jupyter_code># Change float columns to int
# https://stackoverflow.com/questions/21291259/convert-floats-to-ints-in-pandas
df = df.astype({
    'review_overall': 'int', 
    'review_aroma': 'int', 
    'review_appearance': 'int',
    'review_palate': 'int',
    'review_taste': 'int'
    })
# this float column has null values so they need to be dealt with as well
# https://stackoverflow.com/questions/21291259/convert-floats-to-ints-in-pandas

df[("beer_abv")] = df[("beer_abv")].fillna(0.0).astype(int)
# Check if it worked
df.info()
df.describe()<jupyter_output><empty_output><jupyter_text>4.4 Standardise the Numeric columns in the dataset<jupyter_code>df.columns
# Create a list of numeric columns

num_cols = ['review_time', 'review_overall',
       'review_aroma', 'review_appearance',
       'review_palate', 'review_taste', 'beer_abv']
# Scale the numeric columns in the training dataset
scaler = StandardScaler()
df[num_cols] = scaler.fit_transform(df[num_cols])
df.head()<jupyter_output><empty_output><jupyter_text>4.5 One Hot Encode the Categorical Variables (except target variable)<jupyter_code>cat_cols = ['brewery_name', 'review_profilename', 'beer_name']

#Create object for binary encoding
encoder= ce.BinaryEncoder(cols=cat_cols,return_df=True)
#Fit and Transform Data 
df_cleaned = encoder.fit_transform(df) 
df_cleaned<jupyter_output><empty_output><jupyter_text>4.6 Now, Label Encode the Target Variable<jupyter_code>df_cleaned.columns
# https://stackoverflow.com/questions/50473381/scikit-learns-labelbinarizer-vs-onehotencoder

# integer encode
label_encoder = LabelEncoder()
df_cleaned['beer_style'] = label_encoder.fit_transform(df_cleaned['beer_style'])
print(df_cleaned['beer_style'])
df_cleaned.head()<jupyter_output><empty_output><jupyter_text>4.7 Split up the Datasets<jupyter_code># extract the target variable out as y = target
target = pd.DataFrame(df_cleaned.pop('beer_style'))
target.shape
target.head()
X_train, X_test, y_train, y_test = train_test_split(df_cleaned, target, test_size=0.3, random_state = 42)
X_train.shape
X_test.shape
y_train.shape
y_test.shape<jupyter_output><empty_output><jupyter_text>4.8 Save the processed data files<jupyter_code># save the processed datasets
#np.save('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/processed/X_train', X_train)
#np.save('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/processed/X_test',  X_test)
#np.save('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/processed/y_train', y_train)
#np.save('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/processed/y_test',  y_test)
# save csv files too
#X_train.to_csv('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/processed/X_train.csv', index=False)
#X_test.to_csv('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/processed/X_test.csv', index=False)
#y_train.to_csv('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/processed/y_train.csv', index=False)
#y_test.to_csv('/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/data/processed/y_test.csv', index=False)<jupyter_output><empty_output><jupyter_text>Train a Multinomial Logistic Regression Model<jupyter_code>X_train.head()
print(y_train)
# https://machinelearningmastery.com/multinomial-logistic-regression-with-python/
# define the multinomial logistic regression model with a penalty
model = LogisticRegression(multi_class="multinomial", solver='lbfgs', max_iter=100, penalty='l2', C=1.0) #, class_weight='balanced')

# https://stackoverflow.com/questions/62658215/convergencewarning-lbfgs-failed-to-converge-status-1-stop-total-no-of-iter
# Convergence warning below in 'model.fit' can be resolved by adding 'max_iter>100' here, as above

# https://stackoverflow.com/questions/61814494/what-is-this-warning-convergencewarning-lbfgs-failed-to-converge-status-1
# default max_iter = 100
# https://stackoverflow.com/questions/58313842/a-column-vector-y-was-passed-when-a-1d-array-was-expected-error-message
# Model was throwing a array warning so added 'np.ravel()' to the target dataset
model.fit(X_train, y_train)

# ran for over 10min with default max_iter=100 and no class_weight
# ran for 60min with 1000 iterations and balanced class_weight
# should have just tried 300 iters --> ran for 33min, but wasn't enough..<jupyter_output>/opt/homebrew/Caskroom/miniforge/base/envs/pytorch_m1/lib/python3.8/site-packages/sklearn/utils/validation.py:993: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().
  y = column_or_1d(y, warn=True)
/opt/homebrew/Caskroom/miniforge/base/envs/pytorch_m1/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.

Increase the number of iterations (max_iter) or scale the data as shown in:
    https://scikit-learn.org/stable/modules/preprocessing.html
Please also refer to the documentation for alternative solver options:
    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
  n_iter_i = _check_optimize_result(<jupyter_text>Evaluate Model Performance<jupyter_code># https://dataaspirant.com/implement-multinomial-logistic-regression-python/
print ("Multinomial Logistic regression Train Accuracy :: ", accuracy_score(y_train, model.predict(X_train)))
print ("Multinomial Logistic regression Test Accuracy :: ", accuracy_score(y_test, model.predict(X_test)))

# accuracy decreased from 25% to 18% when 4 additional parameters were added to the regressor
# Make predictions on the test dataset
test_pred = model.predict_proba(X_test)
test_pred
# Calculate auc scores for performance evaluation
# AUROC score is one of the preferred metrics for multi-class classification models evaluation
# https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html#sklearn.metrics.roc_auc_score
auc_score = roc_auc_score(y_test, test_pred, multi_class='ovr')

print(f'The Multinomial Logistic regression ROC AUC score is {auc_score}')<jupyter_output>The Multinomial Logistic regression ROC AUC score is 0.8574921936774076<jupyter_text>`First round Accuracy is 0.25 while AUROC is 0.86 -->``this suggests that the model is predciting positive classes correctly but not the negative classes(?)`` it could be because ``    1. the data wasn't balanced - tried to use 'class_weight' but it decreased accuracy to 18%``    2. the model isn't the right type ``    3. flipping is required which would take accuracy to 75% ``    4. Increasingly the max_iterations did not have any positive impact on the model accuracy``https://stackoverflow.com/questions/38387913/reason-of-having-high-auc-and-low-accuracy-in-a-balanced-dataset`<jupyter_code># *** save scaler in the models folder called "scaler.joblib" for use next time
dump(model, '/Users/jasle1/Desktop/MDSI/ADSI/AT_2/adsi_at2/models/mlr_scaled_imbalanced_1st.joblib')

dump(model, '/Users/jasle1/Desktop/MDSI/ADSI/AT_2/api/models/mlr_scaled_imbalanced_1st.joblib')<jupyter_output><empty_output><jupyter_text>7. Test the App  If Docker is Running,  http://localhost:8080/docs otherwise, https://adsi-at2.herokuapp.com/docs<jupyter_code># either enter these values manually
brewery_name		            review_aroma	review_appearance	review_palate	review_taste	beer_abv       beer_style
<NAME>		                2	              2.5		            1.5	           1.5	        5	       Hefeweizen
Pacific Coast Brewing Company	    4	               4	                  4	            4	        10	       American Double / Imperial Stout
Caldera Brewing Company		     	4	               4		              4	            4	         7         American Strong Ale<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10485277521288601, 'fraction_numerical': 0.023391812865497075, 'mean_word_length': 5.375408763897973, 'pattern_counts': {'":': 0, '<': 60, '<?xml version=': 0, '>': 63, 'https://': 13, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '555711', 'license': 'FTL', 'n_tokens_mistral': 3500, 'n_tokens_neox': 3298, 'n_words': 741, 'path': 'notebooks/Kaur_Jasleen-13368028_AT2_LGR_Model_v1.ipynb', 'repo_name': 'JKaur1992/adsi_at2', 'size': '9756'}