Oresti Theodoridis commited on
Commit
f131af3
2 Parent(s): 11ba7a0 725b13f

Merge pull request #41 from Demea9000/35-create-new-text-classifier-sentiment

Browse files
.idea/politweet.iml CHANGED
@@ -5,7 +5,7 @@
5
  <excludeFolder url="file://$MODULE_DIR$/politweet-environment" />
6
  <excludeFolder url="file://$MODULE_DIR$/venv" />
7
  </content>
8
- <orderEntry type="jdk" jdkName="Python 3.10 (politweet)" jdkType="Python SDK" />
9
  <orderEntry type="sourceFolder" forTests="false" />
10
  </component>
11
  <component name="PyNamespacePackagesService">
 
5
  <excludeFolder url="file://$MODULE_DIR$/politweet-environment" />
6
  <excludeFolder url="file://$MODULE_DIR$/venv" />
7
  </content>
8
+ <orderEntry type="inheritedJdk" />
9
  <orderEntry type="sourceFolder" forTests="false" />
10
  </component>
11
  <component name="PyNamespacePackagesService">
textclassifier/TextClassifier.py CHANGED
@@ -6,7 +6,9 @@ from datetime import date
6
 
7
  class TextClassifier:
8
  def __init__(self, model_name="text-davinci-002", from_date='2022-01-01', to_date=str(date.today()),
9
- num_tweets=10, user_name=None):
 
 
10
  """
11
  Initializes the TextClassifier.
12
  :param model_name: name of the model from openai.
@@ -19,8 +21,8 @@ class TextClassifier:
19
  self.from_date = from_date
20
  self.to_date = to_date
21
  self.num_tweets = num_tweets
22
- self.ts = TwitterScraper.TwitterScraper(from_date, to_date, num_tweets)
23
  self.user_name = user_name
 
24
  self.df = self.ts.scrape_by_user(user_name)
25
  # self.api_key = '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'
26
  openai.api_key = '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'
@@ -33,6 +35,11 @@ class TextClassifier:
33
 
34
  @staticmethod
35
  def cleanup_sentiment_results(classification_unclean):
 
 
 
 
 
36
  classification_clean = classification_unclean.replace('\n\n', "")
37
  classification_clean = classification_clean.replace('\n', "")
38
  if classification_clean.startswith(" "):
@@ -72,17 +79,21 @@ class TextClassifier:
72
  """
73
  Classifies the sentiment of a user's tweets.
74
  """
75
- df_sentiment = self.df
 
76
  df_sentiment['sentiment'] = df_sentiment['tweet'].apply(self.classify_sentiment)
77
- return df_sentiment
 
78
 
79
  def analyze_sentiment(self, text: str, sentiment: str):
 
80
  """
81
  Analyzes the sentiment of a text using OpenAI.
82
  :param text: string of the tweet text.
83
  :param sentiment:
84
  :return:
85
  """
 
86
  prompt_string = "Who is the TARGET of this "
87
  prompt_string += sentiment
88
  prompt_string += " TWEET?\\nTWEET=\""
@@ -100,7 +111,6 @@ class TextClassifier:
100
  )
101
 
102
  analyzed_sentiment = response.choices[0]['text']
103
-
104
  # Remove spaces at the start/end of the response
105
  if analyzed_sentiment.startswith(' '):
106
  analyzed_sentiment = analyzed_sentiment[1:]
@@ -110,7 +120,7 @@ class TextClassifier:
110
  # Sometimes GPT-3 gives faulty results, so a simple filter is introduced
111
  # If the prediction is bad
112
  # -> set target value to N/A (not applicable)
113
- if len(analyzed_sentiment) > 10:
114
  analyzed_sentiment = "N/A"
115
 
116
  # An attempt to merge target responses that should be the same
@@ -140,9 +150,21 @@ class TextClassifier:
140
  elif analyzed_sentiment.lower() == "the swedish government":
141
  analyzed_sentiment = "Regeringen"
142
 
143
- tweet_dict[tweet]['target'] = analyzed_sentiment
144
 
145
- return tweet_dict
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
  def classify_topic(self, text: str):
148
  """
