# sentiment_analysis_poc.py
# Proof-of-Concept for Sentiment Analysis Recommendation
# Based on the report: "Recommendation of a Sentiment Analysis ML model"

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, StratifiedKFold, cross_val_predict
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_selection import SelectKBest, chi2
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, precision_recall_fscore_support, accuracy_score
import matplotlib.pyplot as plt

# --- 1. DATA ACQUISITION & PREPROCESSING ---
print("1. Loading and preparing data...")
print("   Loading reviews from 'reviews.tsv'...")

# Load the real dataset
df = pd.read_csv('reviews.tsv', delimiter='\t', header=None, names=['sentiment', 'text'])

# Let's work with a smaller sample for speed in the demo (e.g., 500 reviews)
df = df.sample(n=500, random_state=42).reset_index(drop=True)

print(f"   Loaded {len(df)} reviews.")
print(f"   Sample of the data:")
print(df.head())

# --- 2. FEATURE ENGINEERING ---
print("\n2. Engineering features using TF-IDF...")
# TF-IDF Vectorization with Uni-grams and Bi-grams
tfidf = TfidfVectorizer(ngram_range=(1, 2), max_features=5000)  # Using top 5000 features
X_tfidf = tfidf.fit_transform(df['text'])
y = df['sentiment']

print(f"   Original feature space: {X_tfidf.shape[1]} n-gram features")

# --- 3. FEATURE SELECTION ---
print("\n3. Selecting most informative features using Chi-Square...")
k = 1000  # Select top 1000 features
chi2_selector = SelectKBest(chi2, k=k)
X = chi2_selector.fit_transform(X_tfidf, y)

print(f"   Reduced feature space: {X.shape[1]} features after Chi-square selection")

# --- 4. MODEL TRAINING & VALIDATION ---
print("\n4. Training and validating Logistic Regression model...")
# Initialize the recommended model
model = LogisticRegression(random_state=42, solver='liblinear', max_iter=1000)

# Use Stratified 5-Fold Cross-Validation
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

# Get cross-validated predictions to evaluate performance
cv_predictions = cross_val_predict(model, X, y, cv=skf)

# --- 5. MODEL EVALUATION ---
print("\n5. Evaluating model performance...")
print("\n" + "="*60)
print("CROSS-VALIDATION RESULTS (Stratified 5-Fold)")
print("="*60)

# Calculate metrics
accuracy = accuracy_score(y, cv_predictions)
precision, recall, f1, _ = precision_recall_fscore_support(y, cv_predictions, average='binary')

print(f"Accuracy:  {accuracy:.3f}")
print(f"Precision: {precision:.3f}")
print(f"Recall:    {recall:.3f}")
print(f"F1-Score:  {f1:.3f}")

print("\nDetailed Classification Report:")
print(classification_report(y, cv_predictions, target_names=['Negative', 'Positive']))

# --- 6. TRAIN FINAL MODEL & DEMONSTRATE ---
print("\n6. Training final model on all data and demonstrating prediction...")
# Train the final model on all data
final_model = LogisticRegression(random_state=42, solver='liblinear', max_iter=1000)
final_model.fit(X, y)

# Demonstrate prediction on new text
def predict_sentiment(text):
    # Transform the text using the same TF-IDF and feature selection
    text_tfidf = tfidf.transform([text])
    text_features = chi2_selector.transform(text_tfidf)
    
    prediction = final_model.predict(text_features)[0]
    probability = final_model.predict_proba(text_features)[0]
    
    sentiment = "Positive" if prediction == 1 else "Negative"
    confidence = probability[prediction]
    
    return sentiment, confidence

# Test the model with some example reviews
test_reviews = [
    "This movie is fantastic and has brilliant acting!",
    "A boring and terrible film with no plot.",
    "It was okay, not great but not awful either."
]

print("\n" + "="*50)
print("PREDICTION DEMONSTRATION")
print("="*50)
for review in test_reviews:
    sentiment, confidence = predict_sentiment(review)
    print(f"Review: '{review}'")
    print(f"--> Predicted: {sentiment} (Confidence: {confidence:.3f})\n")

# --- 7. MODEL INTERPRETABILITY (Key Feature Weights) ---
print("\n7. Model Interpretability - Top Predictive Features:")
# Get feature names after TF-IDF and Chi-square selection
feature_names = tfidf.get_feature_names_out()
selected_features = feature_names[chi2_selector.get_support()]

# Get coefficients from the trained model
coefficients = final_model.coef_[0]

# Create a DataFrame for better visualization
feature_importance = pd.DataFrame({
    'feature': selected_features,
    'coefficient': coefficients
})

# Show top 10 positive and negative features
print("\nTop 5 Positive Sentiment Indicators:")
top_positive = feature_importance.nlargest(5, 'coefficient')
for _, row in top_positive.iterrows():
    print(f"  '{row['feature']}': {row['coefficient']:.3f}")

print("\nTop 5 Negative Sentiment Indicators:")
top_negative = feature_importance.nsmallest(5, 'coefficient')
for _, row in top_negative.iterrows():
    print(f"  '{row['feature']}': {row['coefficient']:.3f}")

print("\n" + "="*60)
print("PROOF-OF-COMPLETION: All recommended workflow steps successfully implemented!")
print("="*60)

# Keep the plot window open
plt.show()