<jupyter_start><jupyter_text>Import necessary dependencies<jupyter_code>import pandas as pd
import numpy as np
import text_normalizer as tn<jupyter_output><empty_output><jupyter_text>Load and normalize data<jupyter_code>dataset = pd.read_csv(r'movie_reviews_cleaned.csv')

# take a peek at the data
print(dataset.head())
reviews = np.array(dataset['review'])
sentiments = np.array(dataset['sentiment'])

# build train and test datasets
train_reviews = reviews[:35000]
train_sentiments = sentiments[:35000]
test_reviews = reviews[35000:]
test_sentiments = sentiments[35000:]

# normalize datasets
#norm_train_reviews = train_reviews#tn.normalize_corpus(train_reviews)
#norm_test_reviews = test_reviews#tn.normalize_corpus(test_reviews)<jupyter_output>review sentiment
0  not bother think would see movie great supspen...  negative
1  careful one get mitt change way look kung fu f...  positive
2  chili palmer tired movie know want success mus...  negative
3  follow little know 1998 british film make budg...  positive
4  dark angel cross huxley brave new world percys...  positive<jupyter_text>Build Text Classification Pipeline with The Best Model<jupyter_code>from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
import warnings
warnings.filterwarnings("ignore")

# build BOW features on train reviews
cv = CountVectorizer(binary=False, min_df=0.0, max_df=1.0, ngram_range=(1,2))
cv_train_features = cv.fit_transform(train_reviews)
# build Logistic Regression model
lr = LogisticRegression()
lr.fit(cv_train_features, train_sentiments)

# Build Text Classification Pipeline
lr_pipeline = make_pipeline(cv, lr)

# save the list of prediction classes (positive, negative)
classes = list(lr_pipeline.classes_)<jupyter_output><empty_output><jupyter_text>Analyze Model Prediction Probabilities<jupyter_code>lr_pipeline.predict(['the lord of the rings is an excellent movie', 
                     'i hated the recent movie on tv, it was so bad'])
pd.DataFrame(lr_pipeline.predict_proba(['the lord of the rings is an excellent movie', 
                     'i hated the recent movie on tv, it was so bad']), columns=classes)<jupyter_output><empty_output><jupyter_text>Interpreting Model Decisions<jupyter_code>import skater
from skater.core.local_interpretation.lime.lime_text import LimeTextExplainer
#https://www.oreilly.com/ideas/interpreting-predictive-models-with-skater-unboxing-model-opacity

explainer = LimeTextExplainer(class_names=classes)
def interpret_classification_model_prediction(doc_index, norm_corpus, corpus, 
                                              prediction_labels, explainer_obj):
    # display model prediction and actual sentiments
    print("Test document index: {index}\nActual sentiment: {actual}\nPredicted sentiment: {predicted}"
      .format(index=doc_index, actual=prediction_labels[doc_index],
              predicted=lr_pipeline.predict([norm_corpus[doc_index]])))
    # display actual review content
    print("\nReview:", corpus[doc_index])
    # display prediction probabilities
    print("\nModel Prediction Probabilities:")
    for probs in zip(classes, lr_pipeline.predict_proba([norm_corpus[doc_index]])[0]):
        print(probs)
    # display model prediction interpretation
    exp = explainer.explain_instance(norm_corpus[doc_index], 
                                     lr_pipeline.predict_proba, num_features=10, 
                                     labels=[1])
    exp.show_in_notebook()
doc_index = 100 
interpret_classification_model_prediction(doc_index=doc_index, norm_corpus=test_reviews,
                                         corpus=test_reviews, prediction_labels=test_sentiments,
                                         explainer_obj=explainer)
doc_index = 2000
interpret_classification_model_prediction(doc_index=doc_index, norm_corpus=norm_test_reviews,
                                         corpus=test_reviews, prediction_labels=test_sentiments,
                                         explainer_obj=explainer)
doc_index = 347 
interpret_classification_model_prediction(doc_index=doc_index, norm_corpus=norm_test_reviews,
                                         corpus=test_reviews, prediction_labels=test_sentiments,
                                         explainer_obj=explainer)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0774487471526196, 'fraction_numerical': 0.011161731207289294, 'mean_word_length': 4.006841505131129, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 20, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '555920', 'license': 'Apache-2.0', 'n_tokens_mistral': 1299, 'n_tokens_neox': 1243, 'n_words': 285, 'path': 'Day1/3_sentiment/Sentiment Causal Analysis - Model Interpretation.ipynb', 'repo_name': 'miltonsegura/ML1010_InClass', 'size': '4390'}