Exploring 5,572 real text messages
Introduction to Data Science and Machine Learning · Md Mahbub E Noor · University of Barishal
df = pd.read_csv(url, sep="\t") df["label"].value_counts()
Real SMS messages, each labeled by people as spam or ham (normal).
Published in 2011 by Almeida and Hidalgo, and shared on the UCI Machine Learning Repository.
Mostly UK and Singapore messages from around 2011. Today's scams and our local slang are not in it.
import pandas as pd loads the library, nicknamed pdread_csv reads a table from a file or web linksep="\t": columns are separated by tabsdf (DataFrame) is a table; .shape is (rows, columns)import pandas as pd
url = ("https://raw.githubusercontent.com/"
"justmarkham/pycon-2016-tutorial/"
"master/data/sms.tsv")
df = pd.read_csv(url, sep="\t", header=None,
names=["label", "message"])
print(df.shape)(5572, 2)
sms.tsv into the same folder as your notebookread_csv the file name instead of the linkdf = pd.read_csv("sms.tsv", sep="\t", header=None,
names=["label", "message"])
print(df.shape)(5572, 2)
df.head() shows the first 5 rows. Long messages are cut short with ... on screen, but the full text is still there.
print(df.head())
label message 0 ham Go until jurong point, crazy.. Available only ... 1 ham Ok lar... Joking wif u oni... 2 spam Free entry in 2 a wkly comp to win FA Cup fina... 3 ham U dun say so early hor... U c already then say... 4 ham Nah I don't think he goes to usf, he lives aro...
df["message"] selects one column.loc[2, "message"] selects row 2, column messagefull = df.loc[2, "message"] print(full) print(len(full))
Free entry in 2 a wkly comp to win FA Cup final tkts 21st May 2005. Text FA to 87121 to receive entry question(std txt rate)T&C's apply 08452810075over18's 155
value_counts() counts each labelprint(df["label"].value_counts())
.str.len() measures every message at oncedf["length"]groupby("label") splits the table by labeldf["length"] = df["message"].str.len()
avg = df.groupby("label")["length"].mean()
print(avg.round(1))WATCH FOR
Silent video: press play, pause any time.
duplicated() marks rows seen beforeprint(df.duplicated().sum()) df = df.drop_duplicates() print(df.shape) print(df["label"].value_counts())
403 (5169, 3) label ham 4516 spam 653 Name: count, dtype: int64
str.contains("free") checks every message at oncetext = df["message"].str.lower()
df["has_free"] = text.str.contains("free")
share = df.groupby("label")["has_free"].mean()
print(share.round(3))label ham 0.014 spam 0.259 Name: has_free, dtype: float64
.sample(3)word = "call"
df["has_word"] = text.str.contains(word)
print(df.groupby("label")["has_word"].mean())
spam = df[df["label"] == "spam"]
print(spam["message"].sample(3))Read the last line of an error first. It names the problem.
| What you typed | What Python says | What it means |
|---|---|---|
print(df["Label"]) | KeyError: 'Label' | Column names are case-sensitive. The column is "label". |
print(df.lenght) | AttributeError: 'DataFrame' object has no attribute 'lenght' | Typo in a name. Check spelling, or print(df.columns). |
print(df["message"].lower()) | AttributeError: 'Series' object has no attribute 'lower' | A column is not a single string. Use .str.lower() for text columns. |
In the lab you can
Opens in a new tab and works offline. All labs: labs/START_HERE.html
import pandas as pd | Load the pandas library |
pd.read_csv(url) | Read a table from a file or link |
df.shape, df.head() | Size, and a first look |
df["col"] | Select one column |
df.loc[row, "col"] | Select a single cell |
value_counts() | Count each value |
df["new"] = ... | Add a column |
df.groupby("label") | Split by label to compare groups |
drop_duplicates() | Remove repeated rows |
df[df["label"]=="spam"] | Keep only matching rows |
Due before Lecture 6 · [date]
In a new notebook, load the dataset, print its shape, and count the labels.
Print 5 spam messages with spam["message"].sample(5, random_state=<your roll number>). List 3 patterns you notice.
Test 3 words of your choice. For each, print the share of spam and ham containing it. Which is the best clue, and why?
Plot average length by label with .plot(kind="bar", title="..."). Give it a clear title.
A model always predicts "ham". What is its accuracy after removing duplicates? Why would it still be useless?
Watch it again at home to revise.