# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# ## Import Libraries

# +
import pandas as pd  
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight')

# %matplotlib inline
# %config InlineBackend.figure_format = 'retina'
# -

# ## Load Data

csv = 'clean_tweet.csv'
my_df = pd.read_csv(csv,index_col=0)
my_df.head()

my_df.dropna(inplace=True)
my_df.reset_index(drop=True,inplace=True)
my_df.info()

# ### Defining Input and Output for the Model

x = my_df.text
y = my_df.target

# ### Train Test Split with 80% - 20%

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
from time import time
SEED = 2000
x_train, x_validation_and_test, y_train, y_validation_and_test = train_test_split(x, y, test_size=.02, random_state=SEED)
x_validation, x_test, y_validation, y_test = train_test_split(x_validation_and_test, y_validation_and_test, test_size=.5, random_state=SEED)


def accuracy_summary(pipeline, x_train, y_train, x_test, y_test):
    t0 = time()
    sentiment_fit = pipeline.fit(x_train, y_train)
    y_pred = sentiment_fit.predict(x_test)
    train_test_time = time() - t0
    accuracy = accuracy_score(y_test, y_pred)
    print("accuracy score: {0:.2f}%".format(accuracy*100))
    print("train and test time: {0:.2f}s".format(train_test_time))
    print("-"*80)
    return accuracy, train_test_time, sentiment_fit


# +
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
cvec = CountVectorizer()
lr = LogisticRegression()
n_features = np.arange(10000,100001,10000)

def nfeature_accuracy_checker(vectorizer=cvec, n_features=n_features, stop_words=None, ngram_range=(1, 1), classifier=lr):
    result = []
    print (classifier)
    print ("\n")
    for n in n_features:
        vectorizer.set_params(stop_words=stop_words, max_features=n, ngram_range=ngram_range)
        checker_pipeline = Pipeline([
            ('vectorizer', vectorizer),
            ('classifier', classifier)
        ])
        print("Validation result for {} features".format(n))
        nfeature_accuracy,tt_time,_ = accuracy_summary(checker_pipeline, x_train, y_train, x_validation, y_validation)
        result.append((n,nfeature_accuracy,tt_time))
    return result


# -

# ### TFIDF Vectorizer

# TF-IDF is another way to convert textual data to a numeric form and is short for Term Frequency-Inverse Document Frequency. The vector value it yields is the product of these two terms; TF and IDF.

# Let's first look at Term Frequency. We have already looked at term frequency above with count vectorizer, but this time, we need one more step to calculate the relative frequency. Let's say we have two documents in total as below.
#
# 1. I love dogs
# 2. I hate dogs and knitting

# Relative term frequency is calculated for each term within each document as below.
#
# $${TF(t,d)} = \frac {number\ of\ times\ term(t)\ appears\ in\ document(d)}{total\ number\ of\ terms\ in\ document(d)}$$

# For example, if we calculate relative term frequency for 'I' in both document 1 and document 2, it will be as below.
#
# $${TF('I',d1)} = \frac {1}{3} \approx {0.33}$$
#
# $${TF('I',d2)} = \frac {1}{5} = {0.2}$$

# Next, we need to get Inverse Document Frequency, which measures how important a word is to differentiate each document by following the calculation as below.
#
# $${IDF(t,D)} = \log \Big(\frac {total\ number\ of\ documents(D)}{number\ of\ documents\ with\ the\ term(t)\ in\ it}\Big)$$

# If we calculate inverse document frequency for 'I',
#
# $${IDF('I',D)} = \log \Big(\frac {2}{2}\Big) = {0}$$

# Once we have the values for TF and IDF, now we can calculate TFIDF as below.
#
# $${TFIDF(t,d,D)} = {TF(t,d)}\cdot{IDF(t,D)}$$

# Following the case of our example, TFIDF for term 'I' in both documents will be as below.
#
# $${TFIDF('I',d1,D)} = {TF('I',d1)}\cdot{IDF('I',D)} = {0.33}\times{0} = {0}$$
#
# $${TFIDF('I',d2,D)} = {TF('I',d2)}\cdot{IDF('I',D)} = {0.2}\times{0} = {0}$$

# As you can see, the term 'I' appeared equally in both documents, and the TFIDF score is 0, which means the term is not really informative in differentiating documents. The rest is same as count vectorizer, TFIDF vectorizer will calculate these scores for terms in documents, and convert textual data into a numeric form.

