{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Who's Tweeting? Trump or Trudeau?\n", "> Tweets are notoriously difficult, as they are shorter than most texts and usually have hard-to-parse content like hashtags, mentions, links and emoji. Despite the difficulties, tweets are fun content, so in this notebook we'll take a look at classifying two prominent North American politicians. Can we determine if it is Donald Trump or Justin Trudeau based on just a tweet? This is the Result of Project \"Who's Tweeting? Trump or Trudeau?\", via datacamp.\n", "\n", "- toc: true \n", "- badges: true\n", "- comments: true\n", "- author: Chanseok Kang\n", "- categories: [Python, Datacamp, Data_Science]\n", "- image: images/President_Donald_Trump_and_Prime_Minister_Justin_Trudeau.jpg" ] }, { "cell_type": "markdown", "metadata": { "dc": { "key": "4" }, "deletable": false, "editable": false, "run_control": { "frozen": true }, "tags": [ "context" ] }, "source": [ "## 1. Tweet classification: Trump vs. Trudeau\n", "
So you think you can classify text? How about tweets? In this notebook, we'll take a dive into the world of social media text classification by investigating how to properly classify tweets from two prominent North American politicians: Donald Trump and Justin Trudeau.
\n", "\n", "Photo Credit: Executive Office of the President of the United States
\n", "Tweets pose specific problems to NLP, including the fact they are shorter texts. There are also plenty of platform-specific conventions to give you hassles: mentions, #hashtags, emoji, links and short-hand phrases (ikr?). Can we overcome those challenges and build a useful classifier for these two tweeters? Yes! Let's get started.
\n", "To begin, we will import all the tools we need from scikit-learn. We will need to properly vectorize our data (CountVectorizer
and TfidfVectorizer
). And we will also want to import some models, including MultinomialNB
from the naive_bayes
module, LinearSVC
from the svm
module and PassiveAggressiveClassifier
from the linear_model
module. Finally, we'll need sklearn.metrics
and train_test_split
and GridSearchCV
from the model_selection
module to evaluate and optimize our model.
To begin, let's start with a corpus of tweets which were collected in November 2017. They are available in CSV format. We'll use a Pandas DataFrame to help import the data and pass it to scikit-learn for further processing.
\n", "Since the data has been collected via the Twitter API and not split into test and training sets, we'll need to do this. Let's use train_test_split()
with random_state=53
and a test size of 0.33, just as we did in the DataCamp course. This will ensure we have enough test data and we'll get the same results no matter where or when we run this code.
We have the training and testing data all set up, but we need to create vectorized representations of the tweets in order to apply machine learning.
\n", "To do so, we will utilize the CountVectorizer
and TfidfVectorizer
classes which we will first need to fit to the data.
Once this is complete, we can start modeling with the new vectorized tweets!
" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "dc": { "key": "18" }, "tags": [ "sample_code" ] }, "outputs": [], "source": [ "# Initialize count vectorizer\n", "count_vectorizer = CountVectorizer(stop_words='english', min_df=0.05, max_df=0.9)\n", "\n", "# Create count train and test variables\n", "count_train = count_vectorizer.fit_transform(X_train)\n", "count_test = count_vectorizer.transform(X_test)\n", "\n", "# Initialize tfidf vectorizer\n", "tfidf_vectorizer = TfidfVectorizer(stop_words='english', min_df=0.05, max_df=0.9)\n", "\n", "# Create tfidf train and test variables\n", "tfidf_train = tfidf_vectorizer.fit_transform(X_train)\n", "tfidf_test = tfidf_vectorizer.transform(X_test)" ] }, { "cell_type": "markdown", "metadata": { "dc": { "key": "25" }, "deletable": false, "editable": false, "run_control": { "frozen": true }, "tags": [ "context" ] }, "source": [ "## 4. Training a multinomial naive Bayes model\n", "Now that we have the data in vectorized form, we can train the first model. Investigate using the Multinomial Naive Bayes model with both the CountVectorizer
and TfidfVectorizer
data. Which do will perform better? How come?
To assess the accuracies, we will print the test sets accuracy scores for both models.
" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "dc": { "key": "25" }, "tags": [ "sample_code" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NaiveBayes Tfidf Score: 0.803030303030303\n", "NaiveBayes Count Score: 0.7954545454545454\n" ] } ], "source": [ "# Create a MulitnomialNB model\n", "tfidf_nb = MultinomialNB()\n", "\n", "# ... Train your model here ...\n", "tfidf_nb.fit(tfidf_train, y_train)\n", "\n", "# Run predict on your TF-IDF test data to get your predictions\n", "tfidf_nb_pred = tfidf_nb.predict(tfidf_test)\n", "\n", "# Calculate the accuracy of your predictions\n", "tfidf_nb_score = metrics.accuracy_score(y_test, tfidf_nb_pred)\n", "\n", "# Create a MulitnomialNB model\n", "count_nb = MultinomialNB()\n", "# ... Train your model here ...\n", "count_nb.fit(count_train, y_train)\n", "\n", "# Run predict on your count test data to get your predictions\n", "count_nb_pred = count_nb.predict(count_test)\n", "\n", "# Calculate the accuracy of your predictions\n", "count_nb_score = metrics.accuracy_score(y_test, count_nb_pred)\n", "\n", "print('NaiveBayes Tfidf Score: ', tfidf_nb_score)\n", "print('NaiveBayes Count Score: ', count_nb_score)" ] }, { "cell_type": "markdown", "metadata": { "dc": { "key": "32" }, "deletable": false, "editable": false, "run_control": { "frozen": true }, "tags": [ "context" ] }, "source": [ "## 5. Evaluating our model using a confusion matrix\n", "We see that the TF-IDF model performs better than the count-based approach. Based on what we know from the NLP fundamentals course, why might that be? We know that TF-IDF allows unique tokens to have a greater weight - perhaps tweeters are using specific important words that identify them! Let's continue the investigation.
\n", "For classification tasks, an accuracy score doesn't tell the whole picture. A better evaluation can be made if we look at the confusion matrix, which shows the number correct and incorrect classifications based on each class. We can use the metrics, True Positives, False Positives, False Negatives, and True Negatives, to determine how well the model performed on a given class. How many times was Trump misclassified as Trudeau?
" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "dc": { "key": "32" }, "tags": [ "sample_code" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Confusion matrix, without normalization\n", "Confusion matrix, without normalization\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "