<jupyter_start><jupyter_text>I love reading The Onion. The brilliant snark of their universally caustic takes on politics and everyday life make me feel less alone in reacting to the utter bizarreness of modern life.It is a reflection of the weirdness of our reality that Onion headlines so frequently get mistaken for real ones. There are plenty of stories about celebrities, politicians, and other public figures getting fooled by and inciting outrage over stories that in hindsight seem like they would be too obviously absurd to be taken seriously. But are they? Could an algorithm tell the difference?In this project, I'll be tackling just that question.<jupyter_code>import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline<jupyter_output><empty_output><jupyter_text>Obtain First, we need a source of these headlines. As a seed, I'll be using a collection of headlines from The Onion and the Huffington Post. These were collected for sarcasm classification. I have some qualms with the appropriateness of this data for that purpose -- it is not entirely clear to me or I think to anyone that sarcasm and satire/parody are the same thing. Perhaps there is some intersection, but the line is fuzzy. Still, for *our* purposes, this is a good dataset.<jupyter_code>sarcasm = pd.read_json('../data/raw/Sarcasm_Headlines_Dataset.json', lines=True)
sarcasm.head()
sarcasm.info()
sarcasm['is_sarcastic'].value_counts()<jupyter_output><empty_output><jupyter_text>This is promising. We have rows with the article link and lowercased headline, and whether a headline is 'sarcastic' or not. I don't believe that sarcastic is a good way to characterize this, so I'll just alter that for my own happiness.<jupyter_code>sarcasm.columns = ['article_link', 'headline', 'is_parody']
sarcasm.head()<jupyter_output><empty_output><jupyter_text>I know from some previous exploration that this dataset includes some articles that are linked through the Huffington Post, but not from the Huffington Post. Some of these might be parody articles themselves, and so might be miscoded. Let's make sure.<jupyter_code>sarcasm.loc[sarcasm['article_link'].str.contains('comhttp')]
len('https://www.huffingtonpost.com')
sarcasm.loc[sarcasm['article_link'].str.contains('comhttp'), 'article_link'] = sarcasm.loc[sarcasm['article_link'].str.contains('comhttp'), 'article_link'].str[30:]
sarcasm.loc[(sarcasm['article_link'].str.contains('onion')) & (sarcasm['is_parody'] == 0)]
sarcasm.iloc[19948, 2] = 1
parody = sarcasm[sarcasm['is_parody'] == 1]
type(parody)
parody.to_csv('../data/processed/parody.csv')<jupyter_output><empty_output><jupyter_text>Word2Vec<jupyter_code>from gensim.models import Word2Vec
from keras.preprocessing import text, sequence
from sklearn.model_selection import train_test_split
y = sarcasm['is_parody'].values
y
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.layers import Dense, Input, LSTM, Embedding, Dropout, Activation
from keras.layers import Bidirectional, GlobalMaxPool1D
from keras.models import Model
from keras import initializers, regularizers, constraints, optimizers, layers
X_train, X_test, y_train, y_test = train_test_split(sarcasm['headline'], y, test_size=.20)
type(X_train)
tokenizer = Tokenizer(num_words=20000)
tokenizer.fit_on_texts(list(X_train))
list_tokenized_train = tokenizer.texts_to_sequences(X_train)
list_tokenized_test = tokenizer.texts_to_sequences(X_test)
total_word_counts = [len(headline) for headline in list_tokenized_train]
fig, ax = plt.subplots(figsize=(9,9))
ax.hist(total_word_counts, bins = 40)
max(total_word_counts)
counter = pd.Series(total_word_counts)
counter.value_counts()
maxlen = 18
X_t = pad_sequences(list_tokenized_train, maxlen=maxlen)
X_te = pad_sequences(list_tokenized_test, maxlen=maxlen)
X_t.shape
tokens = tokenizer.sequences_to_texts(list_tokenized_train) + tokenizer.sequences_to_texts(list_tokenized_test)
tokens = [t.split(' ') for t in tokens]
tokens[:1]
model = Word2Vec(tokens, size=100, window=5, min_count=1, workers=4)

model.train(tokens, total_examples=model.corpus_count, epochs=10)
embeddings = model.wv
keras_weights = embeddings.get_keras_embedding()
embeddings.most_similar(positive=['obama', 'policy'])
from gensim.models import Word2Vec
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.layers import Dense, Input, LSTM, Embedding, Dropout, Activation, Conv1D, MaxPooling1D, GlobalMaxPooling1D
from keras.layers import Bidirectional, GlobalMaxPool1D
from keras.models import Model, Sequential
from keras import initializers, regularizers, constraints, optimizers, layers
model = Sequential()
model.add(keras_weights)
model.add(Conv1D(64, 3, activation='relu', padding='same'))
model.add(MaxPooling1D())
model.add(Conv1D(64, 3, activation='relu', padding='same'))
model.add(GlobalMaxPooling1D())
model.add(Dropout(0.5))
model.add(Dense(32, activation='relu', kernel_regularizer=regularizers.l2(1e-4)))
model.add(Dense(1, activation='sigmoid'))
adam = optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
model.compile(loss='binary_crossentropy', optimizer=adam, metrics=['accuracy'])
model.summary()
early_stopping = EarlyStopping(monitor='val_loss', min_delta=0.01, patience=4, verbose=1)
callbacks_list = [early_stopping]
batch_size = 256 
num_epochs = 30
hist = model.fit(X_t, y_train, batch_size=batch_size, epochs=num_epochs, validation_split=0.1, shuffle=True, verbose=2)
y_pred = model.predict(X_te)
from sklearn.metrics import accuracy_score
def rounder(array):
    new = []
    for i in array:
        if i >= .5:
            new.append(1)
        else:
            new.append(0)
    return np.array(new)
y_pred_bin = rounder(y_pred)
accuracy_score(y_test, y_pred_bin)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09926347505858721, 'fraction_numerical': 0.015567458988952126, 'mean_word_length': 6.851511169513798, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 22, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '495153', 'license': 'MIT', 'n_tokens_mistral': 2012, 'n_tokens_neox': 1915, 'n_words': 542, 'path': 'notebooks/Untitled.ipynb', 'repo_name': 'calremmel/Proj4', 'size': '5974'}