Spaces:
Running
Running
Sync from GitHub via hub-sync
Browse files- app/database.py +20 -0
- app/main.py +47 -5
- app/ml_model.py +63 -0
- app/models.py +13 -0
- app/schemas.py +13 -0
- notebooks/01_eda_and_data_engineering.ipynb +133 -389
- notebooks/02_fine_tuning.ipynb +0 -0
- notebooks/eda_and_data_engineering.ipynb +0 -462
- requirements.txt +15 -9
app/database.py
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from sqlalchemy import create_engine
|
| 3 |
+
from sqlalchemy.orm import declarative_base, sessionmaker
|
| 4 |
+
from dotenv import load_dotenv
|
| 5 |
+
|
| 6 |
+
load_dotenv()
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
DATABASE_URL = os.getenv('DATABASE_URL')
|
| 10 |
+
engine = create_engine(DATABASE_URL)
|
| 11 |
+
|
| 12 |
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
| 13 |
+
Base = declarative_base()
|
| 14 |
+
|
| 15 |
+
def get_db():
|
| 16 |
+
db = SessionLocal()
|
| 17 |
+
try:
|
| 18 |
+
yield db
|
| 19 |
+
finally:
|
| 20 |
+
db.close()
|
app/main.py
CHANGED
|
@@ -1,7 +1,49 @@
|
|
| 1 |
-
from fastapi import FastAPI
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI, Depends, HttpException
|
| 2 |
+
from sqlalchemy.orm import Session
|
| 3 |
+
from datetime import datetime, timezone
|
| 4 |
|
| 5 |
+
from .database import get_db
|
| 6 |
+
from .models import InferenceLog
|
| 7 |
+
from .schemas import SentimentRequest, SentimentResponse
|
| 8 |
+
from . import ml_model
|
| 9 |
|
| 10 |
+
app = FastAPI(
|
| 11 |
+
title='FinBERT Sentiment Analyzer API',
|
| 12 |
+
description='An API for analyzing the sentiment of financial news articles using FinBERT.',
|
| 13 |
+
version='1.0.0'
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
@app.post('/predict', response_model=SentimentResponse)
|
| 17 |
+
def predict_sentiment(request: SentimentRequest, db: Session = Depends(get_db)):
|
| 18 |
+
try:
|
| 19 |
+
prediction_result = ml_model.predict(request.text)
|
| 20 |
+
log_entry = InferenceLog(
|
| 21 |
+
input_text=request.text,
|
| 22 |
+
sentiment_prediction=prediction_result['sentiment'],
|
| 23 |
+
confidence_score=prediction_result['confidence'],
|
| 24 |
+
timestamp=datetime.now(timezone.utc)
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
db.add(log_entry)
|
| 28 |
+
db.commit()
|
| 29 |
+
db.close()
|
| 30 |
+
|
| 31 |
+
return SentimentResponse(
|
| 32 |
+
input_text=request.text,
|
| 33 |
+
sentiment=prediction_result['sentiment'],
|
| 34 |
+
confidence=prediction_result['confidence'],
|
| 35 |
+
timestamp=log_entry.timestamp
|
| 36 |
+
)
|
| 37 |
+
except Exception as e:
|
| 38 |
+
raise HttpException(status_code=500, detail=str(e))
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
@app.get('/logs')
|
| 42 |
+
def get_inference_logs(db: Session = Depends(get_db)):
|
| 43 |
+
logs = db.query(InferenceLog).order_by(InferenceLog.timestamp.desc()).all()
|
| 44 |
+
return logs
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
@app.get('/health')
|
| 48 |
+
def health_check():
|
| 49 |
+
return {"status": "ok", "timestamp": datetime.now(timezone.utc)}
|
app/ml_model.py
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn.functional as F
|
| 4 |
+
from transformers import AutoModelForSequenceClassification, AutoTokenizer
|
| 5 |
+
|
| 6 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 7 |
+
# Target your specific Hugging Face repository
|
| 8 |
+
HF_MODEL_REPO = 'mobadara/finbert-finetuned'
|
| 9 |
+
|
| 10 |
+
logging.info(f'Initializing NLP pipeline from {HF_MODEL_REPO}...')
|
| 11 |
+
|
| 12 |
+
# Load tokenizer and model weights
|
| 13 |
+
tokenizer = AutoTokenizer.from_pretrained(HF_MODEL_REPO)
|
| 14 |
+
model = AutoModelForSequenceClassification.from_pretrained(HF_MODEL_REPO)
|
| 15 |
+
model.eval() # Lock the model in evaluation mode for inference
|
| 16 |
+
|
| 17 |
+
# Map model output indices to our target classes
|
| 18 |
+
LABEL_MAPPING = {0: 'Negative', 1: 'Neutral', 2: "Positive"}
|
| 19 |
+
|
| 20 |
+
def predict(text: str) -> dict:
|
| 21 |
+
"""
|
| 22 |
+
Takes raw text, tokenizes it, runs it through FinBERT,
|
| 23 |
+
and returns the predicted sentiment and confidence score.
|
| 24 |
+
|
| 25 |
+
Args:
|
| 26 |
+
text (str): The input text to analyze.
|
| 27 |
+
|
| 28 |
+
Returns:
|
| 29 |
+
dict: A dictionary containing the predicted sentiment and confidence score.
|
| 30 |
+
|
| 31 |
+
Throws:
|
| 32 |
+
ValueError: If the input text is empty or None.
|
| 33 |
+
"""
|
| 34 |
+
if not text:
|
| 35 |
+
raise ValueError("Input text cannot be empty or None.")
|
| 36 |
+
|
| 37 |
+
# Tokenize the incoming text
|
| 38 |
+
inputs = tokenizer(
|
| 39 |
+
text,
|
| 40 |
+
return_tensors='pt',
|
| 41 |
+
truncation=True,
|
| 42 |
+
padding=True,
|
| 43 |
+
max_length=512
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
# Perform inference without tracking gradients (saves memory/time)
|
| 47 |
+
with torch.no_grad():
|
| 48 |
+
outputs = model(**inputs)
|
| 49 |
+
logits = outputs.logits
|
| 50 |
+
|
| 51 |
+
# Convert raw logits to probabilities
|
| 52 |
+
probabilities = F.softmax(logits, dim=-1)
|
| 53 |
+
|
| 54 |
+
# Extract the highest probability and its index
|
| 55 |
+
confidence_score, predicted_class_idx = torch.max(probabilities, dim=1)
|
| 56 |
+
|
| 57 |
+
sentiment_label = LABEL_MAPPING[predicted_class_idx.item()]
|
| 58 |
+
confidence_float = round(confidence_score.item(), 4)
|
| 59 |
+
|
| 60 |
+
return {
|
| 61 |
+
'sentiment': sentiment_label,
|
| 62 |
+
'confidence': confidence_float
|
| 63 |
+
}
|
app/models.py
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sqlalchemy import Column, Integer, String, Float, DateTime
|
| 2 |
+
from datetime import datetime, timezone
|
| 3 |
+
|
| 4 |
+
from .database import Base
|
| 5 |
+
|
| 6 |
+
class InferenceLog(Base):
|
| 7 |
+
__tablename__ = 'inference_logs'
|
| 8 |
+
|
| 9 |
+
id = Column(Integer, primary_key=True, index=True)
|
| 10 |
+
input_text = Column(String, index=True)
|
| 11 |
+
sentiment_prediction = Column(String, index=True)
|
| 12 |
+
confidence_score = Column(Float)
|
| 13 |
+
timestamp = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
app/schemas.py
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pydantic import BaseModel
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
|
| 4 |
+
class SentimentRequest(BaseModel):
|
| 5 |
+
text: StopIteration
|
| 6 |
+
|
| 7 |
+
class SentimentResponse(BaseModel):
|
| 8 |
+
input_text: str
|
| 9 |
+
sentiment: str
|
| 10 |
+
confidence: float
|
| 11 |
+
timestamp: datetime
|
| 12 |
+
|
| 13 |
+
|
notebooks/01_eda_and_data_engineering.ipynb
CHANGED
|
@@ -1,26 +1,10 @@
|
|
| 1 |
{
|
| 2 |
-
"nbformat": 4,
|
| 3 |
-
"nbformat_minor": 0,
|
| 4 |
-
"metadata": {
|
| 5 |
-
"colab": {
|
| 6 |
-
"provenance": [],
|
| 7 |
-
"authorship_tag": "ABX9TyN9T0T3HM5FCsd5NQ18TNLI",
|
| 8 |
-
"include_colab_link": true
|
| 9 |
-
},
|
| 10 |
-
"kernelspec": {
|
| 11 |
-
"name": "python3",
|
| 12 |
-
"display_name": "Python 3"
|
| 13 |
-
},
|
| 14 |
-
"language_info": {
|
| 15 |
-
"name": "python"
|
| 16 |
-
}
|
| 17 |
-
},
|
| 18 |
"cells": [
|
| 19 |
{
|
| 20 |
"cell_type": "markdown",
|
| 21 |
"metadata": {
|
| 22 |
-
"
|
| 23 |
-
"
|
| 24 |
},
|
| 25 |
"source": [
|
| 26 |
"<a href=\"https://colab.research.google.com/github/mobadara/finbert-sentiment-analyzer-api/blob/main/notebooks/01_eda_and_data_engineering.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
|
@@ -28,6 +12,9 @@
|
|
| 28 |
},
|
| 29 |
{
|
| 30 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 31 |
"source": [
|
| 32 |
"# **FINANCIAL NEWS SENTIMENT ANALYSIS**\n",
|
| 33 |
"## 📈 **EDA & Data Engineering**\n",
|
|
@@ -46,23 +33,20 @@
|
|
| 46 |
"* **Source:** `financial_phrasebank` (via Hugging Face Datasets)\n",
|
| 47 |
"* **Configuration:** `sentences_allagree` (Using only sentences where 100% of human annotators agreed on the sentiment)\n",
|
| 48 |
"* **Labels:** 0 (Negative), 1 (Neutral), 2 (Positive)"
|
| 49 |
-
]
|
| 50 |
-
"metadata": {
|
| 51 |
-
"id": "175c_DpCsGNf"
|
| 52 |
-
}
|
| 53 |
},
|
| 54 |
{
|
| 55 |
"cell_type": "markdown",
|
| 56 |
-
"source": [
|
| 57 |
-
"### **Setup**"
|
| 58 |
-
],
|
| 59 |
"metadata": {
|
| 60 |
"id": "Gt4uyJvPtv-s"
|
| 61 |
-
}
|
|
|
|
|
|
|
|
|
|
| 62 |
},
|
| 63 |
{
|
| 64 |
"cell_type": "code",
|
| 65 |
-
"execution_count":
|
| 66 |
"metadata": {
|
| 67 |
"id": "oHA_z_6krqFa"
|
| 68 |
},
|
|
@@ -86,32 +70,30 @@
|
|
| 86 |
},
|
| 87 |
{
|
| 88 |
"cell_type": "code",
|
| 89 |
-
"
|
| 90 |
-
"os.makedirs('figures', exist_ok=True)\n",
|
| 91 |
-
"os.makedirs('datasets', exist_ok=True)"
|
| 92 |
-
],
|
| 93 |
"metadata": {
|
| 94 |
"id": "EpCL1HxowTni"
|
| 95 |
},
|
| 96 |
-
"
|
| 97 |
-
"
|
|
|
|
|
|
|
|
|
|
| 98 |
},
|
| 99 |
{
|
| 100 |
"cell_type": "code",
|
| 101 |
-
"
|
| 102 |
-
"dataset = load_dataset('FinanceMTEB/financial_phrasebank')"
|
| 103 |
-
],
|
| 104 |
"metadata": {
|
| 105 |
"id": "rLHOtOKrvMwg"
|
| 106 |
},
|
| 107 |
-
"
|
| 108 |
-
"
|
|
|
|
|
|
|
| 109 |
},
|
| 110 |
{
|
| 111 |
"cell_type": "code",
|
| 112 |
-
"
|
| 113 |
-
"dataset"
|
| 114 |
-
],
|
| 115 |
"metadata": {
|
| 116 |
"colab": {
|
| 117 |
"base_uri": "https://localhost:8080/"
|
|
@@ -119,48 +101,27 @@
|
|
| 119 |
"id": "BC7Xjb0IvRhf",
|
| 120 |
"outputId": "bfe8f5b4-9a17-42b5-bb14-ac6ecd1cbd0f"
|
| 121 |
},
|
| 122 |
-
"
|
| 123 |
-
"
|
| 124 |
-
|
| 125 |
-
"output_type": "execute_result",
|
| 126 |
-
"data": {
|
| 127 |
-
"text/plain": [
|
| 128 |
-
"DatasetDict({\n",
|
| 129 |
-
" train: Dataset({\n",
|
| 130 |
-
" features: ['text', 'label_text', 'label'],\n",
|
| 131 |
-
" num_rows: 1264\n",
|
| 132 |
-
" })\n",
|
| 133 |
-
" test: Dataset({\n",
|
| 134 |
-
" features: ['text', 'label_text', 'label'],\n",
|
| 135 |
-
" num_rows: 1000\n",
|
| 136 |
-
" })\n",
|
| 137 |
-
"})"
|
| 138 |
-
]
|
| 139 |
-
},
|
| 140 |
-
"metadata": {},
|
| 141 |
-
"execution_count": 4
|
| 142 |
-
}
|
| 143 |
]
|
| 144 |
},
|
| 145 |
{
|
| 146 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 147 |
"source": [
|
| 148 |
"The dataset has two splits:\n",
|
| 149 |
"1. Train Dataset contains 1264 instances.\n",
|
| 150 |
"2. Test Dataset contains 1000 instances.\n",
|
| 151 |
"\n",
|
| 152 |
"We need to convert the train dataset to a pandas datafrome exploration."
|
| 153 |
-
]
|
| 154 |
-
"metadata": {
|
| 155 |
-
"id": "KkoS3g2KxDfk"
|
| 156 |
-
}
|
| 157 |
},
|
| 158 |
{
|
| 159 |
"cell_type": "code",
|
| 160 |
-
"
|
| 161 |
-
"df_train = dataset['train'].to_pandas()\n",
|
| 162 |
-
"df_train.head()"
|
| 163 |
-
],
|
| 164 |
"metadata": {
|
| 165 |
"colab": {
|
| 166 |
"base_uri": "https://localhost:8080/",
|
|
@@ -169,184 +130,32 @@
|
|
| 169 |
"id": "Fd4_eL-PwUNw",
|
| 170 |
"outputId": "2da09fc8-938d-4479-9460-da7cf774a1d4"
|
| 171 |
},
|
| 172 |
-
"
|
| 173 |
-
"
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
"data": {
|
| 177 |
-
"text/plain": [
|
| 178 |
-
" text label_text label\n",
|
| 179 |
-
"0 The Samsung Mobile Applications Store was laun... neutral 1\n",
|
| 180 |
-
"1 F-Secure , a developer of security solutions a... neutral 1\n",
|
| 181 |
-
"2 The company serves customers in various indust... neutral 1\n",
|
| 182 |
-
"3 The company reported net sales of 302 mln euro... neutral 1\n",
|
| 183 |
-
"4 Microsoft last week also issued the first patc... neutral 1"
|
| 184 |
-
],
|
| 185 |
-
"text/html": [
|
| 186 |
-
"\n",
|
| 187 |
-
" <div id=\"df-1def2767-92a3-4c60-8c46-59087082dc12\" class=\"colab-df-container\">\n",
|
| 188 |
-
" <div>\n",
|
| 189 |
-
"<style scoped>\n",
|
| 190 |
-
" .dataframe tbody tr th:only-of-type {\n",
|
| 191 |
-
" vertical-align: middle;\n",
|
| 192 |
-
" }\n",
|
| 193 |
-
"\n",
|
| 194 |
-
" .dataframe tbody tr th {\n",
|
| 195 |
-
" vertical-align: top;\n",
|
| 196 |
-
" }\n",
|
| 197 |
-
"\n",
|
| 198 |
-
" .dataframe thead th {\n",
|
| 199 |
-
" text-align: right;\n",
|
| 200 |
-
" }\n",
|
| 201 |
-
"</style>\n",
|
| 202 |
-
"<table border=\"1\" class=\"dataframe\">\n",
|
| 203 |
-
" <thead>\n",
|
| 204 |
-
" <tr style=\"text-align: right;\">\n",
|
| 205 |
-
" <th></th>\n",
|
| 206 |
-
" <th>text</th>\n",
|
| 207 |
-
" <th>label_text</th>\n",
|
| 208 |
-
" <th>label</th>\n",
|
| 209 |
-
" </tr>\n",
|
| 210 |
-
" </thead>\n",
|
| 211 |
-
" <tbody>\n",
|
| 212 |
-
" <tr>\n",
|
| 213 |
-
" <th>0</th>\n",
|
| 214 |
-
" <td>The Samsung Mobile Applications Store was laun...</td>\n",
|
| 215 |
-
" <td>neutral</td>\n",
|
| 216 |
-
" <td>1</td>\n",
|
| 217 |
-
" </tr>\n",
|
| 218 |
-
" <tr>\n",
|
| 219 |
-
" <th>1</th>\n",
|
| 220 |
-
" <td>F-Secure , a developer of security solutions a...</td>\n",
|
| 221 |
-
" <td>neutral</td>\n",
|
| 222 |
-
" <td>1</td>\n",
|
| 223 |
-
" </tr>\n",
|
| 224 |
-
" <tr>\n",
|
| 225 |
-
" <th>2</th>\n",
|
| 226 |
-
" <td>The company serves customers in various indust...</td>\n",
|
| 227 |
-
" <td>neutral</td>\n",
|
| 228 |
-
" <td>1</td>\n",
|
| 229 |
-
" </tr>\n",
|
| 230 |
-
" <tr>\n",
|
| 231 |
-
" <th>3</th>\n",
|
| 232 |
-
" <td>The company reported net sales of 302 mln euro...</td>\n",
|
| 233 |
-
" <td>neutral</td>\n",
|
| 234 |
-
" <td>1</td>\n",
|
| 235 |
-
" </tr>\n",
|
| 236 |
-
" <tr>\n",
|
| 237 |
-
" <th>4</th>\n",
|
| 238 |
-
" <td>Microsoft last week also issued the first patc...</td>\n",
|
| 239 |
-
" <td>neutral</td>\n",
|
| 240 |
-
" <td>1</td>\n",
|
| 241 |
-
" </tr>\n",
|
| 242 |
-
" </tbody>\n",
|
| 243 |
-
"</table>\n",
|
| 244 |
-
"</div>\n",
|
| 245 |
-
" <div class=\"colab-df-buttons\">\n",
|
| 246 |
-
"\n",
|
| 247 |
-
" <div class=\"colab-df-container\">\n",
|
| 248 |
-
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-1def2767-92a3-4c60-8c46-59087082dc12')\"\n",
|
| 249 |
-
" title=\"Convert this dataframe to an interactive table.\"\n",
|
| 250 |
-
" style=\"display:none;\">\n",
|
| 251 |
-
"\n",
|
| 252 |
-
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
|
| 253 |
-
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
|
| 254 |
-
" </svg>\n",
|
| 255 |
-
" </button>\n",
|
| 256 |
-
"\n",
|
| 257 |
-
" <style>\n",
|
| 258 |
-
" .colab-df-container {\n",
|
| 259 |
-
" display:flex;\n",
|
| 260 |
-
" gap: 12px;\n",
|
| 261 |
-
" }\n",
|
| 262 |
-
"\n",
|
| 263 |
-
" .colab-df-convert {\n",
|
| 264 |
-
" background-color: #E8F0FE;\n",
|
| 265 |
-
" border: none;\n",
|
| 266 |
-
" border-radius: 50%;\n",
|
| 267 |
-
" cursor: pointer;\n",
|
| 268 |
-
" display: none;\n",
|
| 269 |
-
" fill: #1967D2;\n",
|
| 270 |
-
" height: 32px;\n",
|
| 271 |
-
" padding: 0 0 0 0;\n",
|
| 272 |
-
" width: 32px;\n",
|
| 273 |
-
" }\n",
|
| 274 |
-
"\n",
|
| 275 |
-
" .colab-df-convert:hover {\n",
|
| 276 |
-
" background-color: #E2EBFA;\n",
|
| 277 |
-
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
| 278 |
-
" fill: #174EA6;\n",
|
| 279 |
-
" }\n",
|
| 280 |
-
"\n",
|
| 281 |
-
" .colab-df-buttons div {\n",
|
| 282 |
-
" margin-bottom: 4px;\n",
|
| 283 |
-
" }\n",
|
| 284 |
-
"\n",
|
| 285 |
-
" [theme=dark] .colab-df-convert {\n",
|
| 286 |
-
" background-color: #3B4455;\n",
|
| 287 |
-
" fill: #D2E3FC;\n",
|
| 288 |
-
" }\n",
|
| 289 |
-
"\n",
|
| 290 |
-
" [theme=dark] .colab-df-convert:hover {\n",
|
| 291 |
-
" background-color: #434B5C;\n",
|
| 292 |
-
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
|
| 293 |
-
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
|
| 294 |
-
" fill: #FFFFFF;\n",
|
| 295 |
-
" }\n",
|
| 296 |
-
" </style>\n",
|
| 297 |
-
"\n",
|
| 298 |
-
" <script>\n",
|
| 299 |
-
" const buttonEl =\n",
|
| 300 |
-
" document.querySelector('#df-1def2767-92a3-4c60-8c46-59087082dc12 button.colab-df-convert');\n",
|
| 301 |
-
" buttonEl.style.display =\n",
|
| 302 |
-
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
| 303 |
-
"\n",
|
| 304 |
-
" async function convertToInteractive(key) {\n",
|
| 305 |
-
" const element = document.querySelector('#df-1def2767-92a3-4c60-8c46-59087082dc12');\n",
|
| 306 |
-
" const dataTable =\n",
|
| 307 |
-
" await google.colab.kernel.invokeFunction('convertToInteractive',\n",
|
| 308 |
-
" [key], {});\n",
|
| 309 |
-
" if (!dataTable) return;\n",
|
| 310 |
-
"\n",
|
| 311 |
-
" const docLinkHtml = 'Like what you see? Visit the ' +\n",
|
| 312 |
-
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
|
| 313 |
-
" + ' to learn more about interactive tables.';\n",
|
| 314 |
-
" element.innerHTML = '';\n",
|
| 315 |
-
" dataTable['output_type'] = 'display_data';\n",
|
| 316 |
-
" await google.colab.output.renderOutput(dataTable, element);\n",
|
| 317 |
-
" const docLink = document.createElement('div');\n",
|
| 318 |
-
" docLink.innerHTML = docLinkHtml;\n",
|
| 319 |
-
" element.appendChild(docLink);\n",
|
| 320 |
-
" }\n",
|
| 321 |
-
" </script>\n",
|
| 322 |
-
" </div>\n",
|
| 323 |
-
"\n",
|
| 324 |
-
"\n",
|
| 325 |
-
" </div>\n",
|
| 326 |
-
" </div>\n"
|
| 327 |
-
],
|
| 328 |
-
"application/vnd.google.colaboratory.intrinsic+json": {
|
| 329 |
-
"type": "dataframe",
|
| 330 |
-
"variable_name": "df_train",
|
| 331 |
-
"summary": "{\n \"name\": \"df_train\",\n \"rows\": 1264,\n \"fields\": [\n {\n \"column\": \"text\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 1263,\n \"samples\": [\n \"R&D Loan ) .\",\n \"Mr. Mikko Saavalainen , head of Comptel 's Global Sales concludes : `` Gibtelecom provides a perfect illustration of the variety of business , technical and regulatory challenges operators are facing in their OSS today .\",\n \"The decision reflects the underutilisation of the line , which produces nonwovens used in medical and wipes applications as well as for the automotive industry .\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"label_text\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"neutral\",\n \"positive\",\n \"negative\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"label\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 1,\n 2,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
|
| 332 |
-
}
|
| 333 |
-
},
|
| 334 |
-
"metadata": {},
|
| 335 |
-
"execution_count": 5
|
| 336 |
-
}
|
| 337 |
]
|
| 338 |
},
|
| 339 |
{
|
| 340 |
"cell_type": "markdown",
|
| 341 |
-
"source": [
|
| 342 |
-
"### **Data Check and Cleaning**"
|
| 343 |
-
],
|
| 344 |
"metadata": {
|
| 345 |
"id": "8G472RswiiTH"
|
| 346 |
-
}
|
|
|
|
|
|
|
|
|
|
| 347 |
},
|
| 348 |
{
|
| 349 |
"cell_type": "code",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 350 |
"source": [
|
| 351 |
"# Check for `null` values\n",
|
| 352 |
"nulls_per_column = df_train.isna().sum()\n",
|
|
@@ -358,33 +167,13 @@
|
|
| 358 |
"print(nulls_per_column)\n",
|
| 359 |
"print(\"-\" * 30)\n",
|
| 360 |
"print(f\"Number of Duplicated Instances: {duplicated_instances}\")"
|
| 361 |
-
],
|
| 362 |
-
"metadata": {
|
| 363 |
-
"colab": {
|
| 364 |
-
"base_uri": "https://localhost:8080/"
|
| 365 |
-
},
|
| 366 |
-
"id": "rotrrtnxishA",
|
| 367 |
-
"outputId": "8c8a8437-5c03-43f8-9292-0fb453b3c594"
|
| 368 |
-
},
|
| 369 |
-
"execution_count": 6,
|
| 370 |
-
"outputs": [
|
| 371 |
-
{
|
| 372 |
-
"output_type": "stream",
|
| 373 |
-
"name": "stdout",
|
| 374 |
-
"text": [
|
| 375 |
-
"Null Values Per Column:\n",
|
| 376 |
-
"text 0\n",
|
| 377 |
-
"label_text 0\n",
|
| 378 |
-
"label 0\n",
|
| 379 |
-
"dtype: int64\n",
|
| 380 |
-
"------------------------------\n",
|
| 381 |
-
"Number of Duplicated Instances: 1\n"
|
| 382 |
-
]
|
| 383 |
-
}
|
| 384 |
]
|
| 385 |
},
|
| 386 |
{
|
| 387 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 388 |
"source": [
|
| 389 |
"We see that our dataset (in tabular form) contains three columns: **text**, **label_text** and **label**.\n",
|
| 390 |
"\n",
|
|
@@ -395,38 +184,45 @@
|
|
| 395 |
"-----------|-----\n",
|
| 396 |
"negative | `0`\n",
|
| 397 |
"neutral | `1`\n",
|
| 398 |
-
"positive | `
|
| 399 |
"\n",
|
| 400 |
"\n",
|
| 401 |
"We see from our result that one instance in the dataset is exactly repeated. We drop the duplicated values in the following cell."
|
| 402 |
-
]
|
| 403 |
-
"metadata": {
|
| 404 |
-
"id": "1T4BUAkbyjp0"
|
| 405 |
-
}
|
| 406 |
},
|
| 407 |
{
|
| 408 |
"cell_type": "code",
|
| 409 |
-
"
|
| 410 |
-
"df_train.drop_duplicates(inplace=True)\n",
|
| 411 |
-
"assert df_train.duplicated().sum() == 0"
|
| 412 |
-
],
|
| 413 |
"metadata": {
|
| 414 |
"id": "HWZSAfqTkgtU"
|
| 415 |
},
|
| 416 |
-
"
|
| 417 |
-
"
|
|
|
|
|
|
|
|
|
|
| 418 |
},
|
| 419 |
{
|
| 420 |
"cell_type": "markdown",
|
| 421 |
-
"source": [
|
| 422 |
-
"Now that the duplicated entries are removed, we need to visualize our class distribution."
|
| 423 |
-
],
|
| 424 |
"metadata": {
|
| 425 |
"id": "NzLiGGnnl2D2"
|
| 426 |
-
}
|
|
|
|
|
|
|
|
|
|
| 427 |
},
|
| 428 |
{
|
| 429 |
"cell_type": "code",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 430 |
"source": [
|
| 431 |
"plt.figure(figsize=(8, 5))\n",
|
| 432 |
"ax = sns.countplot(data=df_train,\n",
|
|
@@ -447,60 +243,48 @@
|
|
| 447 |
"\n",
|
| 448 |
"plt.savefig('figures/class_distribution.png')\n",
|
| 449 |
"plt.show()"
|
| 450 |
-
],
|
| 451 |
-
"metadata": {
|
| 452 |
-
"colab": {
|
| 453 |
-
"base_uri": "https://localhost:8080/",
|
| 454 |
-
"height": 492
|
| 455 |
-
},
|
| 456 |
-
"id": "FQs0xwBqyPP8",
|
| 457 |
-
"outputId": "0c838bcf-645b-4825-81d8-76ed1e442e3b"
|
| 458 |
-
},
|
| 459 |
-
"execution_count": 8,
|
| 460 |
-
"outputs": [
|
| 461 |
-
{
|
| 462 |
-
"output_type": "display_data",
|
| 463 |
-
"data": {
|
| 464 |
-
"text/plain": [
|
| 465 |
-
"<Figure size 800x500 with 1 Axes>"
|
| 466 |
-
],
|
| 467 |
-
"image/png": "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1atXR8+ePfHbb79hx44dGD16dIlt4+Pj0bhxY2RmZqJTp07o1asXMjMzcfv2baxYsQLff/89LCwsMG3aNKxduxb379/HtGnTxOcHBwdr9RcbG4umTZuibt26GDRoEJ4+fVqqI44LFy5EVFQUevXqhU6dOuHAgQNYtGgRTp06haNHj0IqlZZ5O8jlckybNg2LFi0CAHz22WfispedXBATE4OWLVsiKSkJXbp0Qe3atXHt2jWsWbMGf/75J44fP47AwMAiz+vTpw/OnDmDDh06wNzcHJs3b8bIkSMhlUoxbNiwUuX96aefYunSpfD29saHH34IANi2bRsGDx6MixcvYvHixVpjeH58crn8hf0X/PQZExNTqnyAZ1Nl3nnnHRw+fBjBwcH48MMPoVKpsHv3bnTt2hVLly4t9uftL774AkeOHEHnzp3Rvn177NixA9OnT0deXh7mzJkDAHjvvfeQmpqKP/74A127di3yN/Uyp0+fxvz589G+fXt8/PHHOHToEH788UekpaWhS5cuGDRoELp27YpmzZph9+7d+O6772BnZ4epU6dq9TNx4kR888038Pb2xvvvvw9HR0ccO3YMX3zxBU6fPo0tW7YUWffOnTuxe/dudOnSBc2bN8fRo0cRERGBO3fu4Pjx4wCe7SNjxozB4sWLERQUhPfee098fsEXk/DwcGzevBn16tXD4MGDIZPJ8PDhQxw6dAhnz55FUFBQmbbJ80rzOrwKpd0/jh49igULFuCtt95CkyZNIJVKcfHiRfz444/4+++/ceHChWKnSpRlnJ9//jkWLlwIZ2dnvPfee3B3d8fDhw9x4MABvPnmm6hTp84LxzJy5EgEBQWhbdu2cHNzw+PHj7Fjxw60bdsWkZGR6Nq1q342WgmeP39CpVKhXbt2UCgU6N69O7KysrBx40b07NkTf/31F9q1a1ekj9GjR+PUqVPo1KkTunTpAnd3dwBl2/6CIKB9+/Y4ffo0WrRogXfeeQdmZma4f/8+du7ciQEDBsDX11ds269fP2zYsAHVqlVD3759YWlpif379+PDDz9EdHQ0vv/++1KN//79+7h16xZ8fHzEvAvo8tqcPXsW3377Ldq0aYOPP/4YFy9exI4dO3D16lVcu3YNVlZWJeaiUqkwaNAgrF+/Hp999hkWLlz4Wp7fYhACUTHu3bsnABDat2//wnarV68W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6NFDbNO1a1fk5uZi5cqVyMrKQo0aNTBp0iStN+hPP/0Uq1evxsyZMyGRPLupxJAhQwwxJCIinTRq1Ah37tzRit29exfe3t7l6rdhw4bYsWMHNBqN+Eva3bt34eHhUaTQBYDFixcjNDQUdevWxbVr15Cfny8uU6lU0Gg05cqHiKiiGdUJasYmKSlJ68Q1IqJX5dKlS+jatSs+//xzdOnSBZcuXcIXX3yBb7/9Fu+//z6AZ2ckP378GP/++y8GDhyIFStWoGrVqnB3d4e7uzuAZ1/+PT09xekQjx8/RlhYGD744AMMHjwY9+7dw+eff44hQ4ZgzJgxWjnExMRgyJAh2LdvH2xsbJCdnY1GjRph8uTJcHNzw0cffYQTJ05o3cGSiOhVKe0Jaix2X4DFLhEZ0v79+/HNN9/g3r17eOONN/DRRx+hX79+4vJNmzaJ82wLGzduHD7//HMAQI8ePeDj44NFixaJy8+dO4fp06cjOjoalSpVQu/evcWrMRQQBAHdunXDyJEj8fbbb2vlNHnyZOTl5eHLL79E3759K2DkREQvx2JXD1jsEhERERmn0ha7RnW7YCIiIiIifTKqE9SIiJ7XokWeoVMg0nLiRNET+YjIePHILhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJsvC0AkUNnLkSCQlJRWJt2vXDkOHDkVeXh4iIiJw8uRJqFQqBAUFYejQoZDL5WLb5ORk/PLLL7h+/TqsrKwQEhKCvn37wtzc/BWOhIiIiIiMgVEVu/PmzYNGoxEfP3jwALNnz0azZs0AAOvWrcOFCxcwbtw42NjYYPXq1ViwYAFmzZoFANBoNJg3bx7kcjlmz54NhUKBZcuWwdzcHH379jXImIiIiIjIcIxq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uxbznTt3cPDgQcTHx8PMzAxVq1atyE1AREREBsJilyrc5cuX8cEHH4iPZ8yYAQD44IMP8M033+DOnTv46KOPkJKSAicnJwQFBSEyMhLVq1cXn3P//n2kpKSUqs9FixaJ8ezsbEyePBk//vgjzMye/ZDh5eWFWbNmYdy4cbC0tMSiRYtgbW1dIWMnIiIiw5IIgiAYOgljlZSUpPVzNxG9ei1a6G86C5E+nDhhaegUSoX7Dhkbfe87UqkUbm5uL23HObtEREREZLI4jeEV4TdsMkavyxEqIiIiXfHILhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyLAydQGHR0dHYuXMn7t27B4VCgfHjx6Nx48bickEQsHnzZkRFRSEzMxM1atTA0KFD4enpKbbJyMjAmjVrcP78eUgkEjRp0gSDBw+GlZWVIYZERERERAZkVEd2c3Nz4efnhw8//LDY5X/88Qf27t2LYcOGYe7cuZDJZJgzZw7y8vLENkuWLMHDhw8xZcoUfPXVV7hx4wZWrlz5qoZAREREREbEqIrd+vXro3fv3lpHcwsIgoA9e/bg/fffR6NGjeDr64tRo0ZBoVDg7NmzAIBHjx7h0qVLGD58OKpVq4YaNWpgyJAhOHnyJFJSUl71cIiIiIjIwIyq2H2RxMREpKamol69emLMxsYGAQEBiImJAQDExMTA1tYWVatWFdvUrVsXEokEsbGxJfatUqmQlZUl/svOzhaXSSQSSCQSrfYFsbLEiYxR4b/Nwn+/ZY0/36c+40TGRl/7zavcn4iMjT72m9Iyqjm7L5KamgoAcHR01Io7OjqKy1JTU+Hg4KC13NzcHHZ2dmKb4mzfvh1bt24VH1epUgXz58+Hg4MDBEEA8GyKRWZmJmxtbSGTycS22dnZyM7Ohr29PaRSqRjPzMxEbm4uHB0dYW5uDiBBh1ETVSwnJyco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\n"
|
| 468 |
-
},
|
| 469 |
-
"metadata": {}
|
| 470 |
-
}
|
| 471 |
]
|
| 472 |
},
|
| 473 |
{
|
| 474 |
"cell_type": "markdown",
|
| 475 |
-
"source": [
|
| 476 |
-
"Now that we understand our dataset and we have cleaned it, we need to save the cleaned dataset for future use."
|
| 477 |
-
],
|
| 478 |
"metadata": {
|
| 479 |
"id": "3vRxV6KQnNIR"
|
| 480 |
-
}
|
|
|
|
|
|
|
|
|
|
| 481 |
},
|
| 482 |
{
|
| 483 |
"cell_type": "code",
|
| 484 |
-
"
|
| 485 |
-
"df_train.to_csv('datasets/cleaned_financial_phrasebank.csv', index=False)"
|
| 486 |
-
],
|
| 487 |
"metadata": {
|
| 488 |
"id": "YbIbJHKfjX-c"
|
| 489 |
},
|
| 490 |
-
"
|
| 491 |
-
"
|
|
|
|
|
|
|
| 492 |
},
|
| 493 |
{
|
| 494 |
"cell_type": "markdown",
|
| 495 |
-
"source": [
|
| 496 |
-
"The following cell will only run if woring in colab."
|
| 497 |
-
],
|
| 498 |
"metadata": {
|
| 499 |
"id": "y6W5yvKS1yDA"
|
| 500 |
-
}
|
|
|
|
|
|
|
|
|
|
| 501 |
},
|
| 502 |
{
|
| 503 |
"cell_type": "code",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 504 |
"source": [
|
| 505 |
"if IN_COLAB:\n",
|
| 506 |
" REPO_NAME = 'finbert-sentiment-analyzer-api'\n",
|
|
@@ -530,37 +314,28 @@
|
|
| 530 |
" print(f\" - Error moving Figure: {e}\")\n",
|
| 531 |
"else:\n",
|
| 532 |
" print('Cell skipped (Not running in Google Colab environment).')"
|
| 533 |
-
],
|
| 534 |
-
"metadata": {
|
| 535 |
-
"colab": {
|
| 536 |
-
"base_uri": "https://localhost:8080/"
|
| 537 |
-
},
|
| 538 |
-
"id": "Hmctrq6KpQgY",
|
| 539 |
-
"outputId": "112e118b-c63b-40dd-e891-513158a1aca7"
|
| 540 |
-
},
|
| 541 |
-
"execution_count": 10,
|
| 542 |
-
"outputs": [
|
| 543 |
-
{
|
| 544 |
-
"output_type": "stream",
|
| 545 |
-
"name": "stdout",
|
| 546 |
-
"text": [
|
| 547 |
-
" - CSV file successfully updated in repo.\n",
|
| 548 |
-
" - Figure successfully updated in repo.\n"
|
| 549 |
-
]
|
| 550 |
-
}
|
| 551 |
]
|
| 552 |
},
|
| 553 |
{
|
| 554 |
"cell_type": "markdown",
|
| 555 |
-
"source": [
|
| 556 |
-
"### **Add new files to the repositoy**"
|
| 557 |
-
],
|
| 558 |
"metadata": {
|
| 559 |
"id": "KOtwYfds1fZv"
|
| 560 |
-
}
|
|
|
|
|
|
|
|
|
|
| 561 |
},
|
| 562 |
{
|
| 563 |
"cell_type": "code",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 564 |
"source": [
|
| 565 |
"if IN_COLAB:\n",
|
| 566 |
" print(\"Executing Git commands using explicit repository targeting...\")\n",
|
|
@@ -575,73 +350,42 @@
|
|
| 575 |
" print(\"\\n✅ Done! Check your GitHub repository to see the updated files.\")\n",
|
| 576 |
"else:\n",
|
| 577 |
" print('Cell skipped (Not running in Google Colab environment).')"
|
| 578 |
-
],
|
| 579 |
-
"metadata": {
|
| 580 |
-
"colab": {
|
| 581 |
-
"base_uri": "https://localhost:8080/"
|
| 582 |
-
},
|
| 583 |
-
"id": "vDT7YUz2s2jx",
|
| 584 |
-
"outputId": "f11c3b69-3cd8-4c92-fbd9-14c61f29dcb1"
|
| 585 |
-
},
|
| 586 |
-
"execution_count": 11,
|
| 587 |
-
"outputs": [
|
| 588 |
-
{
|
| 589 |
-
"output_type": "stream",
|
| 590 |
-
"name": "stdout",
|
| 591 |
-
"text": [
|
| 592 |
-
"Executing Git commands using explicit repository targeting...\n",
|
| 593 |
-
"On branch main\n",
|
| 594 |
-
"Your branch is ahead of 'origin/main' by 1 commit.\n",
|
| 595 |
-
" (use \"git push\" to publish your local commits)\n",
|
| 596 |
-
"\n",
|
| 597 |
-
"nothing to commit, working tree clean\n",
|
| 598 |
-
"On branch main\n",
|
| 599 |
-
"Your branch is ahead of 'origin/main' by 1 commit.\n",
|
| 600 |
-
" (use \"git push\" to publish your local commits)\n",
|
| 601 |
-
"\n",
|
| 602 |
-
"nothing to commit, working tree clean\n",
|
| 603 |
-
"remote: Enumerating objects: 11, done.\u001b[K\n",
|
| 604 |
-
"remote: Counting objects: 100% (11/11), done.\u001b[K\n",
|
| 605 |
-
"remote: Compressing objects: 100% (8/8), done.\u001b[K\n",
|
| 606 |
-
"remote: Total 8 (delta 4), reused 0 (delta 0), pack-reused 0 (from 0)\u001b[K\n",
|
| 607 |
-
"Unpacking objects: 100% (8/8), 2.46 KiB | 132.00 KiB/s, done.\n",
|
| 608 |
-
"From https://github.com/mobadara/finbert-sentiment-analyzer-api\n",
|
| 609 |
-
" * branch main -> FETCH_HEAD\n",
|
| 610 |
-
" 3cadbf6..ed946f7 main -> origin/main\n",
|
| 611 |
-
"\u001b[KSuccessfully rebased and updated refs/heads/main.\n",
|
| 612 |
-
"Enumerating objects: 7, done.\n",
|
| 613 |
-
"Counting objects: 100% (7/7), done.\n",
|
| 614 |
-
"Delta compression using up to 2 threads\n",
|
| 615 |
-
"Compressing objects: 100% (4/4), done.\n",
|
| 616 |
-
"Writing objects: 100% (4/4), 6.12 KiB | 521.00 KiB/s, done.\n",
|
| 617 |
-
"Total 4 (delta 2), reused 0 (delta 0), pack-reused 0\n",
|
| 618 |
-
"remote: Resolving deltas: 100% (2/2), completed with 2 local objects.\u001b[K\n",
|
| 619 |
-
"To https://github.com/mobadara/finbert-sentiment-analyzer-api.git\n",
|
| 620 |
-
" ed946f7..ee223d3 main -> main\n",
|
| 621 |
-
"\n",
|
| 622 |
-
"✅ Done! Check your GitHub repository to see the updated files.\n"
|
| 623 |
-
]
|
| 624 |
-
}
|
| 625 |
]
|
| 626 |
},
|
| 627 |
{
|
| 628 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 629 |
"source": [
|
| 630 |
"___\n",
|
| 631 |
"Muyiwa J. Obadara"
|
| 632 |
-
]
|
| 633 |
-
"metadata": {
|
| 634 |
-
"id": "xkHLyIZNBibU"
|
| 635 |
-
}
|
| 636 |
},
|
| 637 |
{
|
| 638 |
"cell_type": "code",
|
| 639 |
-
"
|
| 640 |
"metadata": {
|
| 641 |
"id": "FaTADiWUBm0U"
|
| 642 |
},
|
| 643 |
-
"
|
| 644 |
-
"
|
| 645 |
}
|
| 646 |
-
]
|
| 647 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
"cells": [
|
| 3 |
{
|
| 4 |
"cell_type": "markdown",
|
| 5 |
"metadata": {
|
| 6 |
+
"colab_type": "text",
|
| 7 |
+
"id": "view-in-github"
|
| 8 |
},
|
| 9 |
"source": [
|
| 10 |
"<a href=\"https://colab.research.google.com/github/mobadara/finbert-sentiment-analyzer-api/blob/main/notebooks/01_eda_and_data_engineering.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
|
|
|
| 12 |
},
|
| 13 |
{
|
| 14 |
"cell_type": "markdown",
|
| 15 |
+
"metadata": {
|
| 16 |
+
"id": "175c_DpCsGNf"
|
| 17 |
+
},
|
| 18 |
"source": [
|
| 19 |
"# **FINANCIAL NEWS SENTIMENT ANALYSIS**\n",
|
| 20 |
"## 📈 **EDA & Data Engineering**\n",
|
|
|
|
| 33 |
"* **Source:** `financial_phrasebank` (via Hugging Face Datasets)\n",
|
| 34 |
"* **Configuration:** `sentences_allagree` (Using only sentences where 100% of human annotators agreed on the sentiment)\n",
|
| 35 |
"* **Labels:** 0 (Negative), 1 (Neutral), 2 (Positive)"
|
| 36 |
+
]
|
|
|
|
|
|
|
|
|
|
| 37 |
},
|
| 38 |
{
|
| 39 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 40 |
"metadata": {
|
| 41 |
"id": "Gt4uyJvPtv-s"
|
| 42 |
+
},
|
| 43 |
+
"source": [
|
| 44 |
+
"### **Setup**"
|
| 45 |
+
]
|
| 46 |
},
|
| 47 |
{
|
| 48 |
"cell_type": "code",
|
| 49 |
+
"execution_count": null,
|
| 50 |
"metadata": {
|
| 51 |
"id": "oHA_z_6krqFa"
|
| 52 |
},
|
|
|
|
| 70 |
},
|
| 71 |
{
|
| 72 |
"cell_type": "code",
|
| 73 |
+
"execution_count": null,
|
|
|
|
|
|
|
|
|
|
| 74 |
"metadata": {
|
| 75 |
"id": "EpCL1HxowTni"
|
| 76 |
},
|
| 77 |
+
"outputs": [],
|
| 78 |
+
"source": [
|
| 79 |
+
"os.makedirs('figures', exist_ok=True)\n",
|
| 80 |
+
"os.makedirs('datasets', exist_ok=True)"
|
| 81 |
+
]
|
| 82 |
},
|
| 83 |
{
|
| 84 |
"cell_type": "code",
|
| 85 |
+
"execution_count": null,
|
|
|
|
|
|
|
| 86 |
"metadata": {
|
| 87 |
"id": "rLHOtOKrvMwg"
|
| 88 |
},
|
| 89 |
+
"outputs": [],
|
| 90 |
+
"source": [
|
| 91 |
+
"dataset = load_dataset('FinanceMTEB/financial_phrasebank')"
|
| 92 |
+
]
|
| 93 |
},
|
| 94 |
{
|
| 95 |
"cell_type": "code",
|
| 96 |
+
"execution_count": null,
|
|
|
|
|
|
|
| 97 |
"metadata": {
|
| 98 |
"colab": {
|
| 99 |
"base_uri": "https://localhost:8080/"
|
|
|
|
| 101 |
"id": "BC7Xjb0IvRhf",
|
| 102 |
"outputId": "bfe8f5b4-9a17-42b5-bb14-ac6ecd1cbd0f"
|
| 103 |
},
|
| 104 |
+
"outputs": [],
|
| 105 |
+
"source": [
|
| 106 |
+
"dataset"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
]
|
| 108 |
},
|
| 109 |
{
|
| 110 |
"cell_type": "markdown",
|
| 111 |
+
"metadata": {
|
| 112 |
+
"id": "KkoS3g2KxDfk"
|
| 113 |
+
},
|
| 114 |
"source": [
|
| 115 |
"The dataset has two splits:\n",
|
| 116 |
"1. Train Dataset contains 1264 instances.\n",
|
| 117 |
"2. Test Dataset contains 1000 instances.\n",
|
| 118 |
"\n",
|
| 119 |
"We need to convert the train dataset to a pandas datafrome exploration."
|
| 120 |
+
]
|
|
|
|
|
|
|
|
|
|
| 121 |
},
|
| 122 |
{
|
| 123 |
"cell_type": "code",
|
| 124 |
+
"execution_count": null,
|
|
|
|
|
|
|
|
|
|
| 125 |
"metadata": {
|
| 126 |
"colab": {
|
| 127 |
"base_uri": "https://localhost:8080/",
|
|
|
|
| 130 |
"id": "Fd4_eL-PwUNw",
|
| 131 |
"outputId": "2da09fc8-938d-4479-9460-da7cf774a1d4"
|
| 132 |
},
|
| 133 |
+
"outputs": [],
|
| 134 |
+
"source": [
|
| 135 |
+
"df_train = dataset['train'].to_pandas()\n",
|
| 136 |
+
"df_train.head()"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
]
|
| 138 |
},
|
| 139 |
{
|
| 140 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 141 |
"metadata": {
|
| 142 |
"id": "8G472RswiiTH"
|
| 143 |
+
},
|
| 144 |
+
"source": [
|
| 145 |
+
"### **Data Check and Cleaning**"
|
| 146 |
+
]
|
| 147 |
},
|
| 148 |
{
|
| 149 |
"cell_type": "code",
|
| 150 |
+
"execution_count": null,
|
| 151 |
+
"metadata": {
|
| 152 |
+
"colab": {
|
| 153 |
+
"base_uri": "https://localhost:8080/"
|
| 154 |
+
},
|
| 155 |
+
"id": "rotrrtnxishA",
|
| 156 |
+
"outputId": "8c8a8437-5c03-43f8-9292-0fb453b3c594"
|
| 157 |
+
},
|
| 158 |
+
"outputs": [],
|
| 159 |
"source": [
|
| 160 |
"# Check for `null` values\n",
|
| 161 |
"nulls_per_column = df_train.isna().sum()\n",
|
|
|
|
| 167 |
"print(nulls_per_column)\n",
|
| 168 |
"print(\"-\" * 30)\n",
|
| 169 |
"print(f\"Number of Duplicated Instances: {duplicated_instances}\")"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
]
|
| 171 |
},
|
| 172 |
{
|
| 173 |
"cell_type": "markdown",
|
| 174 |
+
"metadata": {
|
| 175 |
+
"id": "1T4BUAkbyjp0"
|
| 176 |
+
},
|
| 177 |
"source": [
|
| 178 |
"We see that our dataset (in tabular form) contains three columns: **text**, **label_text** and **label**.\n",
|
| 179 |
"\n",
|
|
|
|
| 184 |
"-----------|-----\n",
|
| 185 |
"negative | `0`\n",
|
| 186 |
"neutral | `1`\n",
|
| 187 |
+
"positive | `2`\n",
|
| 188 |
"\n",
|
| 189 |
"\n",
|
| 190 |
"We see from our result that one instance in the dataset is exactly repeated. We drop the duplicated values in the following cell."
|
| 191 |
+
]
|
|
|
|
|
|
|
|
|
|
| 192 |
},
|
| 193 |
{
|
| 194 |
"cell_type": "code",
|
| 195 |
+
"execution_count": null,
|
|
|
|
|
|
|
|
|
|
| 196 |
"metadata": {
|
| 197 |
"id": "HWZSAfqTkgtU"
|
| 198 |
},
|
| 199 |
+
"outputs": [],
|
| 200 |
+
"source": [
|
| 201 |
+
"df_train.drop_duplicates(inplace=True)\n",
|
| 202 |
+
"assert df_train.duplicated().sum() == 0"
|
| 203 |
+
]
|
| 204 |
},
|
| 205 |
{
|
| 206 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 207 |
"metadata": {
|
| 208 |
"id": "NzLiGGnnl2D2"
|
| 209 |
+
},
|
| 210 |
+
"source": [
|
| 211 |
+
"Now that the duplicated entries are removed, we need to visualize our class distribution."
|
| 212 |
+
]
|
| 213 |
},
|
| 214 |
{
|
| 215 |
"cell_type": "code",
|
| 216 |
+
"execution_count": null,
|
| 217 |
+
"metadata": {
|
| 218 |
+
"colab": {
|
| 219 |
+
"base_uri": "https://localhost:8080/",
|
| 220 |
+
"height": 492
|
| 221 |
+
},
|
| 222 |
+
"id": "FQs0xwBqyPP8",
|
| 223 |
+
"outputId": "0c838bcf-645b-4825-81d8-76ed1e442e3b"
|
| 224 |
+
},
|
| 225 |
+
"outputs": [],
|
| 226 |
"source": [
|
| 227 |
"plt.figure(figsize=(8, 5))\n",
|
| 228 |
"ax = sns.countplot(data=df_train,\n",
|
|
|
|
| 243 |
"\n",
|
| 244 |
"plt.savefig('figures/class_distribution.png')\n",
|
| 245 |
"plt.show()"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
]
|
| 247 |
},
|
| 248 |
{
|
| 249 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 250 |
"metadata": {
|
| 251 |
"id": "3vRxV6KQnNIR"
|
| 252 |
+
},
|
| 253 |
+
"source": [
|
| 254 |
+
"Now that we understand our dataset and we have cleaned it, we need to save the cleaned dataset for future use."
|
| 255 |
+
]
|
| 256 |
},
|
| 257 |
{
|
| 258 |
"cell_type": "code",
|
| 259 |
+
"execution_count": null,
|
|
|
|
|
|
|
| 260 |
"metadata": {
|
| 261 |
"id": "YbIbJHKfjX-c"
|
| 262 |
},
|
| 263 |
+
"outputs": [],
|
| 264 |
+
"source": [
|
| 265 |
+
"df_train.to_csv('datasets/cleaned_financial_phrasebank.csv', index=False)"
|
| 266 |
+
]
|
| 267 |
},
|
| 268 |
{
|
| 269 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 270 |
"metadata": {
|
| 271 |
"id": "y6W5yvKS1yDA"
|
| 272 |
+
},
|
| 273 |
+
"source": [
|
| 274 |
+
"The following cell will only run if woring in colab."
|
| 275 |
+
]
|
| 276 |
},
|
| 277 |
{
|
| 278 |
"cell_type": "code",
|
| 279 |
+
"execution_count": null,
|
| 280 |
+
"metadata": {
|
| 281 |
+
"colab": {
|
| 282 |
+
"base_uri": "https://localhost:8080/"
|
| 283 |
+
},
|
| 284 |
+
"id": "Hmctrq6KpQgY",
|
| 285 |
+
"outputId": "112e118b-c63b-40dd-e891-513158a1aca7"
|
| 286 |
+
},
|
| 287 |
+
"outputs": [],
|
| 288 |
"source": [
|
| 289 |
"if IN_COLAB:\n",
|
| 290 |
" REPO_NAME = 'finbert-sentiment-analyzer-api'\n",
|
|
|
|
| 314 |
" print(f\" - Error moving Figure: {e}\")\n",
|
| 315 |
"else:\n",
|
| 316 |
" print('Cell skipped (Not running in Google Colab environment).')"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
]
|
| 318 |
},
|
| 319 |
{
|
| 320 |
"cell_type": "markdown",
|
|
|
|
|
|
|
|
|
|
| 321 |
"metadata": {
|
| 322 |
"id": "KOtwYfds1fZv"
|
| 323 |
+
},
|
| 324 |
+
"source": [
|
| 325 |
+
"### **Add new files to the repositoy**"
|
| 326 |
+
]
|
| 327 |
},
|
| 328 |
{
|
| 329 |
"cell_type": "code",
|
| 330 |
+
"execution_count": null,
|
| 331 |
+
"metadata": {
|
| 332 |
+
"colab": {
|
| 333 |
+
"base_uri": "https://localhost:8080/"
|
| 334 |
+
},
|
| 335 |
+
"id": "vDT7YUz2s2jx",
|
| 336 |
+
"outputId": "f11c3b69-3cd8-4c92-fbd9-14c61f29dcb1"
|
| 337 |
+
},
|
| 338 |
+
"outputs": [],
|
| 339 |
"source": [
|
| 340 |
"if IN_COLAB:\n",
|
| 341 |
" print(\"Executing Git commands using explicit repository targeting...\")\n",
|
|
|
|
| 350 |
" print(\"\\n✅ Done! Check your GitHub repository to see the updated files.\")\n",
|
| 351 |
"else:\n",
|
| 352 |
" print('Cell skipped (Not running in Google Colab environment).')"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
]
|
| 354 |
},
|
| 355 |
{
|
| 356 |
"cell_type": "markdown",
|
| 357 |
+
"metadata": {
|
| 358 |
+
"id": "xkHLyIZNBibU"
|
| 359 |
+
},
|
| 360 |
"source": [
|
| 361 |
"___\n",
|
| 362 |
"Muyiwa J. Obadara"
|
| 363 |
+
]
|
|
|
|
|
|
|
|
|
|
| 364 |
},
|
| 365 |
{
|
| 366 |
"cell_type": "code",
|
| 367 |
+
"execution_count": null,
|
| 368 |
"metadata": {
|
| 369 |
"id": "FaTADiWUBm0U"
|
| 370 |
},
|
| 371 |
+
"outputs": [],
|
| 372 |
+
"source": []
|
| 373 |
}
|
| 374 |
+
],
|
| 375 |
+
"metadata": {
|
| 376 |
+
"colab": {
|
| 377 |
+
"authorship_tag": "ABX9TyN9T0T3HM5FCsd5NQ18TNLI",
|
| 378 |
+
"include_colab_link": true,
|
| 379 |
+
"provenance": []
|
| 380 |
+
},
|
| 381 |
+
"kernelspec": {
|
| 382 |
+
"display_name": "Python 3",
|
| 383 |
+
"name": "python3"
|
| 384 |
+
},
|
| 385 |
+
"language_info": {
|
| 386 |
+
"name": "python"
|
| 387 |
+
}
|
| 388 |
+
},
|
| 389 |
+
"nbformat": 4,
|
| 390 |
+
"nbformat_minor": 0
|
| 391 |
+
}
|
notebooks/02_fine_tuning.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebooks/eda_and_data_engineering.ipynb
DELETED
|
@@ -1,462 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"nbformat": 4,
|
| 3 |
-
"nbformat_minor": 0,
|
| 4 |
-
"metadata": {
|
| 5 |
-
"colab": {
|
| 6 |
-
"provenance": [],
|
| 7 |
-
"authorship_tag": "ABX9TyPMJfuOSBpHVnJTEJsqSxBA",
|
| 8 |
-
"include_colab_link": true
|
| 9 |
-
},
|
| 10 |
-
"kernelspec": {
|
| 11 |
-
"name": "python3",
|
| 12 |
-
"display_name": "Python 3"
|
| 13 |
-
},
|
| 14 |
-
"language_info": {
|
| 15 |
-
"name": "python"
|
| 16 |
-
}
|
| 17 |
-
},
|
| 18 |
-
"cells": [
|
| 19 |
-
{
|
| 20 |
-
"cell_type": "markdown",
|
| 21 |
-
"metadata": {
|
| 22 |
-
"id": "view-in-github",
|
| 23 |
-
"colab_type": "text"
|
| 24 |
-
},
|
| 25 |
-
"source": [
|
| 26 |
-
"<a href=\"https://colab.research.google.com/github/mobadara/finbert-sentiment-analyzer-api/blob/main/notebooks/eda_and_data_engineering.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
| 27 |
-
]
|
| 28 |
-
},
|
| 29 |
-
{
|
| 30 |
-
"cell_type": "markdown",
|
| 31 |
-
"source": [
|
| 32 |
-
"# **FINANCIAL NEWS SENTIMENT ANALYSIS**\n",
|
| 33 |
-
"## 📈 **EDA & Data Engineering**\n",
|
| 34 |
-
"\n",
|
| 35 |
-
"\n",
|
| 36 |
-
"**Author:** [Muyiwa J. Obadara](https://portfolio-frontend-livid.vercel.app)\n",
|
| 37 |
-
"\n",
|
| 38 |
-
"**Project:** FinBERT Sentiment API Backend\n",
|
| 39 |
-
"\n",
|
| 40 |
-
"### **Objective**\n",
|
| 41 |
-
"The goal of this notebook is to perform Exploratory Data Analysis (EDA) and preprocess the **[Financial PhraseBank](https://huggingface.co/datasets/FinanceMTEB/financial_phrasebank)** dataset. Financial text is highly specialized; words that represent positive sentiment in a general context might represent risk in a financial context.\n",
|
| 42 |
-
"\n",
|
| 43 |
-
"By analyzing the class distributions and cleaning the text, we will create a highly optimized dataset ready to fine-tune the `ProsusAI/finbert` model in the next phase of this pipeline.\n",
|
| 44 |
-
"\n",
|
| 45 |
-
"### **Dataset Details**\n",
|
| 46 |
-
"* **Source:** `financial_phrasebank` (via Hugging Face Datasets)\n",
|
| 47 |
-
"* **Configuration:** `sentences_allagree` (Using only sentences where 100% of human annotators agreed on the sentiment)\n",
|
| 48 |
-
"* **Labels:** 0 (Negative), 1 (Neutral), 2 (Positive)"
|
| 49 |
-
],
|
| 50 |
-
"metadata": {
|
| 51 |
-
"id": "175c_DpCsGNf"
|
| 52 |
-
}
|
| 53 |
-
},
|
| 54 |
-
{
|
| 55 |
-
"cell_type": "markdown",
|
| 56 |
-
"source": [
|
| 57 |
-
"### **Setup**"
|
| 58 |
-
],
|
| 59 |
-
"metadata": {
|
| 60 |
-
"id": "Gt4uyJvPtv-s"
|
| 61 |
-
}
|
| 62 |
-
},
|
| 63 |
-
{
|
| 64 |
-
"cell_type": "code",
|
| 65 |
-
"execution_count": 1,
|
| 66 |
-
"metadata": {
|
| 67 |
-
"id": "oHA_z_6krqFa"
|
| 68 |
-
},
|
| 69 |
-
"outputs": [],
|
| 70 |
-
"source": [
|
| 71 |
-
"from datasets import load_dataset\n",
|
| 72 |
-
"import pandas as pd\n",
|
| 73 |
-
"import matplotlib.pyplot as plt\n",
|
| 74 |
-
"import seaborn as sns\n",
|
| 75 |
-
"plt.style.use('ggplot')\n",
|
| 76 |
-
"plt.rcParams['axes.prop_cycle'] = plt.cycler(color=['blue'])"
|
| 77 |
-
]
|
| 78 |
-
},
|
| 79 |
-
{
|
| 80 |
-
"cell_type": "code",
|
| 81 |
-
"source": [
|
| 82 |
-
"dataset = load_dataset('FinanceMTEB/financial_phrasebank')"
|
| 83 |
-
],
|
| 84 |
-
"metadata": {
|
| 85 |
-
"id": "rLHOtOKrvMwg"
|
| 86 |
-
},
|
| 87 |
-
"execution_count": 2,
|
| 88 |
-
"outputs": []
|
| 89 |
-
},
|
| 90 |
-
{
|
| 91 |
-
"cell_type": "code",
|
| 92 |
-
"source": [
|
| 93 |
-
"dataset"
|
| 94 |
-
],
|
| 95 |
-
"metadata": {
|
| 96 |
-
"colab": {
|
| 97 |
-
"base_uri": "https://localhost:8080/"
|
| 98 |
-
},
|
| 99 |
-
"id": "BC7Xjb0IvRhf",
|
| 100 |
-
"outputId": "a72c0d4d-9e8b-422f-eb27-3b26608fd0ab"
|
| 101 |
-
},
|
| 102 |
-
"execution_count": 3,
|
| 103 |
-
"outputs": [
|
| 104 |
-
{
|
| 105 |
-
"output_type": "execute_result",
|
| 106 |
-
"data": {
|
| 107 |
-
"text/plain": [
|
| 108 |
-
"DatasetDict({\n",
|
| 109 |
-
" train: Dataset({\n",
|
| 110 |
-
" features: ['text', 'label_text', 'label'],\n",
|
| 111 |
-
" num_rows: 1264\n",
|
| 112 |
-
" })\n",
|
| 113 |
-
" test: Dataset({\n",
|
| 114 |
-
" features: ['text', 'label_text', 'label'],\n",
|
| 115 |
-
" num_rows: 1000\n",
|
| 116 |
-
" })\n",
|
| 117 |
-
"})"
|
| 118 |
-
]
|
| 119 |
-
},
|
| 120 |
-
"metadata": {},
|
| 121 |
-
"execution_count": 3
|
| 122 |
-
}
|
| 123 |
-
]
|
| 124 |
-
},
|
| 125 |
-
{
|
| 126 |
-
"cell_type": "markdown",
|
| 127 |
-
"source": [
|
| 128 |
-
"The dataset has two splits:\n",
|
| 129 |
-
"1. Train Dataset contains 1264 instances.\n",
|
| 130 |
-
"2. Test Dataset contains 1000 instances.\n",
|
| 131 |
-
"\n",
|
| 132 |
-
"We need to convert the train dataset to a pandas datafrome exploration."
|
| 133 |
-
],
|
| 134 |
-
"metadata": {
|
| 135 |
-
"id": "KkoS3g2KxDfk"
|
| 136 |
-
}
|
| 137 |
-
},
|
| 138 |
-
{
|
| 139 |
-
"cell_type": "code",
|
| 140 |
-
"source": [
|
| 141 |
-
"df_train = dataset['train'].to_pandas()\n",
|
| 142 |
-
"df_train.head()"
|
| 143 |
-
],
|
| 144 |
-
"metadata": {
|
| 145 |
-
"colab": {
|
| 146 |
-
"base_uri": "https://localhost:8080/",
|
| 147 |
-
"height": 206
|
| 148 |
-
},
|
| 149 |
-
"id": "Fd4_eL-PwUNw",
|
| 150 |
-
"outputId": "1b6f9fdc-d9fa-47bf-ef42-09a9952b7a09"
|
| 151 |
-
},
|
| 152 |
-
"execution_count": 4,
|
| 153 |
-
"outputs": [
|
| 154 |
-
{
|
| 155 |
-
"output_type": "execute_result",
|
| 156 |
-
"data": {
|
| 157 |
-
"text/plain": [
|
| 158 |
-
" text label_text label\n",
|
| 159 |
-
"0 The Samsung Mobile Applications Store was laun... neutral 1\n",
|
| 160 |
-
"1 F-Secure , a developer of security solutions a... neutral 1\n",
|
| 161 |
-
"2 The company serves customers in various indust... neutral 1\n",
|
| 162 |
-
"3 The company reported net sales of 302 mln euro... neutral 1\n",
|
| 163 |
-
"4 Microsoft last week also issued the first patc... neutral 1"
|
| 164 |
-
],
|
| 165 |
-
"text/html": [
|
| 166 |
-
"\n",
|
| 167 |
-
" <div id=\"df-499d12bd-abf1-4494-9c02-9cc3895cae4e\" class=\"colab-df-container\">\n",
|
| 168 |
-
" <div>\n",
|
| 169 |
-
"<style scoped>\n",
|
| 170 |
-
" .dataframe tbody tr th:only-of-type {\n",
|
| 171 |
-
" vertical-align: middle;\n",
|
| 172 |
-
" }\n",
|
| 173 |
-
"\n",
|
| 174 |
-
" .dataframe tbody tr th {\n",
|
| 175 |
-
" vertical-align: top;\n",
|
| 176 |
-
" }\n",
|
| 177 |
-
"\n",
|
| 178 |
-
" .dataframe thead th {\n",
|
| 179 |
-
" text-align: right;\n",
|
| 180 |
-
" }\n",
|
| 181 |
-
"</style>\n",
|
| 182 |
-
"<table border=\"1\" class=\"dataframe\">\n",
|
| 183 |
-
" <thead>\n",
|
| 184 |
-
" <tr style=\"text-align: right;\">\n",
|
| 185 |
-
" <th></th>\n",
|
| 186 |
-
" <th>text</th>\n",
|
| 187 |
-
" <th>label_text</th>\n",
|
| 188 |
-
" <th>label</th>\n",
|
| 189 |
-
" </tr>\n",
|
| 190 |
-
" </thead>\n",
|
| 191 |
-
" <tbody>\n",
|
| 192 |
-
" <tr>\n",
|
| 193 |
-
" <th>0</th>\n",
|
| 194 |
-
" <td>The Samsung Mobile Applications Store was laun...</td>\n",
|
| 195 |
-
" <td>neutral</td>\n",
|
| 196 |
-
" <td>1</td>\n",
|
| 197 |
-
" </tr>\n",
|
| 198 |
-
" <tr>\n",
|
| 199 |
-
" <th>1</th>\n",
|
| 200 |
-
" <td>F-Secure , a developer of security solutions a...</td>\n",
|
| 201 |
-
" <td>neutral</td>\n",
|
| 202 |
-
" <td>1</td>\n",
|
| 203 |
-
" </tr>\n",
|
| 204 |
-
" <tr>\n",
|
| 205 |
-
" <th>2</th>\n",
|
| 206 |
-
" <td>The company serves customers in various indust...</td>\n",
|
| 207 |
-
" <td>neutral</td>\n",
|
| 208 |
-
" <td>1</td>\n",
|
| 209 |
-
" </tr>\n",
|
| 210 |
-
" <tr>\n",
|
| 211 |
-
" <th>3</th>\n",
|
| 212 |
-
" <td>The company reported net sales of 302 mln euro...</td>\n",
|
| 213 |
-
" <td>neutral</td>\n",
|
| 214 |
-
" <td>1</td>\n",
|
| 215 |
-
" </tr>\n",
|
| 216 |
-
" <tr>\n",
|
| 217 |
-
" <th>4</th>\n",
|
| 218 |
-
" <td>Microsoft last week also issued the first patc...</td>\n",
|
| 219 |
-
" <td>neutral</td>\n",
|
| 220 |
-
" <td>1</td>\n",
|
| 221 |
-
" </tr>\n",
|
| 222 |
-
" </tbody>\n",
|
| 223 |
-
"</table>\n",
|
| 224 |
-
"</div>\n",
|
| 225 |
-
" <div class=\"colab-df-buttons\">\n",
|
| 226 |
-
"\n",
|
| 227 |
-
" <div class=\"colab-df-container\">\n",
|
| 228 |
-
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-499d12bd-abf1-4494-9c02-9cc3895cae4e')\"\n",
|
| 229 |
-
" title=\"Convert this dataframe to an interactive table.\"\n",
|
| 230 |
-
" style=\"display:none;\">\n",
|
| 231 |
-
"\n",
|
| 232 |
-
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n",
|
| 233 |
-
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n",
|
| 234 |
-
" </svg>\n",
|
| 235 |
-
" </button>\n",
|
| 236 |
-
"\n",
|
| 237 |
-
" <style>\n",
|
| 238 |
-
" .colab-df-container {\n",
|
| 239 |
-
" display:flex;\n",
|
| 240 |
-
" gap: 12px;\n",
|
| 241 |
-
" }\n",
|
| 242 |
-
"\n",
|
| 243 |
-
" .colab-df-convert {\n",
|
| 244 |
-
" background-color: #E8F0FE;\n",
|
| 245 |
-
" border: none;\n",
|
| 246 |
-
" border-radius: 50%;\n",
|
| 247 |
-
" cursor: pointer;\n",
|
| 248 |
-
" display: none;\n",
|
| 249 |
-
" fill: #1967D2;\n",
|
| 250 |
-
" height: 32px;\n",
|
| 251 |
-
" padding: 0 0 0 0;\n",
|
| 252 |
-
" width: 32px;\n",
|
| 253 |
-
" }\n",
|
| 254 |
-
"\n",
|
| 255 |
-
" .colab-df-convert:hover {\n",
|
| 256 |
-
" background-color: #E2EBFA;\n",
|
| 257 |
-
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n",
|
| 258 |
-
" fill: #174EA6;\n",
|
| 259 |
-
" }\n",
|
| 260 |
-
"\n",
|
| 261 |
-
" .colab-df-buttons div {\n",
|
| 262 |
-
" margin-bottom: 4px;\n",
|
| 263 |
-
" }\n",
|
| 264 |
-
"\n",
|
| 265 |
-
" [theme=dark] .colab-df-convert {\n",
|
| 266 |
-
" background-color: #3B4455;\n",
|
| 267 |
-
" fill: #D2E3FC;\n",
|
| 268 |
-
" }\n",
|
| 269 |
-
"\n",
|
| 270 |
-
" [theme=dark] .colab-df-convert:hover {\n",
|
| 271 |
-
" background-color: #434B5C;\n",
|
| 272 |
-
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n",
|
| 273 |
-
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n",
|
| 274 |
-
" fill: #FFFFFF;\n",
|
| 275 |
-
" }\n",
|
| 276 |
-
" </style>\n",
|
| 277 |
-
"\n",
|
| 278 |
-
" <script>\n",
|
| 279 |
-
" const buttonEl =\n",
|
| 280 |
-
" document.querySelector('#df-499d12bd-abf1-4494-9c02-9cc3895cae4e button.colab-df-convert');\n",
|
| 281 |
-
" buttonEl.style.display =\n",
|
| 282 |
-
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n",
|
| 283 |
-
"\n",
|
| 284 |
-
" async function convertToInteractive(key) {\n",
|
| 285 |
-
" const element = document.querySelector('#df-499d12bd-abf1-4494-9c02-9cc3895cae4e');\n",
|
| 286 |
-
" const dataTable =\n",
|
| 287 |
-
" await google.colab.kernel.invokeFunction('convertToInteractive',\n",
|
| 288 |
-
" [key], {});\n",
|
| 289 |
-
" if (!dataTable) return;\n",
|
| 290 |
-
"\n",
|
| 291 |
-
" const docLinkHtml = 'Like what you see? Visit the ' +\n",
|
| 292 |
-
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n",
|
| 293 |
-
" + ' to learn more about interactive tables.';\n",
|
| 294 |
-
" element.innerHTML = '';\n",
|
| 295 |
-
" dataTable['output_type'] = 'display_data';\n",
|
| 296 |
-
" await google.colab.output.renderOutput(dataTable, element);\n",
|
| 297 |
-
" const docLink = document.createElement('div');\n",
|
| 298 |
-
" docLink.innerHTML = docLinkHtml;\n",
|
| 299 |
-
" element.appendChild(docLink);\n",
|
| 300 |
-
" }\n",
|
| 301 |
-
" </script>\n",
|
| 302 |
-
" </div>\n",
|
| 303 |
-
"\n",
|
| 304 |
-
"\n",
|
| 305 |
-
" </div>\n",
|
| 306 |
-
" </div>\n"
|
| 307 |
-
],
|
| 308 |
-
"application/vnd.google.colaboratory.intrinsic+json": {
|
| 309 |
-
"type": "dataframe",
|
| 310 |
-
"variable_name": "df_train",
|
| 311 |
-
"summary": "{\n \"name\": \"df_train\",\n \"rows\": 1264,\n \"fields\": [\n {\n \"column\": \"text\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 1263,\n \"samples\": [\n \"R&D Loan ) .\",\n \"Mr. Mikko Saavalainen , head of Comptel 's Global Sales concludes : `` Gibtelecom provides a perfect illustration of the variety of business , technical and regulatory challenges operators are facing in their OSS today .\",\n \"The decision reflects the underutilisation of the line , which produces nonwovens used in medical and wipes applications as well as for the automotive industry .\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"label_text\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"neutral\",\n \"positive\",\n \"negative\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"label\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 2,\n \"num_unique_values\": 3,\n \"samples\": [\n 1,\n 2,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
|
| 312 |
-
}
|
| 313 |
-
},
|
| 314 |
-
"metadata": {},
|
| 315 |
-
"execution_count": 4
|
| 316 |
-
}
|
| 317 |
-
]
|
| 318 |
-
},
|
| 319 |
-
{
|
| 320 |
-
"cell_type": "markdown",
|
| 321 |
-
"source": [
|
| 322 |
-
"### **Data Check and Cleaning**"
|
| 323 |
-
],
|
| 324 |
-
"metadata": {
|
| 325 |
-
"id": "8G472RswiiTH"
|
| 326 |
-
}
|
| 327 |
-
},
|
| 328 |
-
{
|
| 329 |
-
"cell_type": "code",
|
| 330 |
-
"source": [
|
| 331 |
-
"# Check for `null` values\n",
|
| 332 |
-
"nulls_per_column = df_train.isna().sum()\n",
|
| 333 |
-
"\n",
|
| 334 |
-
"# Check for duplicated values\n",
|
| 335 |
-
"duplicated_instances = df_train.duplicated().sum()\n",
|
| 336 |
-
"\n",
|
| 337 |
-
"print(\"Null Values Per Column:\")\n",
|
| 338 |
-
"print(nulls_per_column)\n",
|
| 339 |
-
"print(\"-\" * 30)\n",
|
| 340 |
-
"print(f\"Number of Duplicated Instances: {duplicated_instances}\")"
|
| 341 |
-
],
|
| 342 |
-
"metadata": {
|
| 343 |
-
"colab": {
|
| 344 |
-
"base_uri": "https://localhost:8080/"
|
| 345 |
-
},
|
| 346 |
-
"id": "rotrrtnxishA",
|
| 347 |
-
"outputId": "9a73f6eb-897e-4da7-ac1d-c6e02eec3678"
|
| 348 |
-
},
|
| 349 |
-
"execution_count": 5,
|
| 350 |
-
"outputs": [
|
| 351 |
-
{
|
| 352 |
-
"output_type": "stream",
|
| 353 |
-
"name": "stdout",
|
| 354 |
-
"text": [
|
| 355 |
-
"Null Values Per Column:\n",
|
| 356 |
-
"text 0\n",
|
| 357 |
-
"label_text 0\n",
|
| 358 |
-
"label 0\n",
|
| 359 |
-
"dtype: int64\n",
|
| 360 |
-
"------------------------------\n",
|
| 361 |
-
"Number of Duplicated Instances: 1\n"
|
| 362 |
-
]
|
| 363 |
-
}
|
| 364 |
-
]
|
| 365 |
-
},
|
| 366 |
-
{
|
| 367 |
-
"cell_type": "markdown",
|
| 368 |
-
"source": [
|
| 369 |
-
"We see that our dataset (in tabular form) contains three columns: **text**, **label_text** and **label**.\n",
|
| 370 |
-
"\n",
|
| 371 |
-
"The **`label_text`** has three unique represents the sentiments of each text in human redable form, which are **positive**, **negative** or **neutral**.\n",
|
| 372 |
-
"\n",
|
| 373 |
-
"Each of this is encoded in the `label` as follows:\n",
|
| 374 |
-
"label_text | code\n",
|
| 375 |
-
"-----------|-----\n",
|
| 376 |
-
"negative | `0`\n",
|
| 377 |
-
"neutral | `1`\n",
|
| 378 |
-
"positive | `1`\n",
|
| 379 |
-
"\n",
|
| 380 |
-
"\n",
|
| 381 |
-
"We see from our result that one instance in the dataset is exactly repeated. We drop the duplicated values in the following cell."
|
| 382 |
-
],
|
| 383 |
-
"metadata": {
|
| 384 |
-
"id": "1T4BUAkbyjp0"
|
| 385 |
-
}
|
| 386 |
-
},
|
| 387 |
-
{
|
| 388 |
-
"cell_type": "code",
|
| 389 |
-
"source": [
|
| 390 |
-
"df_train.drop_duplicates(inplace=True)\n",
|
| 391 |
-
"assert df_train.duplicated().sum() == 0"
|
| 392 |
-
],
|
| 393 |
-
"metadata": {
|
| 394 |
-
"id": "HWZSAfqTkgtU"
|
| 395 |
-
},
|
| 396 |
-
"execution_count": 7,
|
| 397 |
-
"outputs": []
|
| 398 |
-
},
|
| 399 |
-
{
|
| 400 |
-
"cell_type": "markdown",
|
| 401 |
-
"source": [
|
| 402 |
-
"Now that the duplicated entries are removed, we need to visualize our class distribution."
|
| 403 |
-
],
|
| 404 |
-
"metadata": {
|
| 405 |
-
"id": "NzLiGGnnl2D2"
|
| 406 |
-
}
|
| 407 |
-
},
|
| 408 |
-
{
|
| 409 |
-
"cell_type": "code",
|
| 410 |
-
"source": [
|
| 411 |
-
"plt.figure(figsize=(8, 5))\n",
|
| 412 |
-
"ax = sns.countplot(data=df_train,\n",
|
| 413 |
-
" x='label_text',\n",
|
| 414 |
-
" order=['negative', 'neutral', 'positive'])\n",
|
| 415 |
-
"plt.title('Distribution of Sentiments in Financial PhraseBank', fontsize=14)\n",
|
| 416 |
-
"plt.ylabel('Number of Sentences', fontsize=12)\n",
|
| 417 |
-
"plt.xlabel('Sentiment', fontsize=12)\n",
|
| 418 |
-
"plt.grid(axis='y', linestyle='--', alpha=0.7)\n",
|
| 419 |
-
"\n",
|
| 420 |
-
"# Add percentages on top of each bar\n",
|
| 421 |
-
"total = len(df_train)\n",
|
| 422 |
-
"for p in ax.patches:\n",
|
| 423 |
-
" percentage = '{:.1f}%'.format(100 * p.get_height()/total)\n",
|
| 424 |
-
" x = p.get_x() + p.get_width() / 2\n",
|
| 425 |
-
" y = p.get_height()\n",
|
| 426 |
-
" ax.annotate(percentage, (x, y), ha='center', va='bottom')\n",
|
| 427 |
-
"\n",
|
| 428 |
-
"plt.show()"
|
| 429 |
-
],
|
| 430 |
-
"metadata": {
|
| 431 |
-
"colab": {
|
| 432 |
-
"base_uri": "https://localhost:8080/",
|
| 433 |
-
"height": 492
|
| 434 |
-
},
|
| 435 |
-
"id": "FQs0xwBqyPP8",
|
| 436 |
-
"outputId": "13afcab9-fbd1-4dbc-e632-3fecc2fae869"
|
| 437 |
-
},
|
| 438 |
-
"execution_count": 11,
|
| 439 |
-
"outputs": [
|
| 440 |
-
{
|
| 441 |
-
"output_type": "display_data",
|
| 442 |
-
"data": {
|
| 443 |
-
"text/plain": [
|
| 444 |
-
"<Figure size 800x500 with 1 Axes>"
|
| 445 |
-
],
|
| 446 |
-
"image/png": "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1atXR8+ePfHbb79hx44dGD16dIlt4+Pj0bhxY2RmZqJTp07o1asXMjMzcfv2baxYsQLff/89LCwsMG3aNKxduxb379/HtGnTxOcHBwdr9RcbG4umTZuibt26GDRoEJ4+fVqqI44LFy5EVFQUevXqhU6dOuHAgQNYtGgRTp06haNHj0IqlZZ5O8jlckybNg2LFi0CAHz22WfispedXBATE4OWLVsiKSkJXbp0Qe3atXHt2jWsWbMGf/75J44fP47AwMAiz+vTpw/OnDmDDh06wNzcHJs3b8bIkSMhlUoxbNiwUuX96aefYunSpfD29saHH34IANi2bRsGDx6MixcvYvHixVpjeH58crn8hf0X/PQZExNTqnyAZ1Nl3nnnHRw+fBjBwcH48MMPoVKpsHv3bnTt2hVLly4t9uftL774AkeOHEHnzp3Rvn177NixA9OnT0deXh7mzJkDAHjvvfeQmpqKP/74A127di3yN/Uyp0+fxvz589G+fXt8/PHHOHToEH788UekpaWhS5cuGDRoELp27YpmzZph9+7d+O6772BnZ4epU6dq9TNx4kR888038Pb2xvvvvw9HR0ccO3YMX3zxBU6fPo0tW7YUWffOnTuxe/dudOnSBc2bN8fRo0cRERGBO3fu4Pjx4wCe7SNjxozB4sWLERQUhPfee098fsEXk/DwcGzevBn16tXD4MGDIZPJ8PDhQxw6dAhnz55FUFBQmbbJ80rzOrwKpd0/jh49igULFuCtt95CkyZNIJVKcfHiRfz444/4+++/ceHChWKnSpRlnJ9//jkWLlwIZ2dnvPfee3B3d8fDhw9x4MABvPnmm6hTp84LxzJy5EgEBQWhbdu2cHNzw+PHj7Fjxw60bdsWkZGR6Nq1q342WgmeP39CpVKhXbt2UCgU6N69O7KysrBx40b07NkTf/31F9q1a1ekj9GjR+PUqVPo1KkTunTpAnd3dwBl2/6CIKB9+/Y4ffo0WrRogXfeeQdmZma4f/8+du7ciQEDBsDX11ds269fP2zYsAHVqlVD3759YWlpif379+PDDz9EdHQ0vv/++1KN//79+7h16xZ8fHzEvAvo8tqcPXsW3377Ldq0aYOPP/4YFy9exI4dO3D16lVcu3YNVlZWJeaiUqkwaNAgrF+/Hp999hkWLlz4Wp7fYhACUTHu3bsnABDat2//wnarV68WAAgDBgwQY4cOHRIACNOmTRNjS5YsEQAIixYtKtLH06dPtR6HhIQIJf1pFuQFQJg6dWqxbXx9fQVfX1+t2LRp0wQAgqWlpXD58mUxrtFohL59+woAhO+///6FY3g+h/Dw8Jeu92XPadOmjQBAWLlypVZ8+fLlAgAhLCxMK16wbZo0aSIolUoxfvPmTcHCwkKoXr16set/3pEjRwQAQs2aNYXU1FQxnpKSIgQGBgoAhKNHj5Z6fMV5+PCh4ODgIEgkEqFv377Cli1bhLi4uBc+Z9KkSQIA4euvvxY0Go0YT0tLExo2bChYWloKjx8/FuPh4eECAKFKlSpCfHy8GE9KShLkcrlgb28v5ObmivFff/1VACD8+uuvxa6/oL979+6JsYK/BQDCjh07xHheXp5Qr149QSKRCK6ursKZM2e08nV3dxecnZ2FvLw8Mb5v3z5xv8rIyBDjGo1GGD58uABA2Lp1a5F8LSwshOPHj4txtVothIaGCgCEf/75R4yX9HcmCIKQmpoqSCQS4c033xTUarXWMrVaLSgUimK3yfMACCEhIVqxsr4OL+vfxcVFmDZtWpF/e/fufeE4y7p//Pvvv0J6enqRHNatWycAEGbPnl2ucf75558CAKFu3bpCcnKyVl8qlUpISEgQHxe8Rx06dEir3d27d4vkFx8fL3h5eQnVqlXTir/o9S9Owd/XvHnziuQWFhYmABBmzJghxn19fQUAQteuXbXGeeDAgWI/Lwq2l4+Pj3D//v0i6y/L9r9y5YoAQHjvvfeKtM/JydHq5+effxYACIMHD9ba/3Jzc4UuXboIAIRz584V2Q5vvfWW+Lc2efJkITw8XHBychLc3d2FAwcOFFlvWV6bwu8jGzdu1Fo2YMAAAYCwYcMGrXjhfS09PV1o165dsa8XvRyLXSpWaYvdvXv3CgCEDh06iLEXFbvPF3XFKU2xW6lSpRI/PF9U7A4dOrRI+7i4OMHc3FyoU6fOC8fwfA7lLXbv378vABBq1aqlVdgJgiDk5+cLNWrUEAAIDx48EOMF2+bgwYNF1lGwLC0trdgcChsyZIgAQNi0aVORZb///rsAQBgyZEipx1eS/fv3C5UrVxbf5AEIbm5uQs+ePYWoqCittvn5+YKTk5NQtWrVIttDEARh586dAgBh6dKlYqzgw3TNmjVF2hcsu3LlihgrT7Hbpk2bIu1nzpwpfqg+r2AbF/5AfPfddwUAxX7wFxSj3bt3L5LvwIEDi7QvWLZkyRIx9qJiR6lUCgCEFi1aFLt9S+tFxW5pX4eX9V/SvzFjxgiC8PJit7z7h0ajERwcHITQ0NByjbNDhw4l5vO8kordkowePVoAoPUFUtdit3CRN2rUKKFatWpiUV/4YERBsVtckefr6ys4OztrxQq2yeLFi0uVT4Hitn9BsdunT5+XPr9evXqCra2tkJWVVWRZQT+ff/65GCvYDsX9s7CwEEaNGiX8+++/pc6/uNem4H2kdevWRdoXLBs3bpxWvGBfS0pKEho1aiSYm5sX+7dHL8dpDPRKdOnSBRMnTsTIkSMRFRWFd955ByEhIfD399epv6CgoFKfKFVYq1atisR8fX3xxhtv4Pr168jLy9OpX10UXEIpJCSkyE9RZmZmaN26NW7evIlLly7hjTfe0Fr+5ptvFunPx8cHwLMTv+zt7V+47osXLwIofppFmzZttPIrj7Zt2+LOnTs4fPgwjh49ivPnz+P48ePYvHkzNm/ejIkTJ2Lu3LkAgFu3bkGhUMDLywszZswo0ldSUhIA4ObNm0WWvWx76ENx0x4KTmZ70bL4+HhxLu2pU6dga2tb4rxBa2vrChufg4MDOnbsiD179qBBgwb44IMPEBoaikaNGuk0fac4+nodqlevXux20FcehfePyMhIrFy5EhcuXIBCodCaNx0fH69T/wXOnDkDmUxWriuO3L17F/PmzcPBgwfx+PFj5Obmai2Pj48Xf77XVVRUlHgVm4J5s+PGjcPEiRPh7Oys1VYul4t/z4X5+PiI8/Sf17hx4xLXXdrtX7NmTdSrVw8bNmzAo0eP8N577yE0NBTBwcEwM/v/04+ysrJw9epVeHl5Yf78+UXWVzDHtbi/r4KrsQCARqPBkydPsGPHDnz++efYs2dPkWkturw2Zd1H/v33X7Ro0QIPHz7E9u3b0aVLlyJt6OVY7FK5FLwZubm5vbCdn58fTp06henTp2PPnj3YvHkzgGdnVM+cORMffPBBmdbr4eGhU74lPc/DwwNxcXFIT09/ZZfZSUtLe2FOBcVSQbvCijvhy8Li2e78/ElOJa3bzMys2NfNw8MDEomk2PXqwsLCAm3btkXbtm0BPLukz9q1a/HJJ59g3rx56NGjBxo0aICUlBQAwPXr13H9+vUS+8vMzCwSK+/2KI0XreNFywqfQJKSkgK1Wl1sMV+gIse3ZcsWzJ07F+vXr8fkyZPFvgcPHoy5c+eW+5Jir+J10GceCxYswPjx4+Hm5oZ27drBx8dHPNt+0aJFRYqXsvavVCrh7e2tVYyVRWxsLBo3boy0tDS0adMGXbp0gYODA8zMzHD48GEcOXKkxBzLonCR9zIlXe7NwsKixBP0SnqPK8v2t7CwwMGDBzF9+nRs27YNn3/+OYBnnz2jRo3C5MmTYW5uDoVCAUEQ8Pjx4zLvZ4WZmZnB29sbI0eOxJMnTzBnzhwsW7ZM3G90fW3Kuo88efIEaWlpCAgIQJMmTV6YM5WMxS6VS8GZw40aNXpp2zp16mDr1q1QqVQ4f/489u7diyVLlqBXr17w8vJCixYtSr1eXSfl//vvvyXGJRKJeMSn4MOpuLPplUqlTut+XsGbXkk5JSQkaLXTJwcHB2g0GiQlJRU56SIxMRGCIFTIeoFnb+xDhw7FsWPHEBERgUOHDqFBgwbi+rp3717smd2mwMHBARKJxGAX67exscHs2bMxe/Zs3Lt3D4cOHcJPP/2ExYsXIzs7GytXrjRIXoagVqsxa9YseHp64tKlS1r7gSAI+Pbbb8u9DrlcjoSEBGg0Gp0K3h9++AEKhQK//fabeL3zAsOHD3/lN2XRVXHv17psfxcXFyxduhRLlizBzZs3cfDgQSxduhTTpk2DVCrFxIkTxfeRN998E+fOndNL/gVFZuErU7yq1yY4OBjh4eEYOnQo2rRpg4MHD+p8sOe/jJceI53FxMRg8+bNkMlk6NatW6mfJ5VK0bRpU8yYMQNLliyBIAjYtWuXuNzc3BxAxRwJOnbsWJHY/fv38fDhQ9SuXVucwuDk5AQAePz4cZH2BVMAnmdubl6mnAt++j569Kh46bUCgiDg6NGjWu30qX79+gBQ7K1JC2IVsd7C7OzstB7XrFkTDg4OOHfuXIVdTqci/7ZKo0mTJnj69Clu375dIf2XZXxVqlTBkCFDcOTIEdjZ2RV7aTdTlpycDKVSiWbNmhX5wnfu3DnxknLl0bhxY+Tm5upc+BTcpfL5s/oFQcCJEyfKnZ8hlWf7SyQS1KxZEyNHjsT+/fsBQPz7tbe3R82aNXHjxg29TWFSKBQAoHXk+lW+NoMHD8avv/6Kmzdvok2bNiUeIKGSsdglnZw4cQLt27dHbm5uqe44df78+WJ/Fi/YaQtfbqVgjljha/fqS0REBK5cuSI+FgQBkyZNQn5+vtY1O6tXrw57e3vs3LlT/Hm9IN/Zs2cX27ezszOSk5ORk5NTqlwqV66MNm3a4Pr160XmcP7888+4ceMGwsLCiszX1Yfw8HAAwIwZM7ReF6VSKf70V9BGV3/99Rf++OOPYo+Ox8bGipfYKrhjkYWFBT755BPcv38f48ePL7bgvXbtWrHX3yytivzbKo1PP/0UwLM7yxW+Rm6BhIQE3LhxQ+f+nZycIJFIih1fUlKS1nVdCygUCuTm5r7wkkemyN3dHdbW1rhw4QKysrLEuEKheOFlFMti5MiRAIAxY8ZovY8Az45svqxoKZjvWXB5uQLffPNNsa/l66Ss2z8uLq7Ya9EW9xny6aefIisrC8OGDSt2usK9e/dKfV3bnJwc8RrNrVu3FuOv+rUZOHAg1q5di1u3biE0NFT85Y9Kh9MY6IViY2PFGyPk5eWJtwu+evUqzM3NMWXKFK3r4Zbkt99+w8qVK9G6dWtUrVoVDg4OiI6Oxp49e+Ds7Cxe7B8AwsLCsHXrVnTv3h0dOnSAlZUVgoKC9DIxv3379mjWrBl69+4NNzc3REVF4dy5c2jatKnWG6ylpSVGjx6NuXPnokGDBujatSvS09Px559/IiQkRPxWX1hYWBjOnTuHDh06oFWrVrC0tETr1q213iCf9+OPP6Jly5YYNmwY/vzzT9SqVQvXr1/Hzp074ebmhh9//LHcYy5O69atMXr0aCxduhR16tRB9+7dIQgCtm3bhkePHuHTTz99Yd6lcfPmTYwdOxaurq7i6y4IAmJjY7Fnzx7k5eXhk08+0ZqHNmPGDFy4cAFLlizB7t270bp1a7i7u+Px48e4evUqLl++jH/++afIkaDSatasGaytrbFo0SIoFApxzvKUKVPKNdbSeuedd/D1119j1qxZCAgIwDvvvANfX188ffoUsbGxOHbsGGbPno2aNWvq1L+dnR0aNWqEo0ePYsCAAahWrRrMzMwwYMAAKBQK1K9fH0FBQahXrx68vb3x9OlT/PHHH1CpVBg/fryeR2vczMzMMGLECPEmG126dEFaWhr27t0LX19feHl5lXsdHTt2xPjx4/H999+jWrVq6Natm/j3HBUVhfHjx2tdl/t5w4cPx6+//oru3bujZ8+ecHFxwalTp3DhwgV06tQJu3fvLneOhlLW7X/p0iW8//77aNy4MWrVqoVKlSqJ17U1MzPD2LFjxbYff/wxTp06hXXr1uHEiRNo27YtvLy88O+//+LmzZs4ffo01q9fX+TGOAcOHBAPVmg0GiQkJGDv3r149OgRgoODMWLECLGtIV6bAQMGwMzMDOHh4QgNDcWhQ4d4x8dSYrFLL3Tnzh3xSJ+1tTXkcjlq1KiBr7/+GuHh4aW+NW+fPn2Qk5ODEydO4MyZM8jNzYWPjw8++eQTfPHFF1r3gx82bBji4uKwceNGzJ8/H2q1GuHh4XopdseNG4d3330XixYtQmxsLJydnTFmzBjMmjWryFUYCmKrV6/GTz/9BD8/P3z99dfo0qULtm3bVqTvr7/+GgqFArt27cKxY8eQn5+PadOmvbBorF69Os6dO4cZM2bgr7/+wu7du+Hm5obBgwdj2rRp5T7L+kWWLFmC+vXr48cff8TPP/8MAKhduzZmzpyp9eVDV/369YOdnR3+/vtvXL16Ffv370dOTg5cXV3Rrl07DBo0CN27d9d6jkwmw969e7F69WpERERg27ZtyM3NhYeHB2rVqoXhw4ejbt26Oufk7OyMrVu3Yvr06fjll1/En0pfVbELADNnzkTr1q2xZMkSREVFITU1FS4uLqhSpQqmT5+Ofv36lav/3377DWPHjsWuXbugVCohCAJatmyJ4OBgTJ8+HQcPHsSBAwfw9OlTuLq6okGDBhgzZgzeeecdPY3w9TFv3jw4Oztj7dq1WLFiBTw8PNCnTx9Mnz79pTd7KK3vvvsOzZo1w7Jly7B161bk5OTA09MTYWFhePvtt1/43Pr162Pfvn2YMmUKIiMjYW5ujubNm+PEiRPijUZeZ2XZ/g0bNsSECRNw+PBh7N69G6mpqahUqRLatm2LL774Ak2bNhXbFtx1sGPHjvjll1+wa9cuZGRkwN3dHdWqVcP3338vnjBbWOGrUgCAra0tqlWrhuHDh2Ps2LFaJ3Aa6rXp16+f+AW2YA6vPr6YmTqJ8PxkQSIiIiIiE8E5u0RERERksljsEhEREZHJYrFLRERERCaLxS4RERERmSwWu0RERERksljsEhEREZHJYrFLRERERCaLxS4RERERmSzeQe0FFAoF1Gq1odMgIiIioudYWFjAycnp5e1eQS6vLbVaDZVKZeg0iIiIiEhHnMZARERERCbLqI7sajQabN68GceOHUNqaiqcnZ0REhKC7t27QyKRAAAEQcDmzZsRFRWFzMxM1KhRA0OHDoWnp6fYT0ZGBtasWYPz589DIpGgSZMmGDx4MKysrAw1NCIiIiIyAKM6srtjxw7s378fH374IX744Qf069cPO3fuxN69e8U2f/zxB/bu3Ythw4Zh7ty5kMlkmDNnDvLy8sQ2S5YswcOHDzFlyhR89dVXuHHjBlauXGmIIRERERGRARlVsRsTE4OGDRuiQYMGcHd3R9OmTVGvXj3ExsYCeHZUd8+ePXj//ffRqFEj+Pr6YtSoUVAoFDh79iwA4NGjR7h06RKGDx+OatWqoUaNGhgyZAhOnjyJlJQUQw6PiKhMnjx5gtGjR6N27dqoWrUq3nrrLVy+fFlcvmfPHvTp0we1a9eGt7c3rl27Vqp+lUolJk2ahPr166NKlSpo2bIloqKixOWRkZFo2LAhatWqhenTp2s99+HDh2jZsiXS09P1MkYioopmVNMYAgMDERUVhfj4eHh5eSEuLg63bt3CwIEDAQCJiYlITU1FvXr1xOfY2NggICAAMTExaNGiBWJiYmBra4uqVauKberWrQuJRILY2Fg0bty4yHpVKpXWiWgSiQTW1tbi/wPPCu3CywvoGi8c01dc3zlyTBwTx2S4MSmVSrz33nto3rw5fv/9dzg7O+PevXuQy+Vi++zsbDRu3BhdunTBF198AYlEUuQ96/m+8/Ly0KdPH7i6uuLnn3+Gp6cnHj58CAcHBwBASkoKvvjiC/zwww+oXLkyBg4ciBYtWqBdu3YAgEmTJmHSpEmwt7cv85hM8XXimDgmjslwYyotoyp233vvPWRnZ2Ps2LEwMzODRqNB79690apVKwBAamoqAMDR0VHreY6OjuKy1NRU8U27gLm5Oezs7MQ2z9u+fTu2bt0qPq5SpQrmz58PBwcHcYPm5uYiMzMTtra2kMlkYtvs7GxkZ2fD3t4eUqlUjGdmZiI3NxeOjo4wNzcX4+np6VCpVFofWMCzDzaNRlPkEhoKhQJmZmZaYxYEAQqFAlKpVPzAAYD8/HwolUrIZDLY2tqKcZVKhfT0dFhbW4tFPMfEMXFMxj2m1atXo3Llyli3bp04Jl9fX60xDRs2DAqFAo8ePQIAODg4wMnJ6YVjWrp0KZRKJY4dOybmU7NmTXFMCoUCjo6OGDRoEHJzc9G8eXM8ePAATk5O2LRpE2xsbNC9e3e+ThwTx8QxGXxMz9d7JZEIZS2PK9CJEyfwv//9D/3798cbb7yBuLg4rF27FgMHDkRoaChu3bqFr7/+GitXrtQa+MKFCyGRSDB27FhERkbiyJEjWLx4sVbfQ4cORc+ePcWjE4WVdGQ3KSlJvM6uob+9mOI3Mo6JY+KYSo6HhoYiNDQUT548wT///INKlSohPDwc/fv3L5L7w4cP0bRpU+zbtw916tR54ZgGDBgAuVwOa2tr/P3333BxccF7772HkSNHwtzcHEqlEo0bN8a2bdvg7e2Njh07Yt68eahfvz46duyILVu2wMvLS6cxmeLrxDFxTByT4cYklUrh5uaGlzGqI7v/+9//0LVrV7Ro0QIAULlyZSQlJWHHjh0IDQ2FXC4H8KzSL1zsKpVK+Pn5AQDkcjnS0tK0+s3Pz0dGRob4/OdJpVKtbx6FFfddoKTvB2WJ66MPY4sbUy76ihtTLvqKG1Mu+oobUy76ij948AAREREYNmwYRo8ejUuXLmHq1KmQSqXo2bNnif0839fzj+/fv48TJ06gW7du+O2333Dv3j1MmjQJarUa48aNg6OjIxYtWoQxY8YgJycHPXr0QGhoKD7//HMMGjQIDx48wKBBg8T2nTt3LvWYjGn76ituTLnoK25Muegrbky56CtuTLnoK17WPkrLqIrd3NxcmJlpnzNnZmYmDtLd3R1yuRxXr14Vi9usrCzExsaKR2wDAwORmZmJu3fvwt/fHwBw7do1CIKAgICAVzcYIqJy0Gg0qFevHiZOnAgAqFOnDm7duoXffvutxGK3tP26uLjg22+/hbm5OerVq4eEhAT89NNPGDduHACgQ4cO6NChg/icf/75Bzdu3MDs2bPRokULLF++HG5ubujcuTOaNm0KV1fX8g2WiKgCGVWx++abbyIyMhKurq7w8fFBXFwcdu3ahTZt2gB4dhi7Y8eOiIyMhKenJ9zd3bFx40Y4OTmhUaNGAAAfHx8EBwdj5cqVGDZsGNRqNdasWYPmzZvD2dnZkMMjIio1d3d3BAYGasUCAgKwZ8+ecvXr4eEBCwsLrfly1apVQ2JiIvLy8mBpaanVPjc3F5MmTcKSJUtw7949qNVqNGvWDADg7++PCxcuFDs9jIjIWBhVsTtkyBBs2rQJq1atglKphLOzM95++2306NFDbNO1a1fk5uZi5cqVyMrKQo0aNTBp0iStN+hPP/0Uq1evxsyZMyGRPLupxJAhQwwxJCIinTRq1Ah37tzRit29exfe3t7l6rdhw4bYsWMHNBqN+Eva3bt34eHhUaTQBYDFixcjNDQUdevWxbVr15Cfny8uU6lU0Gg05cqHiKiiGdUJasYmKSlJ68Q1IqJX5dKlS+jatSs+//xzdOnSBZcuXcIXX3yBb7/9Fu+//z6AZ2ckP378GP/++y8GDhyIFStWoGrVqnB3d4e7uzuAZ1/+PT09xekQjx8/RlhYGD744AMMHjwY9+7dw+eff44hQ4ZgzJgxWjnExMRgyJAh2LdvH2xsbJCdnY1GjRph8uTJcHNzw0cffYQTJ05o3cGSiOhVKe0Jaix2X4DFLhEZ0v79+/HNN9/g3r17eOONN/DRRx+hX79+4vJNmzaJ82wLGzduHD7//HMAQI8ePeDj44NFixaJy8+dO4fp06cjOjoalSpVQu/evcWrMRQQBAHdunXDyJEj8fbbb2vlNHnyZOTl5eHLL79E3759K2DkREQvx2JXD1jsEhERERmn0ha7RnW7YCIiIiIifTKqE9SIiJ7XokWeoVMg0nLiRNET+YjIePHILhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJsvC0AkUNnLkSCQlJRWJt2vXDkOHDkVeXh4iIiJw8uRJqFQqBAUFYejQoZDL5WLb5ORk/PLLL7h+/TqsrKwQEhKCvn37wtzc/BWOhIiIiIiMgVEVu/PmzYNGoxEfP3jwALNnz0azZs0AAOvWrcOFCxcwbtw42NjYYPXq1ViwYAFmzZoFANBoNJg3bx7kcjlmz54NhUKBZcuWwdzcHH379jXImIiIiIjIcIxq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uxbznTt3cPDgQcTHx8PMzAxVq1atyE1AREREBsJilyrc5cuX8cEHH4iPZ8yYAQD44IMP8M033+DOnTv46KOPkJKSAicnJwQFBSEyMhLVq1cXn3P//n2kpKSUqs9FixaJ8ezsbEyePBk//vgjzMye/ZDh5eWFWbNmYdy4cbC0tMSiRYtgbW1dIWMnIiIiw5IIgiAYOgljlZSUpPVzNxG9ei1a6G86C5E+nDhhaegUSoX7Dhkbfe87UqkUbm5uL23HObtEREREZLI4jeEV4TdsMkavyxEqIiIiXfHILhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyWOwSERERkclisUtEREREJovFLhERERGZLBa7RERERGSyLAydQGHR0dHYuXMn7t27B4VCgfHjx6Nx48bickEQsHnzZkRFRSEzMxM1atTA0KFD4enpKbbJyMjAmjVrcP78eUgkEjRp0gSDBw+GlZWVIYZERERERAZkVEd2c3Nz4efnhw8//LDY5X/88Qf27t2LYcOGYe7cuZDJZJgzZw7y8vLENkuWLMHDhw8xZcoUfPXVV7hx4wZWrlz5qoZAREREREbEqIrd+vXro3fv3lpHcwsIgoA9e/bg/fffR6NGjeDr64tRo0ZBoVDg7NmzAIBHjx7h0qVLGD58OKpVq4YaNWpgyJAhOHnyJFJSUl71cIiIiIjIwIyq2H2RxMREpKamol69emLMxsYGAQEBiImJAQDExMTA1tYWVatWFdvUrVsXEokEsbGxJfatUqmQlZUl/svOzhaXSSQSSCQSrfYFsbLEiYxR4b/Nwn+/ZY0/36c+40TGRl/7zavcn4iMjT72m9Iyqjm7L5KamgoAcHR01Io7OjqKy1JTU+Hg4KC13NzcHHZ2dmKb4mzfvh1bt24VH1epUgXz58+Hg4MDBEEA8GyKRWZmJmxtbSGTycS22dnZyM7Ohr29PaRSqRjPzMxEbm4uHB0dYW5uDiBBh1ETVSwnJyco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\n"
|
| 447 |
-
},
|
| 448 |
-
"metadata": {}
|
| 449 |
-
}
|
| 450 |
-
]
|
| 451 |
-
},
|
| 452 |
-
{
|
| 453 |
-
"cell_type": "code",
|
| 454 |
-
"source": [],
|
| 455 |
-
"metadata": {
|
| 456 |
-
"id": "YbIbJHKfjX-c"
|
| 457 |
-
},
|
| 458 |
-
"execution_count": 8,
|
| 459 |
-
"outputs": []
|
| 460 |
-
}
|
| 461 |
-
]
|
| 462 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
|
@@ -1,9 +1,15 @@
|
|
| 1 |
-
fastapi
|
| 2 |
-
uvicorn
|
| 3 |
-
pydantic
|
| 4 |
-
transformers
|
| 5 |
-
torch
|
| 6 |
-
numpy
|
| 7 |
-
pandas
|
| 8 |
-
sqlalchemy
|
| 9 |
-
psycopg2-binary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi
|
| 2 |
+
uvicorn
|
| 3 |
+
pydantic
|
| 4 |
+
transformers
|
| 5 |
+
torch
|
| 6 |
+
numpy
|
| 7 |
+
pandas
|
| 8 |
+
sqlalchemy
|
| 9 |
+
psycopg2-binary
|
| 10 |
+
python-dotenv
|
| 11 |
+
huggingface-hub
|
| 12 |
+
evaluate
|
| 13 |
+
scikit-learn
|
| 14 |
+
ipykernel
|
| 15 |
+
|