Markndrei commited on
Commit
d5b795c
·
verified ·
1 Parent(s): 6abc5e8

uploading model

Browse files
Files changed (3) hide show
  1. SA_model.pkl +3 -0
  2. app.py +128 -0
  3. model.ipynb +721 -0
SA_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d379ad2f488dc26887b9ab48c3529838564c21bea545d0052ada39f4408dd8ce
3
+ size 1547944
app.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # import libraries
2
+ import streamlit as st
3
+ import pandas as pd
4
+ import matplotlib.pyplot as plt
5
+ import seaborn as sns
6
+ import joblib
7
+ from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
8
+ from sklearn.model_selection import train_test_split
9
+
10
+ #load model
11
+ import joblib
12
+
13
+ @st.cache_resource # Caches the model in Streamlit's memory
14
+ def load_model():
15
+ return joblib.load("SA_model.pkl") # Ensure your model is saved and available
16
+
17
+ model = load_model()
18
+
19
+
20
+
21
+ #load dataset
22
+ df = pd.read_csv('Tweets.csv', encoding='utf-8')
23
+ X = df['text']
24
+ y = df['airline_sentiment']
25
+ X_train, X_test, y_train, y_test = train_test_split(
26
+ X, y , test_size=0.33, random_state=42
27
+ )
28
+
29
+
30
+ #compute sentiment
31
+ class_report_data = {
32
+ "Precision": [0.67, 0.51, 0.88],
33
+ "Recall": [0.73, 0.64, 0.79],
34
+ "F1-score": [0.70, 0.57, 0.83]
35
+ }
36
+
37
+ # Properly structured DataFrame
38
+ class_report_df = pd.DataFrame(class_report_data, index=["Positive", "Neutral", "Negative"])
39
+
40
+ #predict text sentiment
41
+ def predict_sentiment(text):
42
+ if isinstance(text, str):
43
+ text = [text] # Ensure input is a list
44
+
45
+ prediction = model.predict(text) # Get numerical prediction
46
+
47
+ # Mapping numerical labels to sentiment categories
48
+ sentiment_mapping = {0: "Negative", 1: "Neutral", 2: "Positive"}
49
+
50
+ return sentiment_mapping.get(prediction[0], "Unknown") # Convert number to label
51
+
52
+
53
+
54
+ #Model Introduction
55
+ st.title('📌 Sentiment Analysis Web Application')
56
+
57
+ st.markdown(
58
+ """
59
+ ## 📖 Introduction
60
+ Welcome to the **Sentiment Analysis Web Application**! This tool is designed to analyze the sentiment of text messages
61
+ using a **Support Vector Machine (SVM) model**. The model has been trained on the **Airline Tweets dataset from Kaggle**
62
+ and classifies text into three sentiment categories:
63
+ - ✅ **Positive**
64
+ - ❌ **Negative**
65
+ - ⚖ **Neutral**
66
+ """
67
+ )
68
+
69
+ #Tab Structuring
70
+
71
+ tab1, tab2, tab3 = st.tabs(['📊 Dataset Preview', '📈 Model Performance', '🔍 Sentiment Prediction'])
72
+
73
+ with tab1:
74
+ st.markdown(
75
+ """
76
+ ## 📊 Dataset Preview
77
+ The dataset used for training this model consists of tweets related to airline services. Each tweet is labeled
78
+ with one of the three sentiment categories (**Positive, Negative, or Neutral**). Below is a sample of the dataset:
79
+ """
80
+ )
81
+ st.write (df)
82
+
83
+
84
+ with tab2:
85
+ st.markdown(
86
+ """
87
+ ## 📈 Model Performance
88
+ Below are the key performance metrics of the trained **Support Vector Machine (SVM)** model:
89
+
90
+ - **Model Accuracy**: The percentage of correctly classified instances.
91
+ - **Classification Report**: Includes precision and recall for each sentiment class.
92
+ - **Confusion Matrix**: A visual representation comparing actual versus predicted classifications.
93
+ """
94
+ )
95
+
96
+ st.write(f"**📌 Model Accuracy:** 75%")
97
+
98
+ st.markdown("### 📋 Classification Report")
99
+ st.dataframe(class_report_df)
100
+
101
+ st.markdown("### 🔢 Confusion Matrix")
102
+
103
+ # Load and display confusion matrix image
104
+ cm_image_path = "cmap.png"
105
+ try:
106
+ st.image(cm_image_path, caption="Confusion Matrix", use_container_width=True)
107
+ except FileNotFoundError:
108
+ st.warning("⚠️ Confusion matrix image not found. Please check the file path.")
109
+
110
+
111
+
112
+
113
+ with tab3:
114
+ st.markdown(
115
+ """
116
+ ## 🔍 Sentiment Prediction
117
+ Type a sentence in the text box below, and the model will classify it as **Positive, Neutral, or Negative**.
118
+ """
119
+ )
120
+
121
+ user_input = st.text_area("Type your sentence here:", "")
122
+
123
+ if st.button("🔎 Analyze Sentiment"):
124
+ if user_input.strip():
125
+ sentiment_result = predict_sentiment(user_input)
126
+ st.success(f"### 🎯 Prediction: **{sentiment_result}**")
127
+ else:
128
+ st.warning("⚠️ Please enter a valid text input.")
model.ipynb ADDED
@@ -0,0 +1,721 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "## This Model Allows Sentiment Analysis using Support Vector Machine Algorithm"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "markdown",
12
+ "metadata": {},
13
+ "source": [
14
+ "#### This model is comprised of different steps as listed below:\n",
15
+ "1. Importing Libraries\n",
16
+ "2. Data Loading\n",
17
+ "3. Data Cleaning\n",
18
+ "4. Data Preprocessing\n",
19
+ "5. Train Test Split\n",
20
+ "6. Model Training\n",
21
+ "7. Model Evaluation\n",
22
+ "8. Pickle Export"
23
+ ]
24
+ },
25
+ {
26
+ "cell_type": "markdown",
27
+ "metadata": {},
28
+ "source": [
29
+ "#### Importing Libraries"
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "code",
34
+ "execution_count": 55,
35
+ "metadata": {},
36
+ "outputs": [],
37
+ "source": [
38
+ "import numpy as np\n",
39
+ "import pandas as pd\n",
40
+ "import matplotlib.pyplot as plt\n",
41
+ "import seaborn as sns\n",
42
+ "from sklearn import svm\n",
43
+ "from sklearn.model_selection import train_test_split\n",
44
+ "from sklearn.metrics import accuracy_score, classification_report, confusion_matrix, ConfusionMatrixDisplay\n",
45
+ "from sklearn.feature_extraction.text import TfidfVectorizer\n",
46
+ "from sklearn.pipeline import Pipeline\n",
47
+ "import joblib"
48
+ ]
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "#### Data Load"
55
+ ]
56
+ },
57
+ {
58
+ "cell_type": "code",
59
+ "execution_count": 56,
60
+ "metadata": {},
61
+ "outputs": [],
62
+ "source": [
63
+ "df = pd.read_csv('Tweets.csv') # Load dataset\n",
64
+ "df = df[['text', 'airline_sentiment']] # Ensure these columns exist"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "markdown",
69
+ "metadata": {},
70
+ "source": [
71
+ "#### Data Cleaning"
72
+ ]
73
+ },
74
+ {
75
+ "cell_type": "code",
76
+ "execution_count": 57,
77
+ "metadata": {},
78
+ "outputs": [
79
+ {
80
+ "name": "stdout",
81
+ "output_type": "stream",
82
+ "text": [
83
+ "0\n"
84
+ ]
85
+ }
86
+ ],
87
+ "source": [
88
+ "print(df['airline_sentiment'].isnull().sum())"
89
+ ]
90
+ },
91
+ {
92
+ "cell_type": "code",
93
+ "execution_count": 58,
94
+ "metadata": {},
95
+ "outputs": [],
96
+ "source": [
97
+ "df = df.dropna(subset=['airline_sentiment'])\n",
98
+ "df['airline_sentiment'] = df['airline_sentiment'].map({\n",
99
+ " 'positive': 2,\n",
100
+ " 'neutral': 1,\n",
101
+ " 'negative': 0\n",
102
+ "})"
103
+ ]
104
+ },
105
+ {
106
+ "cell_type": "markdown",
107
+ "metadata": {},
108
+ "source": [
109
+ "#### Train Test Split"
110
+ ]
111
+ },
112
+ {
113
+ "cell_type": "code",
114
+ "execution_count": 59,
115
+ "metadata": {},
116
+ "outputs": [],
117
+ "source": [
118
+ "# Split dataset\n",
119
+ "X = df['text']\n",
120
+ "y = df['airline_sentiment']\n",
121
+ "X_train, X_test, y_train, y_test = train_test_split(\n",
122
+ " X, y , test_size=0.33, random_state=42\n",
123
+ ")"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "markdown",
128
+ "metadata": {},
129
+ "source": [
130
+ "#### Model Training"
131
+ ]
132
+ },
133
+ {
134
+ "cell_type": "code",
135
+ "execution_count": 60,
136
+ "metadata": {},
137
+ "outputs": [],
138
+ "source": [
139
+ "#model pipelining\n",
140
+ "\n",
141
+ "model = Pipeline([\n",
142
+ " ('tfidf', TfidfVectorizer(max_features=10000, ngram_range=(1,2), stop_words='english')),\n",
143
+ " ('svm', svm.SVC(kernel='linear', probability=True, class_weight='balanced'))])"
144
+ ]
145
+ },
146
+ {
147
+ "cell_type": "code",
148
+ "execution_count": 61,
149
+ "metadata": {},
150
+ "outputs": [
151
+ {
152
+ "data": {
153
+ "text/html": [
154
+ "<style>#sk-container-id-2 {\n",
155
+ " /* Definition of color scheme common for light and dark mode */\n",
156
+ " --sklearn-color-text: #000;\n",
157
+ " --sklearn-color-text-muted: #666;\n",
158
+ " --sklearn-color-line: gray;\n",
159
+ " /* Definition of color scheme for unfitted estimators */\n",
160
+ " --sklearn-color-unfitted-level-0: #fff5e6;\n",
161
+ " --sklearn-color-unfitted-level-1: #f6e4d2;\n",
162
+ " --sklearn-color-unfitted-level-2: #ffe0b3;\n",
163
+ " --sklearn-color-unfitted-level-3: chocolate;\n",
164
+ " /* Definition of color scheme for fitted estimators */\n",
165
+ " --sklearn-color-fitted-level-0: #f0f8ff;\n",
166
+ " --sklearn-color-fitted-level-1: #d4ebff;\n",
167
+ " --sklearn-color-fitted-level-2: #b3dbfd;\n",
168
+ " --sklearn-color-fitted-level-3: cornflowerblue;\n",
169
+ "\n",
170
+ " /* Specific color for light theme */\n",
171
+ " --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
172
+ " --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
173
+ " --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
174
+ " --sklearn-color-icon: #696969;\n",
175
+ "\n",
176
+ " @media (prefers-color-scheme: dark) {\n",
177
+ " /* Redefinition of color scheme for dark theme */\n",
178
+ " --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
179
+ " --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
180
+ " --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
181
+ " --sklearn-color-icon: #878787;\n",
182
+ " }\n",
183
+ "}\n",
184
+ "\n",
185
+ "#sk-container-id-2 {\n",
186
+ " color: var(--sklearn-color-text);\n",
187
+ "}\n",
188
+ "\n",
189
+ "#sk-container-id-2 pre {\n",
190
+ " padding: 0;\n",
191
+ "}\n",
192
+ "\n",
193
+ "#sk-container-id-2 input.sk-hidden--visually {\n",
194
+ " border: 0;\n",
195
+ " clip: rect(1px 1px 1px 1px);\n",
196
+ " clip: rect(1px, 1px, 1px, 1px);\n",
197
+ " height: 1px;\n",
198
+ " margin: -1px;\n",
199
+ " overflow: hidden;\n",
200
+ " padding: 0;\n",
201
+ " position: absolute;\n",
202
+ " width: 1px;\n",
203
+ "}\n",
204
+ "\n",
205
+ "#sk-container-id-2 div.sk-dashed-wrapped {\n",
206
+ " border: 1px dashed var(--sklearn-color-line);\n",
207
+ " margin: 0 0.4em 0.5em 0.4em;\n",
208
+ " box-sizing: border-box;\n",
209
+ " padding-bottom: 0.4em;\n",
210
+ " background-color: var(--sklearn-color-background);\n",
211
+ "}\n",
212
+ "\n",
213
+ "#sk-container-id-2 div.sk-container {\n",
214
+ " /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
215
+ " but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
216
+ " so we also need the `!important` here to be able to override the\n",
217
+ " default hidden behavior on the sphinx rendered scikit-learn.org.\n",
218
+ " See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
219
+ " display: inline-block !important;\n",
220
+ " position: relative;\n",
221
+ "}\n",
222
+ "\n",
223
+ "#sk-container-id-2 div.sk-text-repr-fallback {\n",
224
+ " display: none;\n",
225
+ "}\n",
226
+ "\n",
227
+ "div.sk-parallel-item,\n",
228
+ "div.sk-serial,\n",
229
+ "div.sk-item {\n",
230
+ " /* draw centered vertical line to link estimators */\n",
231
+ " background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
232
+ " background-size: 2px 100%;\n",
233
+ " background-repeat: no-repeat;\n",
234
+ " background-position: center center;\n",
235
+ "}\n",
236
+ "\n",
237
+ "/* Parallel-specific style estimator block */\n",
238
+ "\n",
239
+ "#sk-container-id-2 div.sk-parallel-item::after {\n",
240
+ " content: \"\";\n",
241
+ " width: 100%;\n",
242
+ " border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
243
+ " flex-grow: 1;\n",
244
+ "}\n",
245
+ "\n",
246
+ "#sk-container-id-2 div.sk-parallel {\n",
247
+ " display: flex;\n",
248
+ " align-items: stretch;\n",
249
+ " justify-content: center;\n",
250
+ " background-color: var(--sklearn-color-background);\n",
251
+ " position: relative;\n",
252
+ "}\n",
253
+ "\n",
254
+ "#sk-container-id-2 div.sk-parallel-item {\n",
255
+ " display: flex;\n",
256
+ " flex-direction: column;\n",
257
+ "}\n",
258
+ "\n",
259
+ "#sk-container-id-2 div.sk-parallel-item:first-child::after {\n",
260
+ " align-self: flex-end;\n",
261
+ " width: 50%;\n",
262
+ "}\n",
263
+ "\n",
264
+ "#sk-container-id-2 div.sk-parallel-item:last-child::after {\n",
265
+ " align-self: flex-start;\n",
266
+ " width: 50%;\n",
267
+ "}\n",
268
+ "\n",
269
+ "#sk-container-id-2 div.sk-parallel-item:only-child::after {\n",
270
+ " width: 0;\n",
271
+ "}\n",
272
+ "\n",
273
+ "/* Serial-specific style estimator block */\n",
274
+ "\n",
275
+ "#sk-container-id-2 div.sk-serial {\n",
276
+ " display: flex;\n",
277
+ " flex-direction: column;\n",
278
+ " align-items: center;\n",
279
+ " background-color: var(--sklearn-color-background);\n",
280
+ " padding-right: 1em;\n",
281
+ " padding-left: 1em;\n",
282
+ "}\n",
283
+ "\n",
284
+ "\n",
285
+ "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
286
+ "clickable and can be expanded/collapsed.\n",
287
+ "- Pipeline and ColumnTransformer use this feature and define the default style\n",
288
+ "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
289
+ "*/\n",
290
+ "\n",
291
+ "/* Pipeline and ColumnTransformer style (default) */\n",
292
+ "\n",
293
+ "#sk-container-id-2 div.sk-toggleable {\n",
294
+ " /* Default theme specific background. It is overwritten whether we have a\n",
295
+ " specific estimator or a Pipeline/ColumnTransformer */\n",
296
+ " background-color: var(--sklearn-color-background);\n",
297
+ "}\n",
298
+ "\n",
299
+ "/* Toggleable label */\n",
300
+ "#sk-container-id-2 label.sk-toggleable__label {\n",
301
+ " cursor: pointer;\n",
302
+ " display: flex;\n",
303
+ " width: 100%;\n",
304
+ " margin-bottom: 0;\n",
305
+ " padding: 0.5em;\n",
306
+ " box-sizing: border-box;\n",
307
+ " text-align: center;\n",
308
+ " align-items: start;\n",
309
+ " justify-content: space-between;\n",
310
+ " gap: 0.5em;\n",
311
+ "}\n",
312
+ "\n",
313
+ "#sk-container-id-2 label.sk-toggleable__label .caption {\n",
314
+ " font-size: 0.6rem;\n",
315
+ " font-weight: lighter;\n",
316
+ " color: var(--sklearn-color-text-muted);\n",
317
+ "}\n",
318
+ "\n",
319
+ "#sk-container-id-2 label.sk-toggleable__label-arrow:before {\n",
320
+ " /* Arrow on the left of the label */\n",
321
+ " content: \"▸\";\n",
322
+ " float: left;\n",
323
+ " margin-right: 0.25em;\n",
324
+ " color: var(--sklearn-color-icon);\n",
325
+ "}\n",
326
+ "\n",
327
+ "#sk-container-id-2 label.sk-toggleable__label-arrow:hover:before {\n",
328
+ " color: var(--sklearn-color-text);\n",
329
+ "}\n",
330
+ "\n",
331
+ "/* Toggleable content - dropdown */\n",
332
+ "\n",
333
+ "#sk-container-id-2 div.sk-toggleable__content {\n",
334
+ " max-height: 0;\n",
335
+ " max-width: 0;\n",
336
+ " overflow: hidden;\n",
337
+ " text-align: left;\n",
338
+ " /* unfitted */\n",
339
+ " background-color: var(--sklearn-color-unfitted-level-0);\n",
340
+ "}\n",
341
+ "\n",
342
+ "#sk-container-id-2 div.sk-toggleable__content.fitted {\n",
343
+ " /* fitted */\n",
344
+ " background-color: var(--sklearn-color-fitted-level-0);\n",
345
+ "}\n",
346
+ "\n",
347
+ "#sk-container-id-2 div.sk-toggleable__content pre {\n",
348
+ " margin: 0.2em;\n",
349
+ " border-radius: 0.25em;\n",
350
+ " color: var(--sklearn-color-text);\n",
351
+ " /* unfitted */\n",
352
+ " background-color: var(--sklearn-color-unfitted-level-0);\n",
353
+ "}\n",
354
+ "\n",
355
+ "#sk-container-id-2 div.sk-toggleable__content.fitted pre {\n",
356
+ " /* unfitted */\n",
357
+ " background-color: var(--sklearn-color-fitted-level-0);\n",
358
+ "}\n",
359
+ "\n",
360
+ "#sk-container-id-2 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
361
+ " /* Expand drop-down */\n",
362
+ " max-height: 200px;\n",
363
+ " max-width: 100%;\n",
364
+ " overflow: auto;\n",
365
+ "}\n",
366
+ "\n",
367
+ "#sk-container-id-2 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
368
+ " content: \"▾\";\n",
369
+ "}\n",
370
+ "\n",
371
+ "/* Pipeline/ColumnTransformer-specific style */\n",
372
+ "\n",
373
+ "#sk-container-id-2 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
374
+ " color: var(--sklearn-color-text);\n",
375
+ " background-color: var(--sklearn-color-unfitted-level-2);\n",
376
+ "}\n",
377
+ "\n",
378
+ "#sk-container-id-2 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
379
+ " background-color: var(--sklearn-color-fitted-level-2);\n",
380
+ "}\n",
381
+ "\n",
382
+ "/* Estimator-specific style */\n",
383
+ "\n",
384
+ "/* Colorize estimator box */\n",
385
+ "#sk-container-id-2 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
386
+ " /* unfitted */\n",
387
+ " background-color: var(--sklearn-color-unfitted-level-2);\n",
388
+ "}\n",
389
+ "\n",
390
+ "#sk-container-id-2 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
391
+ " /* fitted */\n",
392
+ " background-color: var(--sklearn-color-fitted-level-2);\n",
393
+ "}\n",
394
+ "\n",
395
+ "#sk-container-id-2 div.sk-label label.sk-toggleable__label,\n",
396
+ "#sk-container-id-2 div.sk-label label {\n",
397
+ " /* The background is the default theme color */\n",
398
+ " color: var(--sklearn-color-text-on-default-background);\n",
399
+ "}\n",
400
+ "\n",
401
+ "/* On hover, darken the color of the background */\n",
402
+ "#sk-container-id-2 div.sk-label:hover label.sk-toggleable__label {\n",
403
+ " color: var(--sklearn-color-text);\n",
404
+ " background-color: var(--sklearn-color-unfitted-level-2);\n",
405
+ "}\n",
406
+ "\n",
407
+ "/* Label box, darken color on hover, fitted */\n",
408
+ "#sk-container-id-2 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
409
+ " color: var(--sklearn-color-text);\n",
410
+ " background-color: var(--sklearn-color-fitted-level-2);\n",
411
+ "}\n",
412
+ "\n",
413
+ "/* Estimator label */\n",
414
+ "\n",
415
+ "#sk-container-id-2 div.sk-label label {\n",
416
+ " font-family: monospace;\n",
417
+ " font-weight: bold;\n",
418
+ " display: inline-block;\n",
419
+ " line-height: 1.2em;\n",
420
+ "}\n",
421
+ "\n",
422
+ "#sk-container-id-2 div.sk-label-container {\n",
423
+ " text-align: center;\n",
424
+ "}\n",
425
+ "\n",
426
+ "/* Estimator-specific */\n",
427
+ "#sk-container-id-2 div.sk-estimator {\n",
428
+ " font-family: monospace;\n",
429
+ " border: 1px dotted var(--sklearn-color-border-box);\n",
430
+ " border-radius: 0.25em;\n",
431
+ " box-sizing: border-box;\n",
432
+ " margin-bottom: 0.5em;\n",
433
+ " /* unfitted */\n",
434
+ " background-color: var(--sklearn-color-unfitted-level-0);\n",
435
+ "}\n",
436
+ "\n",
437
+ "#sk-container-id-2 div.sk-estimator.fitted {\n",
438
+ " /* fitted */\n",
439
+ " background-color: var(--sklearn-color-fitted-level-0);\n",
440
+ "}\n",
441
+ "\n",
442
+ "/* on hover */\n",
443
+ "#sk-container-id-2 div.sk-estimator:hover {\n",
444
+ " /* unfitted */\n",
445
+ " background-color: var(--sklearn-color-unfitted-level-2);\n",
446
+ "}\n",
447
+ "\n",
448
+ "#sk-container-id-2 div.sk-estimator.fitted:hover {\n",
449
+ " /* fitted */\n",
450
+ " background-color: var(--sklearn-color-fitted-level-2);\n",
451
+ "}\n",
452
+ "\n",
453
+ "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
454
+ "\n",
455
+ "/* Common style for \"i\" and \"?\" */\n",
456
+ "\n",
457
+ ".sk-estimator-doc-link,\n",
458
+ "a:link.sk-estimator-doc-link,\n",
459
+ "a:visited.sk-estimator-doc-link {\n",
460
+ " float: right;\n",
461
+ " font-size: smaller;\n",
462
+ " line-height: 1em;\n",
463
+ " font-family: monospace;\n",
464
+ " background-color: var(--sklearn-color-background);\n",
465
+ " border-radius: 1em;\n",
466
+ " height: 1em;\n",
467
+ " width: 1em;\n",
468
+ " text-decoration: none !important;\n",
469
+ " margin-left: 0.5em;\n",
470
+ " text-align: center;\n",
471
+ " /* unfitted */\n",
472
+ " border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
473
+ " color: var(--sklearn-color-unfitted-level-1);\n",
474
+ "}\n",
475
+ "\n",
476
+ ".sk-estimator-doc-link.fitted,\n",
477
+ "a:link.sk-estimator-doc-link.fitted,\n",
478
+ "a:visited.sk-estimator-doc-link.fitted {\n",
479
+ " /* fitted */\n",
480
+ " border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
481
+ " color: var(--sklearn-color-fitted-level-1);\n",
482
+ "}\n",
483
+ "\n",
484
+ "/* On hover */\n",
485
+ "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
486
+ ".sk-estimator-doc-link:hover,\n",
487
+ "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
488
+ ".sk-estimator-doc-link:hover {\n",
489
+ " /* unfitted */\n",
490
+ " background-color: var(--sklearn-color-unfitted-level-3);\n",
491
+ " color: var(--sklearn-color-background);\n",
492
+ " text-decoration: none;\n",
493
+ "}\n",
494
+ "\n",
495
+ "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
496
+ ".sk-estimator-doc-link.fitted:hover,\n",
497
+ "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
498
+ ".sk-estimator-doc-link.fitted:hover {\n",
499
+ " /* fitted */\n",
500
+ " background-color: var(--sklearn-color-fitted-level-3);\n",
501
+ " color: var(--sklearn-color-background);\n",
502
+ " text-decoration: none;\n",
503
+ "}\n",
504
+ "\n",
505
+ "/* Span, style for the box shown on hovering the info icon */\n",
506
+ ".sk-estimator-doc-link span {\n",
507
+ " display: none;\n",
508
+ " z-index: 9999;\n",
509
+ " position: relative;\n",
510
+ " font-weight: normal;\n",
511
+ " right: .2ex;\n",
512
+ " padding: .5ex;\n",
513
+ " margin: .5ex;\n",
514
+ " width: min-content;\n",
515
+ " min-width: 20ex;\n",
516
+ " max-width: 50ex;\n",
517
+ " color: var(--sklearn-color-text);\n",
518
+ " box-shadow: 2pt 2pt 4pt #999;\n",
519
+ " /* unfitted */\n",
520
+ " background: var(--sklearn-color-unfitted-level-0);\n",
521
+ " border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
522
+ "}\n",
523
+ "\n",
524
+ ".sk-estimator-doc-link.fitted span {\n",
525
+ " /* fitted */\n",
526
+ " background: var(--sklearn-color-fitted-level-0);\n",
527
+ " border: var(--sklearn-color-fitted-level-3);\n",
528
+ "}\n",
529
+ "\n",
530
+ ".sk-estimator-doc-link:hover span {\n",
531
+ " display: block;\n",
532
+ "}\n",
533
+ "\n",
534
+ "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
535
+ "\n",
536
+ "#sk-container-id-2 a.estimator_doc_link {\n",
537
+ " float: right;\n",
538
+ " font-size: 1rem;\n",
539
+ " line-height: 1em;\n",
540
+ " font-family: monospace;\n",
541
+ " background-color: var(--sklearn-color-background);\n",
542
+ " border-radius: 1rem;\n",
543
+ " height: 1rem;\n",
544
+ " width: 1rem;\n",
545
+ " text-decoration: none;\n",
546
+ " /* unfitted */\n",
547
+ " color: var(--sklearn-color-unfitted-level-1);\n",
548
+ " border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
549
+ "}\n",
550
+ "\n",
551
+ "#sk-container-id-2 a.estimator_doc_link.fitted {\n",
552
+ " /* fitted */\n",
553
+ " border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
554
+ " color: var(--sklearn-color-fitted-level-1);\n",
555
+ "}\n",
556
+ "\n",
557
+ "/* On hover */\n",
558
+ "#sk-container-id-2 a.estimator_doc_link:hover {\n",
559
+ " /* unfitted */\n",
560
+ " background-color: var(--sklearn-color-unfitted-level-3);\n",
561
+ " color: var(--sklearn-color-background);\n",
562
+ " text-decoration: none;\n",
563
+ "}\n",
564
+ "\n",
565
+ "#sk-container-id-2 a.estimator_doc_link.fitted:hover {\n",
566
+ " /* fitted */\n",
567
+ " background-color: var(--sklearn-color-fitted-level-3);\n",
568
+ "}\n",
569
+ "</style><div id=\"sk-container-id-2\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>Pipeline(steps=[(&#x27;tfidf&#x27;,\n",
570
+ " TfidfVectorizer(max_features=10000, ngram_range=(1, 2),\n",
571
+ " stop_words=&#x27;english&#x27;)),\n",
572
+ " (&#x27;svm&#x27;,\n",
573
+ " SVC(class_weight=&#x27;balanced&#x27;, kernel=&#x27;linear&#x27;,\n",
574
+ " probability=True))])</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-4\" type=\"checkbox\" ><label for=\"sk-estimator-id-4\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>Pipeline</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.6/modules/generated/sklearn.pipeline.Pipeline.html\">?<span>Documentation for Pipeline</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></div></label><div class=\"sk-toggleable__content fitted\"><pre>Pipeline(steps=[(&#x27;tfidf&#x27;,\n",
575
+ " TfidfVectorizer(max_features=10000, ngram_range=(1, 2),\n",
576
+ " stop_words=&#x27;english&#x27;)),\n",
577
+ " (&#x27;svm&#x27;,\n",
578
+ " SVC(class_weight=&#x27;balanced&#x27;, kernel=&#x27;linear&#x27;,\n",
579
+ " probability=True))])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-5\" type=\"checkbox\" ><label for=\"sk-estimator-id-5\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>TfidfVectorizer</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.6/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html\">?<span>Documentation for TfidfVectorizer</span></a></div></label><div class=\"sk-toggleable__content fitted\"><pre>TfidfVectorizer(max_features=10000, ngram_range=(1, 2), stop_words=&#x27;english&#x27;)</pre></div> </div></div><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-6\" type=\"checkbox\" ><label for=\"sk-estimator-id-6\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>SVC</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.6/modules/generated/sklearn.svm.SVC.html\">?<span>Documentation for SVC</span></a></div></label><div class=\"sk-toggleable__content fitted\"><pre>SVC(class_weight=&#x27;balanced&#x27;, kernel=&#x27;linear&#x27;, probability=True)</pre></div> </div></div></div></div></div></div>"
580
+ ],
581
+ "text/plain": [
582
+ "Pipeline(steps=[('tfidf',\n",
583
+ " TfidfVectorizer(max_features=10000, ngram_range=(1, 2),\n",
584
+ " stop_words='english')),\n",
585
+ " ('svm',\n",
586
+ " SVC(class_weight='balanced', kernel='linear',\n",
587
+ " probability=True))])"
588
+ ]
589
+ },
590
+ "execution_count": 61,
591
+ "metadata": {},
592
+ "output_type": "execute_result"
593
+ }
594
+ ],
595
+ "source": [
596
+ "#model training\n",
597
+ "model.fit(X_train, y_train)"
598
+ ]
599
+ },
600
+ {
601
+ "cell_type": "markdown",
602
+ "metadata": {},
603
+ "source": [
604
+ "#### Model Evaluation"
605
+ ]
606
+ },
607
+ {
608
+ "cell_type": "code",
609
+ "execution_count": null,
610
+ "metadata": {},
611
+ "outputs": [
612
+ {
613
+ "name": "stdout",
614
+ "output_type": "stream",
615
+ "text": [
616
+ "Model Accuracy: 0.7510\n",
617
+ "\n",
618
+ "Classification Report:\n",
619
+ " precision recall f1-score support\n",
620
+ "\n",
621
+ " negative 0.88 0.79 0.83 3085\n",
622
+ " neutral 0.51 0.64 0.57 984\n",
623
+ " positive 0.67 0.73 0.70 763\n",
624
+ "\n",
625
+ " accuracy 0.75 4832\n",
626
+ " macro avg 0.69 0.72 0.70 4832\n",
627
+ "weighted avg 0.77 0.75 0.76 4832\n",
628
+ "\n"
629
+ ]
630
+ }
631
+ ],
632
+ "source": [
633
+ "# Evaluate model\n",
634
+ "y_pred = model.predict(X_test)\n",
635
+ "accuracy = accuracy_score(y_test, y_pred)\n",
636
+ "\n",
637
+ "#Display model accuracy\n",
638
+ "print(f\"Model Accuracy: {accuracy:.4f}\")\n",
639
+ "\n",
640
+ "# Display classification report\n",
641
+ "print(\"\\nClassification Report:\")\n",
642
+ "print(classification_report(y_test, y_pred, target_names=['negative', 'neutral', 'positive']))"
643
+ ]
644
+ },
645
+ {
646
+ "cell_type": "code",
647
+ "execution_count": 63,
648
+ "metadata": {},
649
+ "outputs": [
650
+ {
651
+ "data": {
652
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjkAAAHHCAYAAABdm0mZAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvc2/+5QAAAAlwSFlzAAAPYQAAD2EBqD+naQAAV0BJREFUeJzt3Qd8U+XXwPHTslfZe+8NMvwzFBAQEJCtqCB7yFaGIogsAZE9RIayRQFRUNnIFhAQWbKXsvcoq8y8n/PwJjalDS1Nx739ff1c2+Te3NwkNDk55zzP9XE4HA4BAACwGd+oPgAAAICIQJADAABsiSAHAADYEkEOAACwJYIcAABgSwQ5AADAlghyAACALRHkAAAAWyLIAQAAtkSQA8QQR44ckapVq0rSpEnFx8dHFi1a5NX9//PPP2a/M2bM8Op+reyVV14xC4CoQZADRKJjx47Je++9Jzly5JD48eOLn5+fvPTSSzJ27Fi5e/duhN53s2bNZO/evTJ48GCZPXu2lCxZUuyiefPmJsDS5zO451EDPF2vy4gRI8K8/7Nnz0r//v1l165dXjpiAJEhdqTcCwBZsmSJvPnmmxIvXjxp2rSpFCpUSO7fvy+///67fPjhh7Jv3z6ZMmVKhNy3fvBv2bJFPvnkE+nUqVOE3EfWrFnN/cSJE0eiQuzYseXOnTvy66+/SsOGDd3WzZkzxwSVAQEBz7VvDXIGDBgg2bJlkxdeeCHUt1u5cuVz3R8A7yDIASLBiRMn5O233zaBwJo1ayR9+vSudR07dpSjR4+aICiiXLp0yfxMlixZhN2HZkk0kIgqGjxqVuz7779/Ksj57rvvpGbNmvLjjz9GyrFosJUwYUKJGzdupNwfgOBRrgIiwbBhw+TWrVsydepUtwDHKVeuXPL++++7Lj98+FA+++wzyZkzp/nw1gxC79695d69e2630+tff/11kw363//+Z4IMLYXNmjXLtY2WWTS4Upox0mBEb+cs8zh/D0xvo9sFtmrVKnn55ZdNoJQ4cWLJmzevOaZn9eRoUFeuXDlJlCiRuW2dOnXkwIEDwd6fBnt6TLqd9g61aNHCBAyh1ahRI1m2bJlcv37ddd327dtNuUrXBXX16lXp0aOHFC5c2DwmLXdVr15ddu/e7dpm3bp18uKLL5rf9XicZS/n49SeG83K7dixQ8qXL2+CG+fzErQnR0uG+hoFffzVqlWT5MmTm4wRAO8hyAEigZZQNPgoW7ZsqLZv3bq19O3bV4oXLy6jR4+WChUqyOeff26yQUFpYPDGG29IlSpVZOTIkebDUgMFLX+p+vXrm32od955x/TjjBkzJkzHr/vSYEqDrIEDB5r7qV27tmzatMnj7X777TfzAX7x4kUTyHTr1k02b95sMi4aFAWlGZibN2+ax6q/ayChZaLQ0seqAchPP/3klsXJly+feS6DOn78uGnA1sc2atQoEwRq35I+386AI3/+/OYxq7Zt25rnTxcNaJyuXLligiMtZelzW7FixWCPT3uvUqdObYKdR48emesmT55sylrjx4+XDBkyhPqxAggFB4AIdePGDYf+qdWpUydU2+/atcts37p1a7fre/ToYa5fs2aN67qsWbOa6zZs2OC67uLFi4548eI5unfv7rruxIkTZrvhw4e77bNZs2ZmH0H169fPbO80evRoc/nSpUshHrfzPqZPn+667oUXXnCkSZPGceXKFdd1u3fvdvj6+jqaNm361P21bNnSbZ/16tVzpEyZMsT7DPw4EiVKZH5/4403HJUrVza/P3r0yJEuXTrHgAEDgn0OAgICzDZBH4c+fwMHDnRdt3379qcem1OFChXMukmTJgW7TpfAVqxYYbYfNGiQ4/jx447EiRM76tat+8zHCCDsyOQAEczf39/8TJIkSai2X7p0qfmpWY/Aunfvbn4G7d0pUKCAKQc5aaZAS0mapfAWZy/Pzz//LI8fPw7Vbc6dO2dGI2lWKUWKFK7rixQpYrJOzscZWLt27dwu6+PSLInzOQwNLUtpien8+fOmVKY/gytVKS0F+vo+eRvUzIrel7MU99dff4X6PnU/WsoKDR3GryPsNDukmSctX2k2B4D3EeQAEUz7PJSWYULj33//NR+82qcTWLp06UywoesDy5Ily1P70JLVtWvXxFveeustU2LSMlratGlN2Wz+/PkeAx7ncWrAEJSWgC5fviy3b9/2+Fj0caiwPJYaNWqYgHLevHlmVJX20wR9Lp30+LWUlzt3bhOopEqVygSJe/bskRs3boT6PjNmzBimJmMdxq6BnwaB48aNkzRp0oT6tgBCjyAHiIQgR3st/v777zDdLmjjb0hixYoV7PUOh+O578PZL+KUIEEC2bBhg+mxadKkiQkCNPDRjEzQbcMjPI/FSYMV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",
653
+ "text/plain": [
654
+ "<Figure size 640x480 with 2 Axes>"
655
+ ]
656
+ },
657
+ "metadata": {},
658
+ "output_type": "display_data"
659
+ }
660
+ ],
661
+ "source": [
662
+ "# Plot confusion matrix\n",
663
+ "cm = confusion_matrix(y_test, y_pred)\n",
664
+ "disp = ConfusionMatrixDisplay(confusion_matrix=cm, \n",
665
+ " display_labels=['Negative', 'Neutral', 'Positive'])\n",
666
+ "disp.plot(cmap=plt.cm.Blues)\n",
667
+ "plt.title('Confusion Matrix')\n",
668
+ "plt.show()"
669
+ ]
670
+ },
671
+ {
672
+ "cell_type": "markdown",
673
+ "metadata": {},
674
+ "source": [
675
+ "#### Model Export"
676
+ ]
677
+ },
678
+ {
679
+ "cell_type": "code",
680
+ "execution_count": 64,
681
+ "metadata": {},
682
+ "outputs": [
683
+ {
684
+ "data": {
685
+ "text/plain": [
686
+ "['SA_model.pkl']"
687
+ ]
688
+ },
689
+ "execution_count": 64,
690
+ "metadata": {},
691
+ "output_type": "execute_result"
692
+ }
693
+ ],
694
+ "source": [
695
+ "# Save the trained model\n",
696
+ "joblib.dump(model, \"SA_model.pkl\")"
697
+ ]
698
+ }
699
+ ],
700
+ "metadata": {
701
+ "kernelspec": {
702
+ "display_name": "venv",
703
+ "language": "python",
704
+ "name": "python3"
705
+ },
706
+ "language_info": {
707
+ "codemirror_mode": {
708
+ "name": "ipython",
709
+ "version": 3
710
+ },
711
+ "file_extension": ".py",
712
+ "mimetype": "text/x-python",
713
+ "name": "python",
714
+ "nbconvert_exporter": "python",
715
+ "pygments_lexer": "ipython3",
716
+ "version": "3.12.2"
717
+ }
718
+ },
719
+ "nbformat": 4,
720
+ "nbformat_minor": 2
721
+ }