Skip to content
135 changes: 113 additions & 22 deletions chapter1/spam-fighting-blacklist.ipynb
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## В этом коде используется черный список (Blacklist) для борьбы со спамом в электронной почте"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import pickle\n",
"import email_read_util"
"# Импорт необходимых модулей\n",
"import os # Модуль для работы с операционной системой\n",
"import pickle # Модуль для сериализации и десериализации объектов Python\n",
"import email_read_util # Модуль для чтения и обработки электронных писем"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Download 2007 TREC Public Spam Corpus\n",
"1. Read the \"Agreement for use\"\n",
"### Скачайте общедоступный корпус спама TREC 2007 года выпуска\n",
"1. Прочитайте \"Соглашение об использовании\"\n",
" https://plg.uwaterloo.ca/~gvcormac/treccorpus07/\n",
"\n",
"2. Download 255 MB Corpus (trec07p.tgz) and untar into the 'chapter1/datasets' directory\n",
"2. Загрузите корпус объемом 255 МБ (trec07p.tgz) и распакуйте в каталог \"глава 1/наборы данных\"\n",
"\n",
"3. Check that the below paths for 'DATA_DIR' and 'LABELS_FILE' exist"
"3. Убедитесь, что указанные ниже пути для \"DATA_DIR\" и \"LABELS_FILE\" существуют"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Загрузка данных:\n",
"### Данные загружаются из каталога datasets/trec07p/data/. Также загружаются метки классов (спам/не спам) из файла datasets/trec07p/full/index. Черный список содержит известные серверы, распространяющие спам, и блокирует письма с таких серверов."
]
},
{
Expand All @@ -30,9 +46,10 @@
"metadata": {},
"outputs": [],
"source": [
"DATA_DIR = 'datasets/trec07p/data/'\n",
"LABELS_FILE = 'datasets/trec07p/full/index'\n",
"TRAINING_SET_RATIO = 0.7"
"# Определение директории с данными и файла с метками\n",
"DATA_DIR = 'datasets/trec07p/data/' # Путь к директории с данными\n",
"LABELS_FILE = 'datasets/trec07p/full/index' # Путь к файлу с метками\n",
"TRAINING_SET_RATIO = 0.7 # Пропорция разделения набора данных на тренировочный и тестовый"
]
},
{
Expand All @@ -41,9 +58,10 @@
"metadata": {},
"outputs": [],
"source": [
"labels = {}\n",
"spam_words = set()\n",
"ham_words = set()"
"# Инициализация пустых структур данных\n",
"labels = {} # Словарь для хранения меток (имя файла: метка)\n",
"spam_words = set() # Множество слов, характерных для спама\n",
"ham_words = set() # Множество слов, характерных для нормальной корреспонденции"
]
},
{
Expand All @@ -52,7 +70,12 @@
"metadata": {},
"outputs": [],
"source": [
"# Read the labels\n",
"# Чтение и обработка файла меток\n",
"with open(LABELS_FILE) as f:\n",
" for line in f:\n",
" line = line.strip()\n",
" label, key = line.split()\n",
" labels[key.split('/')[-1]] = 1 if label.lower() == 'ham' else 0# Чтение и обработка файла меток\n",
"with open(LABELS_FILE) as f:\n",
" for line in f:\n",
" line = line.strip()\n",
Expand All @@ -66,12 +89,28 @@
"metadata": {},
"outputs": [],
"source": [
"# Split corpus into train and test sets\n",
"# Разделение корпуса на тренировочный и тестовый наборы\n",
"filelist = os.listdir(DATA_DIR)\n",
"X_train = filelist[:int(len(filelist)*TRAINING_SET_RATIO)]\n",
"X_test = filelist[int(len(filelist)*TRAINING_SET_RATIO):]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Код загружает данные о транзакциях с кредитными картами и обучает модель на основе черного списка"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Построение/загрузка \"черного списка\":\n",
"### Черный список содержит слова, которые характерны для спам-сообщений и не характерны для нормальных писем.\n",
"### Если файл blacklist.pkl уже существует, черный список загружается из него. В противном случае он строится на основе данных обучающего набора и сохраняется для последующего использования."
]
},
{
"cell_type": "code",
"execution_count": 6,
Expand All @@ -86,6 +125,7 @@
}
],
"source": [
"# Построение или загрузка списка слов-маркеров для спама (blacklist)\n",
"if not os.path.exists('blacklist.pkl'):\n",
" for filename in X_train:\n",
" path = os.path.join(DATA_DIR, filename)\n",
Expand All @@ -105,13 +145,16 @@
"else:\n",
" blacklist = pickle.load(open('blacklist.pkl', 'rb') )\n",
"\n",
" # Печать сообщения о построении или загрузке blacklist\n",
"print('Blacklist of {} tokens successfully built/loaded'.format(len(blacklist)))"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
Expand Down Expand Up @@ -1125,22 +1168,36 @@
}
],
"source": [
"# Импорт модуля NLTK для работы с естественным языком\n",
"from nltk.corpus import words\n",
"word_set = set(words.words())\n",
"# Поиск пересечения blacklist и множества английских слов из NLTK\n",
"word_set.intersection(blacklist)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Анализ текста:\n",
"### Для каждого электронного письма из тестового набора:\n",
"### Текст сообщения анализируется на наличие слов из черного списка. Подсчитывается количество ложноположительных (FP), ложноотрицательных (FN), истинноположительных (TP) и истинноотрицательных (TN) результатов."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"fp = 0\n",
"tp = 0\n",
"fn = 0\n",
"tn = 0\n",
"# Инициализация переменных для подсчета статистики классификации\n",
"fp = 0 # Ложноположительные (ошибочно определенные как спам)\n",
"tp = 0 # Истинноположительные (правильно определенные как спам)\n",
"fn = 0 # Ложноотрицательные (ошибочно определенные как не спам)\n",
"tn = 0 # Истинноотрицательные (правильно определенные как не спам)\n",
"\n",
"\n",
"# Проверка каждого письма из тестового набора и классификация по наличию слов из blacklist\n",
"for filename in X_test:\n",
" path = os.path.join(DATA_DIR, filename)\n",
" if filename in labels:\n",
Expand All @@ -1161,6 +1218,14 @@
" fn = fn + 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Визуализация:\n",
"### Строится матрица ошибок для оценки результатов классификации. Выводится процентное соотношение каждой ячейки матрицы ошибок относительно общего количества наблюдений."
]
},
{
"cell_type": "code",
"execution_count": 9,
Expand All @@ -1180,6 +1245,7 @@
}
],
"source": [
"# Вывод матрицы ошибок в HTML-таблице\n",
"from IPython.display import HTML, display\n",
"conf_matrix = [[tn, fp],\n",
" [fn, tp]]\n",
Expand Down Expand Up @@ -1208,6 +1274,7 @@
}
],
"source": [
"# Вывод процентной матрицы ошибок в HTML-таблице\n",
"count = tn + tp + fn + fp\n",
"percent_matrix = [[\"{:.1%}\".format(tn/count), \"{:.1%}\".format(fp/count)],\n",
" [\"{:.1%}\".format(fn/count), \"{:.1%}\".format(tp/count)]]\n",
Expand All @@ -1217,6 +1284,15 @@
" for row in percent_matrix))))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Оценка точности классификации:\n",
"### Вычисляется и выводится процент точности классификации, основанный на количестве правильно классифицированных объектов.\n",
"### Результаты показывают, что классификация имеет точность около 68.6%."
]
},
{
"cell_type": "code",
"execution_count": 11,
Expand All @@ -1231,13 +1307,28 @@
}
],
"source": [
"# Вывод процента правильно классифицированных писем\n",
"print(\"Classification accuracy: {}\".format(\"{:.1%}\".format((tp+tn)/count)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Этот метод - один из старейших способов фильтрации спама."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -1251,7 +1342,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.3"
"version": "3.10.9"
}
},
"nbformat": 4,
Expand Down
Loading