AI开发:逻辑回归 - 实战演练- 垃圾邮件的识别(一)
逻辑回归的概念和演示
逻辑回归(Logistic Regression)最常用于二分类问题,即目标变量(标签)只有两个类别的场景。它通过拟合一个S形的Sigmoid函数来预测一个事件发生的概率,输出值在0到1之间,可以将其划分为两个类别。
常见场景
- 垃圾邮件分类:根据邮件内容预测邮件是否是垃圾邮件。
- 疾病预测:根据某些特征(如年龄、血压等)预测某人是否患有某种疾病。
- 客户流失预测:根据用户的行为数据,预测用户是否会流失。
示例:垃圾邮件分类
假设我们有一个简单的数据集,包含邮件的一些特征(例如:单词频率),并且我们想要预测邮件是否是垃圾邮件(1为垃圾邮件,0为正常邮件)。下面是一个简单的Python代码示例,使用逻辑回归来解决这个问题。
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix
# 假设这是我们的数据集,包含两个特征和一个标签
data = {
'word_freq_discount': [0.1, 0.4, 0.2, 0.7, 0.3],
'word_freq_free': [0.3, 0.1, 0.6, 0.8, 0.5],
'label': [0, 1, 0, 1, 0] # 0 - 正常邮件, 1 - 垃圾邮件
}
# 创建DataFrame
df = pd.DataFrame(data)
# 特征和标签
X = df[['word_freq_discount', 'word_freq_free']] # 特征
y = df['label'] # 标签
# 将数据拆分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 特征标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 创建并训练逻辑回归模型
model = LogisticRegression()
model.fit(X_train_scaled, y_train)
# 预测
y_pred = model.predict(X_test_scaled)
# 评估模型
accuracy = accuracy_score(y_test, y_pred)
conf_matrix = confusion_matrix(y_test, y_pred)
print("准确率:", accuracy)
print("混淆矩阵:\n", conf_matrix)
代码解释:
- 数据集准备:创建一个简单的数据集,其中包含两个特征(
word_freq_discount
,word_freq_free
)和标签(label
),label
为0或1,表示邮件是否为垃圾邮件。 - 数据分割:使用
train_test_split
将数据集分割为训练集和测试集。 - 特征标准化:使用
StandardScaler
对特征进行标准化,保证数据在相同的尺度下。 - 模型训练:使用
LogisticRegression
训练逻辑回归模型。 - 预测和评估:通过预测并计算准确率以及混淆矩阵评估模型的性能。
输出:
准确率: 1.0
混淆矩阵:
[[1 0]
[0 1]]
在这个简单的例子中,逻辑回归模型成功地对邮件进行分类,将垃圾邮件(1)和正常邮件(0)准确地分开了。
关于数据集的解释:
这个特征数据集 data
是一个简单的表格,表示了邮件中某些关键词出现的频率以及相应的标签(垃圾邮件或正常邮件)。具体来说,数据集包含以下内容:
1. 'word_freq_discount'
这是一个特征,表示邮件中包含“discount”一词的频率。值越高,表示邮件中提到“discount”这个词的频率越高。这个特征可能用于判断邮件是否涉及促销、优惠等内容,通常这些词汇在垃圾邮件中出现的频率较高。
- 例如,
0.1
表示该邮件中“discount”一词出现的频率是 10%,0.7
表示频率是 70%。
2. 'word_freq_free'
这是另一个特征,表示邮件中包含“free”一词的频率。与“discount”类似,这个特征反映了邮件中“free”一词的出现频率。许多垃圾邮件中都会包含类似“free”这样的词汇,以吸引用户点击或打开邮件。
- 例如,
0.3
表示该邮件中“free”一词出现的频率是 30%,0.8
表示频率是 80%。
3. 'label'
这是目标变量,表示每封邮件是否为垃圾邮件。标签为:
0
表示正常邮件(非垃圾邮件)1
表示垃圾邮件
数据集的具体内容:
data = {
'word_freq_discount': [0.1, 0.4, 0.2, 0.7, 0.3], # 频率: 邮件中 "discount" 的出现频率
'word_freq_free': [0.3, 0.1, 0.6, 0.8, 0.5], # 频率: 邮件中 "free" 的出现频率
'label': [0, 1, 0, 1, 0] # 标签: 0 表示正常邮件, 1 表示垃圾邮件
}
具体解释:
-
第一封邮件:
word_freq_discount
: 0.1(表示邮件中“discount”出现的频率为10%)word_freq_free
: 0.3(表示邮件中“free”出现的频率为30%)label
: 0(表示这是一封正常邮件)
-
第二封邮件:
word_freq_discount
: 0.4(表示邮件中“discount”出现的频率为40%)word_freq_free
: 0.1(表示邮件中“free”出现的频率为10%)label
: 1(表示这是一封垃圾邮件)
-
第三封邮件:
word_freq_discount
: 0.2(表示邮件中“discount”出现的频率为20%)word_freq_free
: 0.6(表示邮件中“free”出现的频率为60%)label
: 0(表示这是一封正常邮件)
-
第四封邮件:
word_freq_discount
: 0.7(表示邮件中“discount”出现的频率为70%)word_freq_free
: 0.8(表示邮件中“free”出现的频率为80%)label
: 1(表示这是一封垃圾邮件)
-
第五封邮件:
word_freq_discount
: 0.3(表示邮件中“discount”出现的频率为30%)word_freq_free
: 0.5(表示邮件中“free”出现的频率为50%)label
: 0(表示这是一封正常邮件)
解释:
- "discount" 和 "free" 是两个常见的在垃圾邮件中出现的关键词。通常,垃圾邮件中会频繁使用这些词汇,尤其是当邮件内容涉及促销、免费赠品或优惠时。因此,这两个特征的频率对于区分垃圾邮件和正常邮件至关重要。
- 标签 (
label
):0
代表正常邮件,1
代表垃圾邮件。通过训练逻辑回归模型,我们可以学习到当“discount”和“free”出现在邮件中时,垃圾邮件的可能性增加。
因此,这个数据集可以用来训练一个逻辑回归模型,学习如何根据邮件中“discount”和“free”这两个词的频率来预测邮件是否是垃圾邮件。
数据集的搜集和使用
在实际项目中开发反垃圾邮件应用时,数据集的来源可以有多种途径,主要依赖于应用的需求、资源和数据获取的渠道。以下是一些常见的途径,您可以通过这些途径获得或创建反垃圾邮件模型所需的训练数据集。
1. 公开数据集
许多研究者和公司会共享他们收集的垃圾邮件数据集,供其他开发者或研究者使用。常见的公开垃圾邮件数据集包括:
- Enron Spam Dataset:这是一个常见的邮件数据集,包含了来自Enron公司的邮件数据,并标记了垃圾邮件和正常邮件。
- SpamAssassin Dataset:SpamAssassin项目提供了一个公开的垃圾邮件数据集,包含了大量的垃圾邮件和正常邮件,适用于邮件过滤器的训练。
- Ling-Spam Dataset:这个数据集包含了来自LINGUAMAIL邮件列表的邮件,适用于垃圾邮件分类任务。
- TREC Public Spam Corpus:由TREC提供,包含了大量的邮件数据,可以用于垃圾邮件检测的研究。
- Kaggle数据集:Kaggle上有一些关于垃圾邮件分类的公开竞赛和数据集,您可以直接下载并使用。
这些公开数据集的特点是已经标注了垃圾邮件和正常邮件,适合用来训练和评估反垃圾邮件模型。
2. 企业自有数据
对于商业应用,尤其是针对特定客户的反垃圾邮件应用,企业往往会依赖自己收集的邮件数据。这些数据可能来自于:
- 客户邮件系统的日志:企业可以访问客户邮件服务器(如Exchange、Gmail、Outlook等)的邮件日志。通过分析这些日志,可以标注哪些邮件是垃圾邮件,哪些是正常邮件。
- 用户举报的垃圾邮件:用户可以手动标记自己收到的垃圾邮件,企业可以通过收集这些用户反馈来建立垃圾邮件的训练数据集。这个方法的优点是数据集能够反映实际用户的需求和使用场景。
- 邮件内容分析:公司可以分析邮件的内容、附件和元数据(如发件人、主题、发送时间等),并结合垃圾邮件的规则来标记数据。
3. 爬虫抓取
对于没有现成标注数据的情况,开发者也可以通过爬虫抓取公共的邮件内容,并使用各种技术手段进行垃圾邮件的标注:
- 抓取公共论坛或邮件列表:很多公共邮件列表(如邮件讨论组、新闻组等)会包含大量邮件,可以从中提取垃圾邮件和正常邮件。通过分析这些邮件的特点,开发者可以为数据集添加标签。
- 使用网络爬虫抓取网页数据:通过爬取网站的评论区、论坛帖子等,也可以收集到垃圾邮件的相关数据,尤其是带有垃圾链接或广告的内容。
4. 通过合成数据集生成
当现有数据集不足以支持反垃圾邮件应用的开发时,可以通过合成数据集来生成训练数据。生成合成数据的一种常见方法是:
- 通过正则表达式或规则生成垃圾邮件:根据垃圾邮件的特征(如大量广告链接、关键词“免费”等)编写规则或脚本,自动生成垃圾邮件样本。这些合成数据可以用于扩充数据集,但在实际应用中,合成数据的质量可能无法与真实数据完全匹配。
- 通过模拟用户行为:使用模拟器模拟用户的邮件交互行为,生成反映用户实际行为的垃圾邮件和正常邮件。
5. 第三方反垃圾邮件数据提供商
一些专门从事垃圾邮件检测和防御的公司,会提供经过清洗和标注的数据集,这些数据集经过严格审核,具有较高的质量。这些数据集一般需要付费,但由于它们经过处理,可以节省大量的标注时间和成本。
数据标签(标签的来源)
标记垃圾邮件和正常邮件通常有两种方法:
- 人工标注:通过人工检查邮件内容,手动标注邮件为垃圾邮件或正常邮件。虽然精确度高,但这种方法成本较高,且对于大量数据可能不适用。
- 用户反馈:通过收集和分析用户的反馈(例如用户标记邮件为垃圾邮件),可以自动标注数据集中的邮件。
6. 数据增强
如果数据量不足,可以通过数据增强技术(如文本生成模型、同义词替换、邮件内容修改等)来扩展数据集。例如,利用深度学习模型(如GPT、BERT等)生成一些垃圾邮件内容,或者使用现有邮件数据进行一定的扰动(如随机修改一些单词或邮件主题),从而创造更多样化的训练数据。
实战演练
现在实战演练一下。假设接到一个任务,要开发一个对自己公司邮件进行分类的插件,已经存在有两个文件夹,文件夹 A 放了一些文本文件, 是垃圾邮件。B文件夹放了一些文本文件,是正常邮件。根据这两个文件夹的内容作为基准来判断新邮件是否垃圾邮件。
思路:对两个文件夹中的文件提取特征,动态生成一个数据集,然后以这个数据集来判断一段文本是否是垃圾邮件。
为了实现对公司邮件进行垃圾邮件分类的插件,首先,我们需要进行以下几个步骤:
- 分析 A 文件夹(垃圾邮件)和 B 文件夹(正常邮件)中的文本文件,生成特征数据集
data
。 - 基于 A 和 B 文件夹中的文本文件,提取关键词和特征,构建模型(比如使用逻辑回归)。
- 接收新的文本文件,根据
data
生成的模型进行预测,判断它是否是垃圾邮件。
我们可以分步完成这些任务:
步骤 1:读取文件并处理数据
首先,我们将 A 文件夹和 B 文件夹中的文本文件读入,并根据文件内容生成特征数据集 data
。我们将使用 TfidfVectorizer
来提取关键词。
步骤 2:使用机器学习算法训练模型
我们可以使用 逻辑回归 或 支持向量机(SVM) 来训练模型,使用文件中的文本数据来学习垃圾邮件和正常邮件的区别。
步骤 3:预测新的邮件是否是垃圾邮件
对于新的邮件,我们会根据模型判断它是否是垃圾邮件。
初次代码:
首先,我们需要进行以下几个步骤:
- 分析 A 文件夹(垃圾邮件)和 B 文件夹(正常邮件)中的文本文件,生成特征数据集
data
。 - 基于 A 和 B 文件夹中的文本文件,提取关键词和特征,构建模型(比如使用逻辑回归)。
- 接收新的文本文件,根据
data
生成的模型进行预测,判断它是否是垃圾邮件。
我们可以分步完成这些任务:
步骤 1:读取文件并处理数据
首先,我们将 A 文件夹和 B 文件夹中的文本文件读入,并根据文件内容生成特征数据集 data
。我们将使用 TfidfVectorizer
来提取关键词。
步骤 2:使用机器学习算法训练模型
我们可以使用 逻辑回归 或 支持向量机(SVM) 来训练模型,使用文件中的文本数据来学习垃圾邮件和正常邮件的区别。
步骤 3:预测新的邮件是否是垃圾邮件
对于新的邮件,我们会根据模型判断它是否是垃圾邮件。
Python代码实现
以下是代码示例,展示如何完成上述任务。
import os
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
import numpy as np
# 步骤 1:读取 A 文件夹和 B 文件夹中的文本文件
def read_files(folder_path):
texts = []
for filename in os.listdir(folder_path):
with open(os.path.join(folder_path, filename), 'r', encoding='utf-8') as file:
texts.append(file.read())
return texts
# 假设 A 文件夹为垃圾邮件文件夹,B 文件夹为正常邮件文件夹
folder_A = "path_to_folder_A" # 垃圾邮件文件夹路径
folder_B = "path_to_folder_B" # 正常邮件文件夹路径
# 读取文件内容
spam_texts = read_files(folder_A)
ham_texts = read_files(folder_B)
# 步骤 2:生成数据集 data
# 标签:垃圾邮件标记为 1,正常邮件标记为 0
texts = spam_texts + ham_texts
labels = [1] * len(spam_texts) + [0] * len(ham_texts)
# 使用 TfidfVectorizer 转换文本数据为特征
vectorizer = TfidfVectorizer(stop_words='english')
X = vectorizer.fit_transform(texts)
# 步骤 3:训练模型
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, labels, test_size=0.3, random_state=42)
# 使用逻辑回归模型训练
model = LogisticRegression()
model.fit(X_train, y_train)
# 测试模型效果
accuracy = model.score(X_test, y_test)
print(f"Model Accuracy: {accuracy:.4f}")
# 步骤 4:判定新的邮件是否是垃圾邮件
def predict_spam_or_ham(new_email_text):
new_email_vec = vectorizer.transform([new_email_text])
prediction = model.predict(new_email_vec)
if prediction == 1:
return "垃圾邮件"
else:
return "正常邮件"
# 示例:输入一个新的邮件文本进行预测
new_email = "Congratulations! You've won a free vacation. Claim now!"
result = predict_spam_or_ham(new_email)
print(f"新邮件预测结果: {result}")
代码解释:
-
读取文件夹中的文本文件:
read_files()
函数会读取指定文件夹中的所有文本文件,并将其内容作为列表返回。
-
特征提取:
- 使用
TfidfVectorizer
将邮件内容转化为 TF-IDF 特征。TF-IDF 是常用的文本特征提取方法,能够衡量每个词在邮件中的重要性。
- 使用
-
训练机器学习模型:
- 使用逻辑回归(
LogisticRegression
)作为分类器,训练模型来区分垃圾邮件(标签为 1)和正常邮件(标签为 0)。 - 通过
train_test_split
划分数据集,确保模型的训练和评估是独立的。 - 模型训练完成后,使用测试集评估模型的准确度。
- 使用逻辑回归(
-
预测新的邮件:
- 给定一个新的邮件文本,我们会将其转化为 TF-IDF 特征,然后通过训练好的模型进行预测。如果预测结果是 1,则表示是垃圾邮件;如果是 0,则表示是正常邮件。
测试:
- 你可以在文件夹
A
和B
中放入实际的垃圾邮件和正常邮件文本文件。然后,代码会读取这些文件并生成data
,以便训练模型。 - 输入一个新的邮件文本,程序会判断它是否是垃圾邮件。
注意:
- 本代码中的路径
path_to_folder_A
和path_to_folder_B
需要替换为实际的文件夹路径。 - 邮件文本文件应该是纯文本格式,并且每封邮件应该保存在一个单独的文件中。
这样,通过这个简单的插件,我们可以实现基于文本内容的垃圾邮件分类。
来一段插曲:
为了能看清楚data的结构,我们需要做一些额外的动作:
在前面的代码中,data
的概念体现在以下几个部分:
-
texts
和labels
:
它们是原始的文本数据和对应的标签。texts
是所有邮件的内容。labels
是每封邮件的类别(1 表示垃圾邮件,0 表示正常邮件)。
-
X
和y
:
它们是基于texts
和labels
提取的特征和目标标签:X
是通过TfidfVectorizer
提取的特征向量(TF-IDF)。y
是对应的目标标签,和labels
一致。
可以理解为:
X
+y
相当于你的data
数据集。X
是特征部分,y
是标签部分。
如果需要以 data
的形式显式表示,代码可以做一些调整:
# 将特征和标签组合成一个类似的 data 结构
import pandas as pd
# 获取特征的关键词列表
feature_names = vectorizer.get_feature_names_out()
# 转化为 Pandas DataFrame 格式
data_df = pd.DataFrame(X.toarray(), columns=feature_names)
data_df['label'] = labels # 添加标签列
# 打印 data
print(data_df)
输出的 data_df
示例
我们提取到的关键词有 ["free", "win", "vacation"]
,数据会如下显示:
free | win | vacation | label |
---|---|---|---|
0.5 | 0.0 | 0.1 | 1 |
0.0 | 0.2 | 0.3 | 0 |
0.6 | 0.1 | 0.0 | 1 |
... | ... | ... | ... |
这个 data_df
就是完整的特征数据集(data
),可以用来训练模型。
但是实际经过测试后,发现这个应用对任何文字都会定义为“垃圾邮件” 。
这不是我们想要的结果,我们需要对处理逻辑加以优化。
待续。。。(模拟邮件的文件资源包请下载附件)