Skip to content

Instantly share code, notes, and snippets.

@daniel-covelli
Created April 16, 2020 01:38
Show Gist options
  • Save daniel-covelli/055306a9d551e97cd7cfc5cd27e735e7 to your computer and use it in GitHub Desktop.
Save daniel-covelli/055306a9d551e97cd7cfc5cd27e735e7 to your computer and use it in GitHub Desktop.
SPAM/HAM.ipynb
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "SPAM/HAM.ipynb",
"provenance": [],
"mount_file_id": "1WPoOppqzkURZj9mayZA_qNwtbyBQQpEm",
"authorship_tag": "ABX9TyPMyWVbZ1W+6/H6jvolyokR",
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/daniel-covelli/055306a9d551e97cd7cfc5cd27e735e7/spam-ham.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "tTId221qAfIW",
"colab_type": "text"
},
"source": [
"# Spam/Ham Classification\n",
"The following code will aim to classify and distinguish spam emails from non-spam emails."
]
},
{
"cell_type": "code",
"metadata": {
"id": "J0ONaCJMAeBN",
"colab_type": "code",
"colab": {}
},
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"\n",
"import matplotlib.pyplot as plt\n",
"\n",
"import seaborn as sns"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "RpvjlKJRBYCJ",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 204
},
"outputId": "6f62a87f-2a04-4d0d-8001-830c376dd7fd"
},
"source": [
"data = pd.read_csv(\"/content/drive/My Drive/Colab Notebooks/DATA/SPAM HAM/spam.csv\", encoding='latin-1')\n",
"data.head()"
],
"execution_count": 87,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>v1</th>\n",
" <th>v2</th>\n",
" <th>Unnamed: 2</th>\n",
" <th>Unnamed: 3</th>\n",
" <th>Unnamed: 4</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>ham</td>\n",
" <td>Go until jurong point, crazy.. Available only ...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>ham</td>\n",
" <td>Ok lar... Joking wif u oni...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>spam</td>\n",
" <td>Free entry in 2 a wkly comp to win FA Cup fina...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>ham</td>\n",
" <td>U dun say so early hor... U c already then say...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>ham</td>\n",
" <td>Nah I don't think he goes to usf, he lives aro...</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" v1 ... Unnamed: 4\n",
"0 ham ... NaN\n",
"1 ham ... NaN\n",
"2 spam ... NaN\n",
"3 ham ... NaN\n",
"4 ham ... NaN\n",
"\n",
"[5 rows x 5 columns]"
]
},
"metadata": {
"tags": []
},
"execution_count": 87
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "p1Icxz18D-cH",
"colab_type": "text"
},
"source": [
"Lets clean the data a bit and check if there are any NaN values that we should. be concerned about.\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "eeAkVch7DM-B",
"colab_type": "code",
"colab": {}
},
"source": [
" def clean(df):\n",
" '''\n",
" Args:\n",
" df: a pandas datframe\n",
"\n",
" Returns:\n",
" A cleaned data frame, with relevant columns \n",
" '''\n",
" clean = df.rename(columns={'v2': \"email\"})\n",
" clean['spam'] = clean.v1.map({'ham':0,'spam':1})\n",
" clean = clean[['spam', 'email']]\n",
" return clean\n",
"\n",
"data = clean(data)"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "l63MMWC4M9PB",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 68
},
"outputId": "07c01fe1-efa4-41fd-f087-94a04690ad39"
},
"source": [
"data.isnull().sum(axis = 0)"
],
"execution_count": 89,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"spam 0\n",
"email 0\n",
"dtype: int64"
]
},
"metadata": {
"tags": []
},
"execution_count": 89
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "GYDLGKPKD9XX",
"colab_type": "text"
},
"source": [
"The clean **data** DataFrame contains labeled data that will be used to train the model. It contains the following columns:\n",
"\n",
"\n",
"1. **spam**: 1 if an email is spam, 0 if an email is ham (not spam)\n",
"2. **email**: The text of the email\n",
"\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "D4MjKS8uITHr",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 204
},
"outputId": "6e4381f6-caad-4503-9564-7c6f8edbacf9"
},
"source": [
"data.head()"
],
"execution_count": 90,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>spam</th>\n",
" <th>email</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>Go until jurong point, crazy.. Available only ...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>0</td>\n",
" <td>Ok lar... Joking wif u oni...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>1</td>\n",
" <td>Free entry in 2 a wkly comp to win FA Cup fina...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>0</td>\n",
" <td>U dun say so early hor... U c already then say...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>0</td>\n",
" <td>Nah I don't think he goes to usf, he lives aro...</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" spam email\n",
"0 0 Go until jurong point, crazy.. Available only ...\n",
"1 0 Ok lar... Joking wif u oni...\n",
"2 1 Free entry in 2 a wkly comp to win FA Cup fina...\n",
"3 0 U dun say so early hor... U c already then say...\n",
"4 0 Nah I don't think he goes to usf, he lives aro..."
]
},
"metadata": {
"tags": []
},
"execution_count": 90
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "pBfOY0_JD3Bp",
"colab_type": "text"
},
"source": [
"Now lets split the data into a test and training set. \n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "akeHue7HJRi6",
"colab_type": "code",
"colab": {}
},
"source": [
"from sklearn.model_selection import train_test_split\n",
"\n",
"train, test = train_test_split(data, test_size=0.1, random_state=83)"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "c5gyrbZ_iyna",
"colab_type": "text"
},
"source": [
"# Data Exploration"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "poLlZlXme2T0",
"colab_type": "text"
},
"source": [
"Lets try do identity some features that destinguish our spam emails from our ham emails."
]
},
{
"cell_type": "code",
"metadata": {
"id": "aozUilmoDuVO",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 105
},
"outputId": "e6690fc2-f5f2-434a-8f69-10eecd52c107"
},
"source": [
"spam_emails = train[train['spam']==1]['email']\n",
"print(spam_emails.iloc[0])\n",
"print(spam_emails.iloc[3])\n",
"print(spam_emails.iloc[33])\n",
"print(spam_emails.iloc[49])\n"
],
"execution_count": 92,
"outputs": [
{
"output_type": "stream",
"text": [
"Congratulations ur awarded 500 of CD vouchers or 125gift guaranteed & Free entry 2 100 wkly draw txt MUSIC to 87066 TnCs www.Ldew.com1win150ppmx3age16\n",
"Someone U know has asked our dating service 2 contact you! Cant Guess who? CALL 09058091854 NOW all will be revealed. PO BOX385 M6 6WU\n",
"Sunshine Hols. To claim ur med holiday send a stamped self address envelope to Drinks on Us UK, PO Box 113, Bray, Wicklow, Eire. Quiz Starts Saturday! Unsub Stop\n",
"Text PASS to 69669 to collect your polyphonic ringtones. Normal gprs charges apply only. Enjoy your tones\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "zp9_fhnofy1w",
"colab_type": "text"
},
"source": [
"As we can see, many of the spam emails have some mention 'winning' something that is free or 'matching' with someone romantically with specific request to 'text' or 'call' a specific number. Nowing this, we can target specific keywords that we think might appear in spam emails more frequently. Lets define a function that will do this. "
]
},
{
"cell_type": "code",
"metadata": {
"id": "HIufYVKZhG0E",
"colab_type": "code",
"colab": {}
},
"source": [
"def words_in_texts(words, texts):\n",
" '''\n",
" Arguments:\n",
" words: words to find\n",
" texts: strings to search through\n",
" \n",
" Returns:\n",
" NumPy array of 0s and 1s with shape (n, p) \n",
" where n is the number of texts and p is the number of words.\n",
" '''\n",
" master = []\n",
" for n in texts:\n",
" minor = []\n",
" for p in words:\n",
" if p in n:\n",
" minor += [1]\n",
" else:\n",
" minor += [0]\n",
" master += [minor]\n",
" indicator_array = np.asarray(master)\n",
" return indicator_array"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "Y6Z9SwCO321W",
"colab_type": "text"
},
"source": [
"Lets check to see if we can find words that appear in spam emails more frequently then ham emails."
]
},
{
"cell_type": "code",
"metadata": {
"id": "tk9NHq1x4DG1",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 457
},
"outputId": "fcf81466-693b-45f0-a9c3-487f0a32c281"
},
"source": [
"def word_viz(df, words):\n",
" '''\n",
" Args:\n",
" df: DataFrame containing emails\n",
" words: a list of 5 words to check\n",
" Returns:\n",
" A Seaborn BarPlot of the proportion that each word\n",
" is either in spam or ham emails\n",
" '''\n",
" # creates an array of insances p words show up in n emails \n",
" hits = words_in_texts(words, df['email'])\n",
" hits = np.c_[hits, df.spam.map({0:'ham', 1:'spam'})]\n",
" \n",
" # gets column i in matrix m\n",
" def column(m, i):\n",
" return [row[i] for row in m]\n",
" \n",
" # constructs DataFrame into catplot readable format w/ df.melt( )\n",
" df = pd.DataFrame({\n",
" words[0]: column(hits, 0),\n",
" words[1]: column(hits, 1),\n",
" words[2]: column(hits, 2),\n",
" words[3]: column(hits, 3),\n",
" words[4]:column(hits,4),\n",
" 'type': column(hits,5)\n",
" })\n",
" df = df.melt('type')\n",
"\n",
" # create barplot of new DataFrame\n",
" g = sns.catplot(x=\"variable\", y=\"value\", hue=\"type\", data=df,\n",
" height=6, kind=\"bar\", palette=\"muted\", ci=None,\n",
" legend_out=False)\n",
" g.set_ylabels(\"Proportion of Emails\")\n",
" g.set_xlabels(\"Words\")\n",
" plt.title('Frequency of words in Spam/Ham Emails')\n",
" plt.legend(prop={'size': 16}, title = None)\n",
" g.fig.set_figwidth(10)\n",
" return g\n",
"\n",
"words = ['win', 'txt', 'text', 'call', 'award']\n",
"word_viz(train, words);"
],
"execution_count": 121,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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B7T8+fUeXpckSepFxx13HEceeSQAY8aM4ZZbbuHSSy/lyCOPZO211+b73//+wrbz589nzz33ZPjw4Vx66aV89rOfXWRdH/7wh/nyl78MwOjRo7n66qsZN24c06ZNY9NNNwVgwYIF7L///tx+++28+93v7qV3+Vr2dEqSJPWivffee5HxN7/5zTz++OMLx6+44gp23nlnhgwZQr9+/Xj961/PP//5T6ZOnfqade21114Lh/v168fIkSPZcsstFwZOgK222gqAGTNmrOi3slQMnZIkSb1onXXWWWR8zTXXXPhM82uvvZZDDjmErbfemksuuYQ777yTyZMnM2zYsG6fez506NBFxvv379/tNGC5npu+Inh4XZIkqY+47LLLGDlyJOPHj1847ZVXXmH27NmtK2oFsadTkiSpj5gzZ85rbhx/8cUXM3/+/BZVtOLY0ylJktRHjB07lmuuuYbPfvaz7LPPPkyZMoVvf/vbDBkypNWlLTdDpyRJWqks62MoVwYf//jHmTFjBhdeeCHf+9732HHHHbn22ms58MADW13acovMbHUNK0RHR0dOmTKl1WVIkrREPpGoOQ8//DBbb7118e2oeU3sk1jcDM/plCRJUnGGTkmSJBVn6JQkSVJxhk5JkiQVZ+iUJElScYZOSZIkFWfolCRJUnGGTkmSJBVn6JQkSVJxhk5JkiQV57PXJUnSSqXVjxHtjUeAtiN7OiVJklScoVOSJEnFGTolSZJ6ybRp0zjwwANZb731GDBgACNGjOCggw5i3rx5TJo0iYjgJz/5CUcccQRDhw5l8ODBfOhDH+Lpp59eZD3nnHMOu+yyC+ussw5DhgzhbW97G9ddd90ibR577DEigu9+97ucdNJJrL/++gwaNIjDDjuMOXPmMH36dPbcc08GDhzIyJEjmTBhQtH37jmdkiRJvWTvvfdm6NChnHfeeay77rrMmjWL66+/ngULFixs85nPfIYxY8Zw6aWX8sgjj3DyySfzxBNP8Mtf/nJhm8cee4yPfexjbLLJJsybN49rr72WffbZhxtuuIGxY8cuss0zzzyT0aNHM2HCBB566CFOOOEEVlttNe655x4+/vGPc/zxx3Peeedx5JFH0tHRwahRo4q8d0OnJElSL3jqqaeYPn06P/3pT9lvv/0WTv/gBz+4SLtRo0bxwx/+EICxY8eyzjrrcNhhh/GL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\n",
"text/plain": [
"<Figure size 720x432 with 1 Axes>"
]
},
"metadata": {
"tags": [],
"needs_background": "light"
}
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Ph1xF53qWpt9",
"colab_type": "text"
},
"source": [
"We also might want to look at the length of spam and ham emails as an indicator. Lets see if that is the case. "
]
},
{
"cell_type": "code",
"metadata": {
"id": "iFmEPzvXWpDf",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 279
},
"outputId": "72d4ec6d-48fe-44cd-ee85-742646d26b27"
},
"source": [
"def email_count(df, cats):\n",
" '''\n",
" Args:\n",
" df: the DataFrame from which the data will be graphed\n",
" cats: email categories of interest\n",
" Return:\n",
" A visualization of the distribution of Email length for\n",
" for the different categories\n",
" '''\n",
" copy = df.copy()\n",
" copy['spam'] = copy.spam.map({0:'ham', 1:'spam'})\n",
" copy['len'] = copy['email'].str.len()\n",
" for cat in cats:\n",
" subset = copy[copy['spam'] == cat]\n",
"\n",
" sns.distplot(subset['len'], hist = False, kde = True,\n",
" kde_kws = {'linewidth': 3},\n",
" label = cat)\n",
"\n",
" plt.legend(prop={'size': 16}, title = None)\n",
" plt.xlabel('Length of Email Body')\n",
" plt.ylabel('Distribution')\n",
" plt.xlim(0, 500);\n",
"\n",
"email_count(train, ['ham', 'spam'])\n"
],
"execution_count": 118,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"tags": [],
"needs_background": "light"
}
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "lZ4nisHdiodQ",
"colab_type": "text"
},
"source": [
"# Creating A Model"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "urcKUwiljGLQ",
"colab_type": "text"
},
"source": [
"For our first model, lets use the words that we selected above, to create two matrices, \n",
"\n",
"1. **X_train**: whos columns are the words of interest and rows are each email \n",
"2. **Y_train**: whos column is the spam categorization and rows are each email\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "zUn8uXTE4EjQ",
"colab_type": "code",
"colab": {}
},
"source": [
"words = ['win', 'txt', 'text', 'call', 'award']\n",
"\n",
"X_train = words_in_texts(words, train['email']) \n",
"Y_train = train['spam']"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "uFEFg7BAkk0D",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 102
},
"outputId": "9c38944d-0a13-4a11-8758-018c8cd72327"
},
"source": [
"X_train[:5]"
],
"execution_count": 134,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"array([[0, 0, 0, 0, 0],\n",
" [0, 0, 0, 0, 0],\n",
" [0, 0, 0, 0, 0],\n",
" [0, 0, 0, 1, 0],\n",
" [0, 0, 0, 0, 0]])"
]
},
"metadata": {
"tags": []
},
"execution_count": 134
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "qVsMgccbj_Fb",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 119
},
"outputId": "92829106-8b90-4353-819c-3d4d36cbed61"
},
"source": [
"Y_train[:5]"
],
"execution_count": 132,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"3701 0\n",
"5420 0\n",
"3650 0\n",
"1151 0\n",
"2764 0\n",
"Name: spam, dtype: int64"
]
},
"metadata": {
"tags": []
},
"execution_count": 132
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VIxA3J6ukouH",
"colab_type": "text"
},
"source": [
"Now that we have the matrices, we can use sklearn to train our model using logistic regression. "
]
},
{
"cell_type": "code",
"metadata": {
"id": "rliDSg_ZkiYr",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 34
},
"outputId": "291f39da-cb7f-4ede-b2dd-ddf24c8329a2"
},
"source": [
"from sklearn.linear_model import LogisticRegression\n",
"from sklearn import metrics\n",
"\n",
"model = LogisticRegression()\n",
"model.fit(X_train, Y_train)\n",
"\n",
"training_accuracy = metrics.accuracy_score(Y_train, model.predict(X_train))\n",
"print('Training Accuracy: ', training_accuracy)"
],
"execution_count": 139,
"outputs": [
{
"output_type": "stream",
"text": [
"Training Accuracy: 0.8960909453530116\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1Y9Inp-goLCH",
"colab_type": "text"
},
"source": [
"Great! Now we know that our first model can correctly classify spam around 90% percent of the time. This is a great start, but we can do more. "
]
},
{
"cell_type": "code",
"metadata": {
"id": "9KQFj38UoSuN",
"colab_type": "code",
"colab": {}
},
"source": [
""
],
"execution_count": 0,
"outputs": []
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment