 ============================================================
# TEXT REPRESENTATION METHODS FOR SENTIMENT CLASSIFICATION
# BoW, CountVectorizer, TF-IDF, Word2Vec, Skip-Gram, GloVe
# Dataset: IMDB (Kaggle)
# ============================================================

# Install libraries
!pip install kaggle gensim scikit-learn nltk -q
import kagglehub
import numpy as np
import pandas as pd

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

from gensim.models import Word2Vec

import nltk
nltk.download('punkt')
nltk.download('punkt_tab') # Download missing resource

from nltk.tokenize import word_tokenize

# ============================================================
# DOWNLOAD DATASET FROM KAGGLE
# ============================================================


data_path = kagglehub.dataset_download("lakshmi25npathi/imdb-dataset-of-50k-movie-reviews")

print("Dataset Path:",data_path)

# Load the dataset into a pandas DataFrame
data = pd.read_csv(f"{data_path}/IMDB Dataset.csv")

# Convert sentiment labels
data['sentiment'] = data['sentiment'].map({
    'positive':1,
    'negative':0
})

# Reduce size for faster training
data = data.sample(30000, random_state=42)

X = data['review']
y = data['sentiment']

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# ============================================================
# 1 BAG OF WORDS / COUNT VECTORIZER
# ============================================================

print("\n===== CountVectorizer ====")

cv = CountVectorizer(max_features=5000)

X_train_cv = cv.fit_transform(X_train)
X_test_cv = cv.transform(X_test)

model_cv = LogisticRegression(max_iter=1000)

model_cv.fit(X_train_cv, y_train)

pred_cv = model_cv.predict(X_test_cv)

print("Accuracy:", accuracy_score(y_test, pred_cv))


# ============================================================
# 2 TF-IDF
# ============================================================

print("\n===== TF-IDF ====")

tfidf = TfidfVectorizer(max_features=5000)

X_train_tfidf = tfidf.fit_transform(X_train)
X_test_tfidf = tfidf.transform(X_test)

model_tfidf = LogisticRegression(max_iter=1000)

model_tfidf.fit(X_train_tfidf, y_train)

pred_tfidf = model_tfidf.predict(X_test_tfidf)

print("Accuracy:", accuracy_score(y_test, pred_tfidf))


# ============================================================
# TOKENIZE TEXT
# ============================================================

tokenized = [word_tokenize(text.lower()) for text in X_train]


# ============================================================
# 3 WORD2VEC (CBOW)
# ============================================================

print("\n===== Word2Vec (CBOW) ====")

w2v_model = Word2Vec(
    sentences=tokenized,
    vector_size=100,
    window=5,
    min_count=2,
    sg=0
)

def get_vector(text):

    words = word_tokenize(text.lower())
    vectors = []

    for word in words:
        if word in w2v_model.wv:
            vectors.append(w2v_model.wv[word])

    if len(vectors) == 0:
        return np.zeros(100)

    return np.mean(vectors, axis=0)

X_train_w2v = np.array([get_vector(t) for t in X_train])
X_test_w2v = np.array([get_vector(t) for t in X_test])

model_w2v = LogisticRegression(max_iter=1000)

model_w2v.fit(X_train_w2v, y_train)

pred_w2v = model_w2v.predict(X_test_w2v)

print("Accuracy:", accuracy_score(y_test, pred_w2v))


# ============================================================
# 4 SKIP-GRAM WORD2VEC
# ============================================================

print("\n===== Word2Vec Skip-Gram ====")

skip_model = Word2Vec(
    sentences=tokenized,
    vector_size=100,
    window=5,
    min_count=2,
    sg=1
)

def get_skip_vector(text):

    words = word_tokenize(text.lower())
    vectors = []

    for word in words:
        if word in skip_model.wv:
            vectors.append(skip_model.wv[word])

    if len(vectors) == 0:
        return np.zeros(100)

    return np.mean(vectors, axis=0)

X_train_skip = np.array([get_skip_vector(t) for t in X_train])
X_test_skip = np.array([get_skip_vector(t) for t in X_test])

model_skip = LogisticRegression(max_iter=1000)

model_skip.fit(X_train_skip, y_train)

pred_skip = model_skip.predict(X_test_skip)

print("Accuracy:", accuracy_score(y_test, pred_skip))


# ============================================================
# 5 GLOVE EMBEDDINGS
# ============================================================

print("\n===== GloVe ====")

!wget http://nlp.stanford.edu/data/glove.6B.zip
!unzip glove.6B.zip

embedding_index = {}

with open("glove.6B.100d.txt", encoding="utf8") as f:

    for line in f:

        values = line.split()
        word = values[0]
        vector = np.asarray(values[1:], dtype='float32')
        embedding_index[word] = vector


def glove_vector(text):

    words = word_tokenize(text.lower())
    vectors = []

    for word in words:
        if word in embedding_index:
            vectors.append(embedding_index[word])

    if len(vectors) == 0:
        return np.zeros(100)

    return np.mean(vectors, axis=0)

X_train_glove = np.array([glove_vector(t) for t in X_train])
X_test_glove = np.array([glove_vector(t) for t in X_test])

model_glove = LogisticRegression(max_iter=1000)

model_glove.fit(X_train_glove, y_train)

pred_glove = model_glove.predict(X_test_glove)

print("Accuracy:", accuracy_score(y_test, pred_glove))