NOTE: This Use Case is not purposed for resource constrained devices.
Hate Speech And Offensive Language Detection¶
Credit: AITS Cainvas Community
Photo by Lucien Leyh on Dribbble
Nowadays we are well aware of the fact that if social media platforms are not handled carefully then they can create chaos in the world.One of the problems faced on these platforms are usage of Hate Speech and Offensive Language.Usage of such Language often results in fights, crimes or sometimes riots at worst.So, Detection of such language is essential and as humans cannot monitor such large volumes of data, we can take help of AI and detect the use of such language and prevent users from using such languages.
Importing Libraries¶
In [ ]:
# Essential tools
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from wordcloud import WordCloud
#to data preprocessing
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
#NLP tools
import re
import nltk
nltk.download('stopwords')
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer
from sklearn.feature_extraction.text import CountVectorizer
#train split and fit models
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB
#model selection
from sklearn.metrics import confusion_matrix, accuracy_score
import os
Importing the Dataset¶
In [2]:
tweets_df = pd.read_csv('https://cainvas-static.s3.amazonaws.com/media/user_data/cainvas-admin/twitter_labeled_data.csv')
Data Visualization and Preprocessing¶
In [3]:
tweets_df.head()
Out[3]:
In [4]:
tweets_df = tweets_df.drop(['neither','Unnamed: 0','count','hate_speech','offensive_language'], axis= 1)
In [5]:
tweets_df.head()
Out[5]:
Adding length column to data to see length of tweets¶
In [6]:
tweets_df['length'] = tweets_df['tweet'].apply(len)
In [7]:
tweets_df.head()
Out[7]:
In [8]:
tweets_df.describe()
Out[8]:
Segregating data on the basis of class¶
In [9]:
hatespeech = tweets_df[tweets_df['class']==0]
In [10]:
hatespeech
Out[10]:
In [11]:
offensive = tweets_df[tweets_df['class']==1]
In [12]:
offensive
Out[12]:
In [13]:
neutral = tweets_df[tweets_df['class']==2]
In [14]:
neutral
Out[14]:
Visualizing each class¶
In [15]:
sentences = hatespeech['tweet'].tolist()
len(sentences)
Out[15]:
In [16]:
sentences_as_one_string = " ".join(sentences)
In [17]:
plt.figure(figsize=(20,20))
plt.imshow(WordCloud().generate(sentences_as_one_string))
Out[17]:
In [18]:
sentences = offensive['tweet'].tolist()
len(sentences)
Out[18]:
In [19]:
sentences_as_one_string = " ".join(sentences)
In [20]:
plt.figure(figsize=(20,20))
plt.imshow(WordCloud().generate(sentences_as_one_string))
Out[20]:
In [21]:
sentences = neutral['tweet'].tolist()
len(sentences)
Out[21]:
In [22]:
sentences_as_one_string = " ".join(sentences)
In [23]:
plt.figure(figsize=(20,20))
plt.imshow(WordCloud().generate(sentences_as_one_string))
Out[23]:
Preprocessing the tweets¶
In [24]:
import string
string.punctuation
Out[24]:
In [25]:
# Let's define a pipeline to clean up all the messages
# The pipeline performs the following: (1) remove punctuation, (2) remove stopwords
def message_cleaning(message):
Test_punc_removed = [char for char in message if char not in string.punctuation]
Test_punc_removed_join = ''.join(Test_punc_removed)
Test_punc_removed_join_clean = [word for word in Test_punc_removed_join.split() if word.lower() not in stopwords.words('english')]
Test_punc_removed_join_clean_join = ' '.join(Test_punc_removed_join_clean)
return Test_punc_removed_join_clean_join
In [26]:
# Create a new Dataframe for cleaned text
tweets_df_clean = pd.DataFrame(columns=['class', 'tweet'])
tweets_df_clean['tweet'] = tweets_df['tweet'].apply(message_cleaning)
tweets_df_clean['class'] = tweets_df['class']
In [27]:
tweets_df_clean.head()
Out[27]:
In [28]:
print(tweets_df_clean['tweet'][5]) # show the cleaned up version
print(tweets_df['tweet'][5]) # show the original version
Vectorizing the cleaned text for model training¶
In [29]:
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(analyzer = message_cleaning)
tweets_countvectorizer = CountVectorizer(analyzer = message_cleaning, dtype = 'uint8').fit_transform(tweets_df_clean['tweet']).toarray()
In [30]:
tweets_countvectorizer.shape
Out[30]:
In [31]:
X = tweets_countvectorizer
X
Out[31]:
In [32]:
y = tweets_df_clean['class']
y = pd.get_dummies(y)
y = np.array(y)
y
Out[32]:
In [33]:
X.shape
Out[33]:
In [34]:
y.shape
Out[34]:
Test-Train Split¶
In [35]:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1)
In [36]:
X_train.shape
Out[36]:
In [37]:
total_words = 200
total_words
Out[37]:
Model architecture¶
In [38]:
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten,RepeatVector, Embedding, Input, LSTM, Conv1D, MaxPool1D, Bidirectional
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Embedding, Dense, GlobalAveragePooling1D
In [39]:
# Sequential Model
model1 = Sequential()
# embeddidng layer
model1.add(Embedding(total_words, output_dim = 32))
model1.add(LSTM(32))
model1.add(RepeatVector(200))
model1.add(GlobalAveragePooling1D())
model1.add(Dense(32, activation='relu'))
model1.add(Dense(16, activation='relu'))
model1.add(Dense(3,activation= 'softmax'))
model1.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
model1.summary()
Model Training¶
In [40]:
# train the model
history = model1.fit(X_train, y_train, batch_size = 256, validation_split = 0.1, epochs = 50)
Model Accuracy can be improved and around 80% accuracy acn be achieved by letting the model train a little longer
Training Plots¶
In [41]:
# plot the training artifacts
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train_loss','val_loss'], loc = 'upper right')
plt.show()
In [42]:
# plot the training artifacts
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('Model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train_acc','val_acc'], loc = 'upper right')
plt.show()
Save the trained model¶
In [43]:
model1.save("hate_speech.h5")
Accessing the Model's Performance¶
In [44]:
model1.evaluate(X_test,y_test)
Out[44]:
In [45]:
print(tweets_df['tweet'][0])
print(tweets_df['tweet'][1])
print(tweets_df['tweet'][2])
print(tweets_df['tweet'][3])
print(tweets_df['tweet'][4])
In [46]:
tweets_countvectorizer = CountVectorizer(analyzer = message_cleaning, dtype = 'uint8').fit_transform(tweets_df['tweet'][:5]).toarray()
In [47]:
preds = model1.predict(tweets_countvectorizer)
In [48]:
preds_class = []
for i in range(len(preds)):
preds_class.append(np.argmax(preds[i]))
preds_class = np.array(preds_class)
In [49]:
df = pd.DataFrame(columns=['Predicted Labels', 'Actual Labels'])
df['Predicted Labels'] = preds_class
df['Actual Labels'] = tweets_df['class'][:5]
df.head()
Out[49]:
Compiling the model with DeepC¶
In [50]:
!deepCC hate_speech.h5