-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMain.py
More file actions
203 lines (145 loc) · 5.99 KB
/
Copy pathMain.py
File metadata and controls
203 lines (145 loc) · 5.99 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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import pandas as pd
import numpy as np
import nltk
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
nltk.download('stopwords')
import re
import string
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from imblearn.under_sampling import RandomUnderSampler
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
# Models
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.neural_network import MLPClassifier
def process_doc(doc):
'''
- Tokenize the string
- Lowercase
- Remove stop words and punctuation
- Stem
'''
# Lowercase all words
doc = doc.lower()
# Remove dots
doc = re.sub(r'\.', ' ', doc)
# split into tokens by white space
tokens = doc.split()
# prepare regex for char filtering
re_punc = re.compile('[%s]' % re.escape(string.punctuation))
# remove punctuation from each word
tokens = [re_punc.sub('', w) for w in tokens]
# remove remaining tokens that are not alphabetic
tokens = [word for word in tokens if word.isalpha()]
# filter out stop words
stop_words = set(stopwords.words('english'))
tokens = [w for w in tokens if not w in stop_words]
# filter out short tokens
tokens = [word for word in tokens if len(word) > 1]
# Stemming
stemmer = PorterStemmer()
# Create an empty list to store the stems
tweets_stem = ''
# Get the words together as a phrase
for word in tokens:
stem_word = stemmer.stem(word) # stemming word
tweets_stem += ' '+stem_word
return tweets_stem
def vectorite_features(tweets):
# Create a dictionary with the word frequencies
#count_vect = CountVectorizer(min_df=3)
count_vect = TfidfVectorizer(min_df=5)
vect = count_vect.fit(tweets)
feature_names = vect.get_feature_names()
print("\nFirst 10 features:\n", feature_names[:10], "\n")
#vect.vocabulary_
# Vectorize tweets to a sparse matrix
X_vect = vect.transform(tweets)
return X_vect, vect
def build_train_test(X_vect, labels, balanced=False, scaling=False):
if scaling==True:
scaler = StandardScaler(with_mean=False)
X_vect = scaler.fit_transform(X_vect)
# Use sampling to fix the unbalanced sets
if balanced==True:
print(">>> Using balanced samples")
rus = RandomUnderSampler()
X_rus, y_rus = rus.fit_sample(X_vect, labels)
# Split using balanced sample
X_train, X_test, y_train, y_test = train_test_split(X_rus, y_rus, random_state=0)
# Split without using balanced sample
else:
print(">>> Using imbalanced dataset")
X_train, X_test, y_train, y_test = train_test_split(X_vect, labels, random_state=0)
return X_train, X_test, y_train, y_test
def select_best_model(X_train, X_test, y_train, y_test):
model_1 = LogisticRegression(random_state=0, max_iter=3000)
model_2 = SVC(kernel='linear', probability=False)
model_3 = SVC(kernel='rbf', C=10, gamma=0.01)
model_4 = RandomForestClassifier(n_estimators=100, random_state=2, n_jobs=-1)
model_5 = MLPClassifier(solver='adam', alpha=1, max_iter=1000, random_state=0, hidden_layer_sizes=[10, 10])
models = [model_1, model_2, model_3, model_4, model_5]
best_model = None
best_accuracy = 0
print("\n####### Training Models #######")
for model in models:
print("\nModel: ", type(model).__name__)
model.fit(X_train, y_train)
accuracy = np.mean(cross_val_score(model, X_train, y_train, cv=5))
print('Accuracy: ', accuracy)
y_pred = model.predict(X_test)
confusion = confusion_matrix(y_test, y_pred)
print("Confusion matrix:\n{}".format(confusion))
if accuracy > best_accuracy:
best_model = model
best_accuracy = accuracy
print("The best model is: ", type(best_model).__name__, "with an accuracy of ", best_accuracy)
return best_model
# Use the built model to predict a sentiment
# sadness: 0; anger: 1; happiness: 2
def predict_sentiment(doc, model):
doc = vect.transform([doc])
sentiment = model.predict(doc)[0]
if sentiment == 0:
return "Sadness :("
elif sentiment == 1:
return "Anger -.-"
else:
return "Happiness :)"
# Data downloaded from https://data.world/crowdflower/sentiment-analysis-in-text
data = pd.read_csv('data/text_emotion.csv')
print("\n>>> Dataset loaded\n\n")
# Let's use just two columns from the dataset
columns_to_keep = ['content', 'sentiment']
data = data[columns_to_keep]
# Let's merge 'hate' and 'anger' to increase our sample size
data['sentiment'][ data['sentiment'] == 'hate'] = 'anger'
# Select only the tweets belonging to our sentiments of interest
emotions_to_keep = ['happiness', 'sadness', 'anger']
data = data[data['sentiment'].isin(emotions_to_keep)]
print(data['sentiment'].value_counts(), "\n")
# Use an index to represent each sentiment
data['sentiment_id'] = data['sentiment'].factorize()[0]
for i in [0,1,2]:
tweet = data[ data['sentiment_id'] == i ].iloc[0]
print(tweet['sentiment_id'], " ", tweet['sentiment'], ": ", tweet['content'])
##### ---- Data Cleaning ---- ######
new_doc = data['content'].apply(process_doc)
print("\nPost-processing tweets:\n\n", new_doc.head())
##### ---- Vectorise Features ---- ######
X_vect, vect = vectorite_features(new_doc)
# Building training and test sets
X_train, X_test, y_train, y_test = build_train_test(X_vect, data['sentiment_id'], balanced=True, scaling=False)
###### Select the best model ######
model = select_best_model(X_train, X_test, y_train, y_test)
user_text = ''
while user_text != '0':
user_text = input("\nEnter your message (0 to quit): ")
if user_text != '0':
print(predict_sentiment(user_text, model))