@@ -178,17 +200,16 @@ class TextClassifier:
178
  df_topic['topic'] = df_topic['tweet'].apply(self.classify_topic)
179
  return df_topic
180
 
 
 
 
 
181
  def cleanup_topic_results(prediction_dict, text):
182
  new_item = text.replace("\n", " ")
183
  new_item = new_item.replace(" ", " ")
184
  return new_item
185
 
186
 
187
- if __name__ == "__main__":
188
- import pandas as pd
189
- #pd.set_option('display.max_columns', None)
190
- tc = TextClassifier(model_name="text-davinci-002", from_date='2022-01-01', to_date=str(date.today()), num_tweets=20, user_name="jimmieakesson")
191
- print(tc.classify_topics_of_tweets())
192
-
193
 
 
194
 
 
6
 
7
  class TextClassifier:
8
  def __init__(self, model_name="text-davinci-002", from_date='2022-01-01', to_date=str(date.today()),
9
+
10
+ user_name='jimmieakesson',
11
+ num_tweets=20):
12
  """
13
  Initializes the TextClassifier.
14
  :param model_name: name of the model from openai.
 
21
  self.from_date = from_date
22
  self.to_date = to_date
23
  self.num_tweets = num_tweets
 
24
  self.user_name = user_name
25
+ self.ts = TwitterScraper.TwitterScraper(from_date, to_date, num_tweets)
26
  self.df = self.ts.scrape_by_user(user_name)
27
  # self.api_key = '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'
28
  openai.api_key = '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'
 
35
 
36
  @staticmethod
37
  def cleanup_sentiment_results(classification_unclean):
38
+ """
39
+ Cleans up the results of the sentiment classification.
40
+ :param classification_unclean: string of the classification result.
41
+ :return: cleaned up string.
42
+ """
43
  classification_clean = classification_unclean.replace('\n\n', "")
44
  classification_clean = classification_clean.replace('\n', "")
45
  if classification_clean.startswith(" "):
 
79
  """
80
  Classifies the sentiment of a user's tweets.
81
  """
82
+ df_sentiment = self.df.copy()
83
+
84
  df_sentiment['sentiment'] = df_sentiment['tweet'].apply(self.classify_sentiment)
85
+ self.df = df_sentiment
86
+ return self.df
87
 
88
  def analyze_sentiment(self, text: str, sentiment: str):
89
+ # TODO: fix prompt before running this method
90
  """
91
  Analyzes the sentiment of a text using OpenAI.
92
  :param text: string of the tweet text.
93
  :param sentiment:
94
  :return:
95
  """
96
+ # assert 1 == 2, "Måste fixa prompt innan denna metod körs"
97
  prompt_string = "Who is the TARGET of this "
98
  prompt_string += sentiment
99
  prompt_string += " TWEET?\\nTWEET=\""
 
111
  )
112
 
113
  analyzed_sentiment = response.choices[0]['text']
 
114
  # Remove spaces at the start/end of the response
115
  if analyzed_sentiment.startswith(' '):
116
  analyzed_sentiment = analyzed_sentiment[1:]
 
120
  # Sometimes GPT-3 gives faulty results, so a simple filter is introduced
121
  # If the prediction is bad
122
  # -> set target value to N/A (not applicable)
123
+ if len(analyzed_sentiment) > 50:
124
  analyzed_sentiment = "N/A"
125
 
126
  # An attempt to merge target responses that should be the same
 
150
  elif analyzed_sentiment.lower() == "the swedish government":
151
  analyzed_sentiment = "Regeringen"
152
 
153
+ return analyzed_sentiment
154
 
155
+ def analyze_sentiment_of_tweets(self):
156
+ """
157
+ Analyzes the sentiment of a user's tweets.
158
+ """
159
+ # check if 'sentiment' column exists, raise exception if not
160
+ assert 'sentiment' in self.df.columns, \
161
+ "'sentiment' column does not exist. Please run classify_sentiment_of_tweets first."
162
+
163
+ df_sentiment = self.df.copy()
164
+ df_sentiment['target'] = df_sentiment.apply(lambda row: self.analyze_sentiment(row['tweet'], row['sentiment']),
165
+ axis=1)
166
+ self.df = df_sentiment
167
+ return self.df
168
 
169
  def classify_topic(self, text: str):
170
  """
 
