Text Classification

Toxic challenge - classify comments as toxic or not

In [4]:
import numpy as np
import pandas as pd
import keras
import matplotlib.pyplot as plt
%matplotlib inline
import vis
Using TensorFlow backend.

Get the data

Uncomment and run this to get the data

In [6]:
#!wget http://bit.do/deep_toxic_train -P data/
#! mv data/deep_toxic_train data/train.zip
In [7]:
df = pd.read_csv("data/train.zip")
In [10]:
df.columns
Out[10]:
Index(['id', 'comment_text', 'toxic', 'severe_toxic', 'obscene', 'threat',
       'insult', 'identity_hate'],
      dtype='object')
In [11]:
df.head()
Out[11]:
id comment_text toxic severe_toxic obscene threat insult identity_hate
0 0000997932d777bf Explanation\nWhy the edits made under my usern... 0 0 0 0 0 0
1 000103f0d9cfb60f D'aww! He matches this background colour I'm s... 0 0 0 0 0 0
2 000113f07ec002fd Hey man, I'm really not trying to edit war. It... 0 0 0 0 0 0
3 0001b41b1c6bb37e "\nMore\nI can't make any real suggestions on ... 0 0 0 0 0 0
4 0001d958c54c6e35 You, sir, are my hero. Any chance you remember... 0 0 0 0 0 0

Step 1: Create the Input and Output Data

In [12]:
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
In [18]:
train_sentences = df["comment_text"]
train_sentences.head()
Out[18]:
0    Explanation\nWhy the edits made under my usern...
1    D'aww! He matches this background colour I'm s...
2    Hey man, I'm really not trying to edit war. It...
3    "\nMore\nI can't make any real suggestions on ...
4    You, sir, are my hero. Any chance you remember...
Name: comment_text, dtype: object
In [17]:
# Tokenizer
max_features = 2000
tokenizer = Tokenizer(num_words = max_features)
tokenizer.fit_on_texts(list(train_sentences))
In [21]:
# Index Representation
tokenized_train = tokenizer.texts_to_sequences(train_sentences)
In [24]:
len(tokenized_train[0]), len(tokenized_train[1])
Out[24]:
(34, 11)
In [28]:
## Selecting Padding
# Find the length of each sentence and plot the lenght
number_of_words = [len(comment) for comment in tokenized_train]
plt.hist(number_of_words, bins = np.arange(0, 500, 10));
In [34]:
# Padding to make in uniform
maxlen = 200
X = pad_sequences(tokenized_train, maxlen = maxlen, padding="post")
In [35]:
X
Out[35]:
array([[688,  75,   1, ...,   0,   0,   0],
       [ 52,  13, 555, ...,   0,   0,   0],
       [412, 437,  73, ...,   0,   0,   0],
       ...,
       [ 46, 737,  23, ...,   0,   0,   0],
       [  4,  11, 574, ...,   0,   0,   0],
       [  4,   7, 134, ...,   0,   0,   0]], dtype=int32)
In [37]:
labels = df.iloc[:,2].values
labels
Out[37]:
array([0, 0, 0, ..., 0, 0, 0])
In [43]:
# Baseline Beat
sum(labels), len(labels), 1 - sum(labels)/len(labels)
Out[43]:
(15294, 159571, 0.9041555169799024)
In [44]:
from keras.utils import to_categorical
In [45]:
y = to_categorical(labels)
In [46]:
from sklearn.model_selection import train_test_split
In [47]:
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size=0.2,
                                                   random_state=42)
In [48]:
X_train.shape, X_test.shape, y_test.shape, y_train.shape
Out[48]:
((127656, 200), (31915, 200), (31915, 2), (127656, 2))

Step 2: Create the Model Architecture

In [68]:
from keras.models import Sequential
from keras.layers import Dense, Embedding, Dropout, LSTM, Flatten
In [70]:
model = Sequential()
model.add(Embedding(max_features, output_dim=128, input_length=maxlen))
model.add(Flatten())
model.add(Dense(50, activation="relu"))
model.add(Dropout(0.1))
model.add(Dense(2, activation="sigmoid"))
In [71]:
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_8 (Embedding)      (None, 200, 128)          256000    
_________________________________________________________________
flatten_2 (Flatten)          (None, 25600)             0         
_________________________________________________________________
dense_8 (Dense)              (None, 50)                1280050   
_________________________________________________________________
dropout_5 (Dropout)          (None, 50)                0         
_________________________________________________________________
dense_9 (Dense)              (None, 2)                 102       
=================================================================
Total params: 1,536,152
Trainable params: 1,536,152
Non-trainable params: 0
_________________________________________________________________

Step 3: compile and fit the model

In [72]:
model.compile(loss="binary_crossentropy", optimizer="rmsprop", metrics=["accuracy"])
In [74]:
output = model.fit(X_train, y_train, batch_size=128, epochs=5, 
                   validation_data =(X_test, y_test), verbose=1)
Train on 127656 samples, validate on 31915 samples
Epoch 1/5
127656/127656 [==============================] - 7s 56us/step - loss: 0.1182 - acc: 0.9603 - val_loss: 0.1582 - val_acc: 0.9520
Epoch 2/5
127656/127656 [==============================] - 7s 55us/step - loss: 0.0976 - acc: 0.9663 - val_loss: 0.1719 - val_acc: 0.9505
Epoch 3/5
127656/127656 [==============================] - 7s 55us/step - loss: 0.0807 - acc: 0.9723 - val_loss: 0.1934 - val_acc: 0.9491
Epoch 4/5
127656/127656 [==============================] - 7s 55us/step - loss: 0.0680 - acc: 0.9767 - val_loss: 0.2238 - val_acc: 0.9491
Epoch 5/5
127656/127656 [==============================] - 7s 56us/step - loss: 0.0588 - acc: 0.9801 - val_loss: 0.2534 - val_acc: 0.9418

Model 2 - LSTM

In [75]:
from keras.layers import LSTM
In [82]:
model_LSTM = Sequential()
model_LSTM.add(Embedding(max_features, output_dim=128, input_length=maxlen))
model_LSTM.add(LSTM(60))
model_LSTM.add(Dropout(0.1))
model_LSTM.add(Dense(2, activation="sigmoid"))
In [83]:
model_LSTM.compile(loss="binary_crossentropy", optimizer="rmsprop", metrics=["accuracy"])
In [84]:
output = model_LSTM.fit(X_train, y_train, batch_size=128, epochs=2, 
                   validation_data =(X_test, y_test), verbose=1)
Train on 127656 samples, validate on 31915 samples
Epoch 1/2
127656/127656 [==============================] - 466s 4ms/step - loss: 0.3147 - acc: 0.9043 - val_loss: 0.3710 - val_acc: 0.9010
Epoch 2/2
127656/127656 [==============================] - 465s 4ms/step - loss: 0.2245 - acc: 0.9187 - val_loss: 0.1547 - val_acc: 0.9486