# #### How does Uni-Gram, Bi-Gram, Tri-Gram tokens work as the vocabulory of the dataset?

from sklearn.feature_extraction.text import TfidfVectorizer
tvec = TfidfVectorizer()
ttvec = TfidfVectorizer(ngram_range=(1,3))
ttvec.fit(["an apple a day keeps the doctor away"])
print(ttvec.vocabulary_)

# ## Evaluting what Feature Size (Vocabulory Size) and Token Method (Uni-Gram, Bi-Gram, Tri-Gram) works best on the dataset

# %%time
print("RESULT FOR UNIGRAM WITH STOP WORDS (Tfidf)\n")
feature_result_ugt = nfeature_accuracy_checker(vectorizer=tvec)

# %%time
print("RESULT FOR BIGRAM WITH STOP WORDS (Tfidf)\n")
feature_result_bgt = nfeature_accuracy_checker(vectorizer=tvec,ngram_range=(1, 2))

# %%time
print("RESULT FOR TRIGRAM WITH STOP WORDS (Tfidf)\n")
feature_result_tgt = nfeature_accuracy_checker(vectorizer=tvec,ngram_range=(1, 3))

# It seems like TFIDF vectorizer is yielding better results when fed to logistic regression. Let's plot the results from  together with TFIDF vectorizer.

# +
nfeatures_plot_tgt = pd.DataFrame(feature_result_tgt,columns=['nfeatures','validation_accuracy','train_test_time'])
nfeatures_plot_bgt = pd.DataFrame(feature_result_bgt,columns=['nfeatures','validation_accuracy','train_test_time'])
nfeatures_plot_ugt = pd.DataFrame(feature_result_ugt,columns=['nfeatures','validation_accuracy','train_test_time'])

plt.figure(figsize=(8,6))
plt.plot(nfeatures_plot_tgt.nfeatures, nfeatures_plot_tgt.validation_accuracy,label='trigram tfidf vectorizer',color='royalblue')
plt.plot(nfeatures_plot_bgt.nfeatures, nfeatures_plot_bgt.validation_accuracy,label='bigram tfidf vectorizer',color='orangered')
plt.plot(nfeatures_plot_ugt.nfeatures, nfeatures_plot_ugt.validation_accuracy, label='unigram tfidf vectorizer',color='gold')
plt.title("N-gram(1~3) test result : Accuracy")
plt.xlabel("Number of features")
plt.ylabel("Validation set accuracy")
plt.legend()
# -

# From above chart, we can see including bigram and trigram boost the model performance both in count vectorizer and TFIDF vectorizer. And for every case of unigram to trigram, TFIDF yields better results than count vectorizer.

# ## Model Training

names = ["Logistic Regression"]
classifiers = [
    LogisticRegression()
    ]
zipped_clf = zip(names,classifiers)

tvec = TfidfVectorizer()
def classifier_comparator(vectorizer=tvec, n_features=10000, stop_words=None, ngram_range=(1, 1), classifier=zipped_clf):
    result = []
    model= None
    vectorizer.set_params(stop_words=stop_words, max_features=n_features, ngram_range=ngram_range)
    for n,c in classifier:
        checker_pipeline = Pipeline([
            ('vectorizer', vectorizer),
            ('classifier', c)
        ])
        print("Validation result for {}".format(n))
        print(c)
        clf_accuracy,tt_time, model = accuracy_summary(checker_pipeline, x_train, y_train, x_validation, y_validation)
        result.append((n,clf_accuracy,tt_time))
    return result, model


# %%time
trigram_result, model = classifier_comparator(n_features=100000,ngram_range=(1,3))

print(trigram_result)

# ### Testing Training Model on some other tweets for Sanity Testing

# +
sentences = ["The weather is not very well today. i wish it was raining",
             "a real bad example of customer engagement",
             "glad to be part of the venture"]

predictions = []
predictions_conf = []

for s in sentences:
    predictions.append(model.predict(pd.Series(s)))
    predictions_conf.append(model.predict_proba(pd.Series(s)))

print(model.classes_)
#print(predictions, predictions_conf)
# print("%s %s %s %s")
i = 1
for p, pc in zip(predictions, predictions_conf):
    print("Tweet {} is classified as {} with confidence (0,1) {}".format(i, p, pc))
    i = i+1


StarcoderdataJupyterScriptsDedupFiltered