-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathRNplus.py
More file actions
122 lines (97 loc) · 4.14 KB
/
Copy pathRNplus.py
File metadata and controls
122 lines (97 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import re
import csv
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import classification_report, confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
def clean_tweet(tweet):
tweet = tweet.lower()
tweet = re.sub(r"http\S+", "", tweet)
tweet = re.sub(r"@\w+", "", tweet)
tweet = re.sub(r"#\w+", "", tweet)
tweet = re.sub(r"rt\s?:", "", tweet)
tweet = re.sub(r"[^\w\s]", "", tweet)
tweet = re.sub(r"\s+", " ", tweet).strip()
return tweet
tweets_data = []
with open("balanced_tweets_200k.csv", "r", encoding="latin1") as f:
reader = csv.reader(f)
for row in reader:
if len(row) >= 6:
raw_label = row[0]
tweet = row[5]
if raw_label == "0":
label = 0
elif raw_label == "4":
label = 1
else:
continue
tweets_data.append((clean_tweet(tweet), label))
texts = [t[0] for t in tweets_data if isinstance(t[0], str) and len(t[0].strip()) > 0]
labels = [t[1] for t in tweets_data if isinstance(t[0], str) and len(t[0].strip()) > 0]
vectorizer = TfidfVectorizer(max_features=1024)
X = vectorizer.fit_transform(texts).toarray()
y = torch.tensor(labels).float()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.15, random_state=42)
X_train = torch.tensor(X_train).float()
X_test = torch.tensor(X_test).float()
y_train = y_train.view(-1, 1).float()
y_test = y_test.view(-1, 1).float()
class SentimentNN(nn.Module):# c'est ici que ça change
def __init__(self):
super(SentimentNN, self).__init__()
self.fc1 = nn.Linear(1024, 512)
self.relu1 = nn.LeakyReLU(0.01)# ici on utilise LeakyReLU pour éviter le problème de vanishing gradient( c'est une activation qui permet de garder une petite pente pour les valeurs négatives)
self.drop1 = nn.Dropout(0.3)# # le dropout sert contre le sur-apprentissage
self.fc2 = nn.Linear(512, 128)
self.relu2 = nn.LeakyReLU(0.01)
self.drop2 = nn.Dropout(0.3)
self.fc3 = nn.Linear(128, 1)
def forward(self, x):
x = self.drop1(self.relu1(self.fc1(x)))
x = self.drop2(self.relu2(self.fc2(x)))
x = self.fc3(x)
return x
model = SentimentNN()
# et la on vas gérer le déséquilibre des classes pour que le modèle n'apprenne pas à "favoriser" la classe majoritaire.
n_pos = y_train.sum()
n_neg = len(y_train) - n_pos
pos_weight = torch.tensor([n_neg / n_pos]).float() # e ratio permet de dire : “Un exemple positif compte autant que X exemples négatifs.”
criterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)#fonction de perte adaptée aux classes déséquilibrées
optimizer = torch.optim.AdamW(model.parameters(), lr=0.01)#AdamW a meilleure convergence (plus rapide et plus stable),moins d’overfitting
# Entraînement du modèle
print("⚡ Entraînement du modèle...")
for epoch in range(100):
model.train()
optimizer.zero_grad()
outputs = model(X_train)
loss = criterion(outputs, y_train)
loss.backward()
optimizer.step()
print(f"Epoch {epoch+1}/20 - Loss: {loss.item():.4f}")
# évaluation du modèle
model.eval()
with torch.no_grad():
logits = model(X_test)
probs = torch.sigmoid(logits)
y_pred_label = (probs > 0.49).int()
print("\n Résultats sur le test :")
print(classification_report(y_test.int(), y_pred_label))
# Matrice de confusion
cm = confusion_matrix(y_test.int(), y_pred_label)
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=["négatif", "positif"])
disp.plot(cmap=plt.cm.Blues)
plt.title("Matrice de confusion")
plt.show()
def predict_sentiment(tweet):
cleaned = clean_tweet(tweet)
vec = vectorizer.transform([cleaned]).toarray()
with torch.no_grad():
output = model(torch.tensor(vec).float())
prob = torch.sigmoid(output).item()
return "positif" if prob >= 0.5 else "négatif"
if __name__ == "__main__":
print("Exemple :", predict_sentiment("I love how this works"))