200
  df_topic['topic'] = df_topic['tweet'].apply(self.classify_topic)
201
  return df_topic
202
 
203
+ def __repr__(self):
204
+ return "TwitterScraper(from_date={}, to_date={}, num_tweets={})".format(self.from_date, self.to_date,
205
+ self.num_tweets)
206
+
207
  def cleanup_topic_results(prediction_dict, text):
208
  new_item = text.replace("\n", " ")
209
  new_item = new_item.replace(" ", " ")
210
  return new_item
211
 
212
 
 
 
 
 
 
 
213
 
214
+ if __name__ == "__main__":
215
 
twitterscraper/TwitterScraper.py CHANGED
@@ -10,6 +10,7 @@ class TwitterScraper(object):
10
  input: user, from_date, to_date, num_tweets
11
  output: dict
12
  """
 
13
  def __init__(self, from_date="2022-07-01", to_date=str(date.today()), num_tweets=20):
14
  # TODO: add a check to make sure that the dates are in the correct format.
15
  # TODO: add a check to make sure that the number of tweets is a positive number.
@@ -67,7 +68,7 @@ class TwitterScraper(object):
67
  tweets_info = tweet_and_replies_info.drop(labels=indx_replies, axis=0)
68
  # drop removes the columns which its index specified by
69
  # indx_replies. axis=0 if we want to delete rows.
70
- #print(len(tweets['tweet']), " of them are Tweets")
71
  return tweets_info
72
 
73
  def __get_tweets__from_twint__(self):
@@ -95,6 +96,7 @@ class TwitterScraper(object):
95
  tweet_and_replies_inf = tweet_and_replies_inf[
96
  ["id", "tweet", "date", "user_id", "username", "urls", 'nlikes', 'nreplies', 'nretweets']]
97
  return tweet_and_replies_inf
 
98
  # def __check_date_type(d1,d2): if (type(d1) or type(d2)) is not type("str"): # If the type of ite date input
99
  # is not string it generates exception print("[!] Please make sure the date is a string in this format
100
  # \"yyyy-mm-dd\" ") raise EXCEPTION("Incorrect date type Exception!") elif (len(d1.split("-")) or len(d2.split(
@@ -104,11 +106,11 @@ class TwitterScraper(object):
104
  def __repr__(self):
105
  return "TwitterScraper(from_date={}, to_date={}, num_tweets={})".format(self.from_date, self.to_date,
106
  self.num_tweets)
107
- if __name__ == "__main__":
108
- sc = TwitterScraper(from_date="2022-05-01", to_date="2022-07-31", num_tweets=40)
109
- dc = sc.scrape_by_user("jimmieakesson")
110
- print(dc.head())
111
- print(dc.shape)
112
- print(dc.columns)
113
 
114
 
 
 
 
 
 
 
 
10
  input: user, from_date, to_date, num_tweets
11
  output: dict
12
  """
13
+
14
  def __init__(self, from_date="2022-07-01", to_date=str(date.today()), num_tweets=20):
15
  # TODO: add a check to make sure that the dates are in the correct format.
16
  # TODO: add a check to make sure that the number of tweets is a positive number.
 
68
  tweets_info = tweet_and_replies_info.drop(labels=indx_replies, axis=0)
69
  # drop removes the columns which its index specified by
70
  # indx_replies. axis=0 if we want to delete rows.
71
+ # print(len(tweets['tweet']), " of them are Tweets")
72
  return tweets_info
73
 
