SanjanaSuryadevara/Sentiment_Analysis_using_Word2Vector
0
1# ---------------------------------------------------------2# ๐ฌ Sentiment Analysis App (Word2Vec)3# ---------------------------------------------------------4import streamlit as st5import pandas as pd6import numpy as np7import re8import nltk9from nltk.stem import WordNetLemmatizer10from nltk.corpus import stopwords11from sklearn.model_selection import train_test_split12from sklearn.metrics import accuracy_score, confusion_matrix, classification_report13from sklearn.ensemble import RandomForestClassifier14from gensim.models import Word2Vec15import matplotlib.pyplot as plt16import seaborn as sns17 18# Optional: SMOTE for imbalance19from imblearn.over_sampling import SMOTE20 21# ---------------------------------------------------------22# Download NLTK Resources23# ---------------------------------------------------------24nltk.download('wordnet')25nltk.download('omw-1.4')26nltk.download('stopwords')27 28stop_words = set(stopwords.words('english'))29 30# ---------------------------------------------------------31# Page Design & Custom CSS32# ---------------------------------------------------------33def add_custom_styles():34 st.markdown(35 f"""36 <style>37 .stApp {{38 background-image: 39 linear-gradient(rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.85)),40 url("https://images.unsplash.com/photo-1506744038136-46273834b3fb?auto=format&fit=crop&w=1470&q=80");41 background-attachment: fixed;42 background-size: cover;43 background-position: center;44 }}45 textarea {{46 font-size: 20px !important;47 font-weight: 900 !important;48 color: black !important;49 }}50 textarea::placeholder {{51 color: black !important;52 font-weight: 900 !important;53 font-size: 20px !important;54 }}55 </style>56 """,57 unsafe_allow_html=True58 )59 60add_custom_styles()61 62# ---------------------------------------------------------63# Data Loading & Preprocessing64# ---------------------------------------------------------65@st.cache_data66def load_and_preprocess():67 df = pd.read_csv("comments_with_sentiment.csv")68 69 # Remove rows where 'Comment' is missing or empty70 df['Comment'] = df['Comment'].astype(str).str.strip()71 df = df[df['Comment'] != '']72 73 # Check if Sentiment column exists74 if 'Sentiment Analysis' not in df.columns:75 raise KeyError("Column 'Sentiment Analysis' not found in CSV!")76 df['Sentiment Analysis'] = df['Sentiment Analysis'].fillna('Neutral')77 78 # Drop duplicate comments79 df = df.drop_duplicates(subset=['Comment'])80 81 # Clean text82 df['Comment'] = df['Comment'].str.lower()83 df['Comment'] = df['Comment'].apply(lambda x: re.sub(r'[^a-z\s]', '', x)).str.strip()84 85 # Tokenize & Lemmatize, remove stopwords86 lemmatizer = WordNetLemmatizer()87 df['tokens'] = df['Comment'].apply(88 lambda x: [lemmatizer.lemmatize(word) for word in x.split() if word not in stop_words]89 )90 91 return df92 93# ---------------------------------------------------------94# Custom Word2Vec Transformer95# ---------------------------------------------------------96class Word2VecVectorizer:97 def __init__(self, vector_size=100, window=5, min_count=2, sg=1):98 self.vector_size = vector_size99 self.window = window100 self.min_count = min_count101 self.sg = sg102 self.w2v_model = None103 104 def fit(self, texts):105 self.w2v_model = Word2Vec(106 sentences=texts,107 vector_size=self.vector_size,108 window=self.window,109 min_count=self.min_count,110 sg=self.sg,111 workers=4112 )113 return self114 115 def transform(self, texts):116 def document_vector(tokens):117 tokens = [t for t in tokens if t in self.w2v_model.wv]118 if len(tokens) == 0:119 return np.random.normal(size=self.vector_size)120 return np.mean(self.w2v_model.wv[tokens], axis=0)121 return np.array([document_vector(t) for t in texts])122 123# ---------------------------------------------------------124# Train Model Pipeline125# ---------------------------------------------------------126@st.cache_resource127def train_pipeline(df):128 X = df['tokens']129 y = df['Sentiment Analysis']130 131 X_train, X_test, y_train, y_test = train_test_split(132 X, y, test_size=0.2, random_state=42, stratify=y133 )134 135 w2v_vectorizer = Word2VecVectorizer(vector_size=100, window=5, min_count=2, sg=1)136 w2v_vectorizer.fit(X_train)137 138 X_train_vec = w2v_vectorizer.transform(X_train)139 X_test_vec = w2v_vectorizer.transform(X_test)140 141 # SMOTE to handle imbalance142 smote = SMOTE(random_state=42)143 X_train_vec, y_train = smote.fit_resample(X_train_vec, y_train)144 145 clf = RandomForestClassifier(146 n_estimators=500,147 max_depth=15,148 random_state=42,149 class_weight='balanced'150 )151 clf.fit(X_train_vec, y_train)152 y_pred = clf.predict(X_test_vec)153 154 acc = accuracy_score(y_test, y_pred)155 return w2v_vectorizer, clf, acc156 157# ---------------------------------------------------------158# Streamlit App UI159# ---------------------------------------------------------160st.markdown("## ๐ฌโจ **Sentiment Analysis** โจ๐ฌ")161st.markdown("##### ๐ก Enter a comment to analyze its sentiment using Word2Vec")162 163# Load & preprocess data164df = load_and_preprocess()165 166# Train model pipeline167vectorizer, model, acc = train_pipeline(df)168st.success(f"โ
Model trained successfully with Accuracy: **{acc:.2f}**")169 170# User input171user_input = st.text_area("๐ฌ Enter your comment here:", key="user_input")172 173if st.button("๐ง Predict Sentiment"):174 lemmatizer = WordNetLemmatizer()175 cleaned = re.sub(r'[^a-z\s]', '', user_input.lower()).strip()176 tokens = [lemmatizer.lemmatize(word) for word in cleaned.split() if word not in stop_words]177 vec = vectorizer.transform([tokens])178 prediction = model.predict(vec)[0]179 180 # Dynamic button color181 color = "#4CAF50" # Green for Positive182 if prediction.lower() == "neutral":183 color = "#2196F3" # Blue184 elif prediction.lower() == "negative":185 color = "#F44336" # Red186 187 st.markdown(188 f"""189 <div style="padding: 10px; text-align: center; background-color: {color}; 190 color: white; font-size: 22px; font-weight: 900; border-radius: 10px;">191 ๐ฏ Predicted Sentiment: {prediction}192 </div>193 """,194 unsafe_allow_html=True195 )196 