74
  def __get_tweets__from_twint__(self):
 
96
  tweet_and_replies_inf = tweet_and_replies_inf[
97
  ["id", "tweet", "date", "user_id", "username", "urls", 'nlikes', 'nreplies', 'nretweets']]
98
  return tweet_and_replies_inf
99
+
100
  # def __check_date_type(d1,d2): if (type(d1) or type(d2)) is not type("str"): # If the type of ite date input
101
  # is not string it generates exception print("[!] Please make sure the date is a string in this format
102
  # \"yyyy-mm-dd\" ") raise EXCEPTION("Incorrect date type Exception!") elif (len(d1.split("-")) or len(d2.split(
 
106
  def __repr__(self):
107
  return "TwitterScraper(from_date={}, to_date={}, num_tweets={})".format(self.from_date, self.to_date,
108
  self.num_tweets)
 
 
 
 
 
 
109
 
110
 
111
+ if __name__ == "__main__":
112
+ sc = TwitterScraper(from_date="2022-05-01", to_date="2022-07-31", num_tweets=40)
113
+ dc = sc.scrape_by_user("jimmieakesson")
114
+ print(dc.head())
115
+ print(dc.shape)
116
+ print(dc.columns)
twitterscraper/jimmieakesson.csv ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ,id,tweet,date,user_id,username,urls,nlikes,nreplies,nretweets
2
+ 0,1546801285021814784,"Sverigedemokraterna kommer även fortsättningsvis att vara den tyngsta rösten för kraftigt sänkta priser på både bränsle och el. Alla vi miljontals människor som bor utanför storstädernas kollektivtrafik och cykelbanor måste kunna leva. Sänk bränslepriserna, nu! https://t.co/OiPb6WdaZG",2022-07-12 12:18:59,95972673,jimmieakesson,[],1074,63,103
3
+ 1,1544748873767424001,Fruktansvärt att nås av beskedet att kvinnan som attackerades i Visby har avlidit. Mina tankar finns hos hennes familj ikväll.,2022-07-06 20:23:26,95972673,jimmieakesson,[],3482,178,143
4
+ 2,1538948369611210764,"@annieloof Nej, jag håller med. Tänk mer som Mathias Andersson (SD). https://t.co/gSqQDz5N8z",2022-06-20 20:14:18,95972673,jimmieakesson,[],1511,89,115
5
+ 3,1537770920621879297,"Man kan ha synpunkter på en sådan lösning, men den är naturligtvis att föredra framför frigående våldsverkare som fortsätter misshandla sina offer i väntan på fängelse.",2022-06-17 14:15:32,95972673,jimmieakesson,[],694,17,41
6
+ 4,1537770809225273344,Är det ont om plats på anstalterna så får man sänka standarden rejält för att få rum med fler interner per kvadratmeter.,2022-06-17 14:15:05,95972673,jimmieakesson,[],812,26,57
7
+ 5,1537770713368735744,"Döms man för brott, särskilt våldsbrott, ska man vara inlåst från det att domen faller tills straffet är avtjänat. Allt annat är vansinne.",2022-06-17 14:14:43,95972673,jimmieakesson,[],1015,26,85
8
+ 6,1537770657823576066,"Platsbrist? Jaha, vad spelar det för roll? Det gör mig förbannad och bestört att lösningen på problemet med överfulla fängelser verkar vara att dömda våldsbrottslingar får röra sig fritt i samhället istället för att sitta inlåsta. https://t.co/QDi9rM3kMC",2022-06-17 14:14:29,95972673,jimmieakesson,['https://sverigesradio.se/artikel/domda-kvinnomisshandlare-kan-fortsatta-valdet-mot-samma-kvinna-innan-fangelset'],1157,86,132
9
+ 7,1534230353094885383,"Det är ytterst beklagligt att Magdalena Andersson saboterar Sveriges Natoansökan genom att kohandla med en marxistisk vilde som inte bryr sig ett smack om Sverige, utan istället fullt ut företräder utländska intressen. Svekfullt, maktfullkomligt och ansvarslöst.",2022-06-07 19:46:35,95972673,jimmieakesson,[],6118,544,556
10
+ 8,1533881878553538560,"Glöm att Sverigedemokraterna kommer att lova regeringen frikort att missköta sig för att de gör sig av med en, förvisso exceptionellt usel, minister. https://t.co/3yVuUQU42o",2022-06-06 20:41:52,95972673,jimmieakesson,['https://live.aftonbladet.se/supernytt/news/m-och-l-foeljer-kds-erbjudande-till-magdalena-andersson.CqhNSVhf9'],1079,97,77
11
+ 9,1532625870824808448,"Det är bra att väljarna får denna tydliga varudeklaration, en röst på Centern är en röst på Socialdemokraterna.",2022-06-03 09:30:57,95972673,jimmieakesson,[],1255,57,96
12
+ 10,1532625804223516672,Centern ❤️ Sossarna Ännu en gång är det Annie Lööf som kommer till Morgan Johanssons räddning. För vilken gång i ordningen vet jag inte. Det är tydligt att Centern blivit det vänsterparti som krafter inom partiet arbetat för att det ska bli.,2022-06-03 09:30:41,95972673,jimmieakesson,[],2512,211,188
13
+ 11,1532341074127163392,"Därför valde Sverigedemokraterna idag att, under dagens frågestund i kammaren, väcka frågan om misstroende gentemot Morgan Johansson. Sverige förtjänar bättre.",2022-06-02 14:39:16,95972673,jimmieakesson,[],790,32,34
14
+ 12,1532340946456694785,"Morgan Johanssons misslyckanden kan inte få fortgå en enda dag mer än nödvändigt och det är vår inställning att oavsett valets utfall, så bör han förtidspensioneras som Sveriges justitie- och inrikesminister.",2022-06-02 14:38:45,95972673,jimmieakesson,[],659,9,40
15
+ 13,1532340845042622465,"De enda som kan vara nöjda med regeringens arbete är de kriminella, de som mördar, skadar och hotar. De hoppas just nu på att även kommande mandatperiod ska innebära ytterligare fyra år med Socialdemokratisk saft- och bullepolitik.",2022-06-02 14:38:21,95972673,jimmieakesson,[],435,15,35
16
+ 14,1532340768681209858,Tusentals föräldrar och syskon har förlorat någon närstående och Morgan Johanssons misslyckanden är förmodligen ett av de mest tragiska kapitlen i svensk historia.,2022-06-02 14:38:03,95972673,jimmieakesson,[],406,7,21
17
+ 15,1532340666751242240,Morgan Johansson måste avgå som minister. Otryggheten biter sig fast och gängkriminaliteten är allt annat än knäckt. Antalet skjutningar ökar och sätter skräck i varje del av vårt land. Sverige har förvandlats till ett gangsterland.,2022-06-02 14:37:39,95972673,jimmieakesson,[],3064,172,231
18
+ 16,1523345947165483008, https://t.co/64aJSb1G58,2022-05-08 18:55:50,95972673,jimmieakesson,['https://www.dn.se/debatt/sa-vill-m-sd-kd-och-l-ge-alla-pensionarer-mer-i-planboken/'],122,9,11
19
+ 17,1523345873769357312,"För oss Sverigedemokrater är detta en prioriterad fråga om både rättvisa och moral. Svenskar som på olika sätt har varit med och byggt det här landet, förtjänar en värdig ålderdom.",2022-05-08 18:55:33,95972673,jimmieakesson,[],294,11,14
20
+ 18,1523345831629180928,"I en tid när priserna stiger kraftigt på just de varor och tjänster som är svårast att avvara – mat, värme och bränsle - är det nödvändigt att förbättra de svenska pensionärernas situation.",2022-05-08 18:55:23,95972673,jimmieakesson,[],214,5,8
21
+ 19,1523345750255538176,"Största pensionssatsningen sedan pensionssystemet infördes. Vi kan idag presentera en överenskommelse med Moderaterna, Kristdemokraterna och Liberalerna om att göra den största förstärkningen av pensionärernas ekonomi sedan det nuvarande pensionssystemet infördes. https://t.co/tENrQDFy9o",2022-05-08 18:55:03,95972673,jimmieakesson,[],706,57,73
22
+ 20,1522508592376602625,Varför har ens SR alla dessa invandrarredaktioner? Ska du bo i Sverige - lär dig svenska.,2022-05-06 11:28:29,95972673,jimmieakesson,[],6876,380,522
23
+ 21,1521752982198620161,"Jag uppmanar andra inbjudna partiledare att ställa samma krav. Det får faktiskt finnas någon gräns för tokigheterna, svensk polis förtjänar tydligt stöd från Sveriges politiska partier.",2022-05-04 09:25:58,95972673,jimmieakesson,[],1914,48,106
24
+ 22,1521752934702362626,Järvaveckan får helt enkelt välja – polishataren Kakan Hermansson eller partiledaren Jimmie Åkesson.,2022-05-04 09:25:47,95972673,jimmieakesson,[],1588,53,77
25
+ 23,1521752853110566912,"Jag kommer idag att meddela arrangörerna att jag inte avser närvara och hålla tal på årets Järvaveckan, vilket tidigare planerats, om denna person på något sätt är en del av deras evenemang.",2022-05-04 09:25:27,95972673,jimmieakesson,[],1258,46,56
26
+ 24,1521752814082535424,"Kakan Hermansson har genom åren gjort sig känd för en rad politiskt extrema och direkt stötande uttalanden, inte minst hatiska inlägg om svensk polis.",2022-05-04 09:25:18,95972673,jimmieakesson,[],1006,27,47
27
+ 25,1521752766921781249,"Nu figurerar uppgifter om att årets upplaga av Järvaveckan, en politikervecka i norra Stockholm, återigen genomförs i samarbete med den mycket hårt kritiserade extremvänsterprofilen Kakan Hermansson.",2022-05-04 09:25:07,95972673,jimmieakesson,[],780,10,33
28
+ 26,1521752718070755331,"Den senaste tidens utveckling, med Ramadan-kravaller innefattande grovt våld i uppenbart syfte att döda poliser, har aktualiserat behovet av sammanhållning och rakryggat stöd för Polisen och för det svenska samhället i stort.",2022-05-04 09:24:55,95972673,jimmieakesson,[],853,13,35
29
+ 27,1521752661170794496,Järvaveckan får välja – Kakan Hermansson eller Jimmie Åkesson,2022-05-04 09:24:41,95972673,jimmieakesson,[],3924,465,215
30
+ 28,1521489890369843200,Varför svenska barn påtvingas politisk indoktrinering i skolan är en fråga som kräver en omedelbar förklaring. Vi kommer att kalla Skolverkets generaldirektör till utbildningsutskottet. Från dagens nationella prov i historia.,2022-05-03 16:00:32,95972673,jimmieakesson,[],3359,168,246
31
+ 29,1521489797038157827,Det här äcklar mig på riktigt. Propaganda riktad till skolbarn hör hemma i diktaturer. https://t.co/BDYiNs8NDV,2022-05-03 16:00:10,95972673,jimmieakesson,[],6804,735,711
32
+ 30,1521395241454034945, https://t.co/tpIq94r7BG,2022-05-03 09:44:26,95972673,jimmieakesson,['https://www.youtube.com/watch?v=f-eK1cgzGF8&ab_channel=Sverigedemokraterna'],178,10,20
33
+ 31,1521180859012943878,Ikväll medverkar jag i Aktuellt. Ämnet är trafiken och Sveriges åtgärder för att minska utsläppen. Debatt mot Annie Lööf. Aktuellt sänds i SVT2 med start kl 21.00.,2022-05-02 19:32:33,95972673,jimmieakesson,[],874,104,53