大力力力力力力力力出奇迹 2024-06-09 13:08 采纳率: 33.3%
浏览 2

关于#机器学习#的问题:目的是对待分类邮件进行预测


import os
import re
import string
import math
import numpy as np
from collections import defaultdict
from sklearn.model_selection import train_test_split

DATA_DIR = r'C:\Users\***\Desktop\team7'  # 数据集地址
target_names = ['ham', 'spam']  # 正常、垃圾
stopwords = set(open('stopwords.txt', 'r').read().splitlines())  # 加载停用词


def get_data(DATA_DIR):
    # 假设“未分类邮件”是包含所有邮件的文件夹
    mail_folder = '待分类邮件'
    data = []
    target = []
    # 获取“未分类邮件”文件夹中的所有文件
    all_files = os.listdir(os.path.join(DATA_DIR, mail_folder))
    for mail_file in all_files:
        # 通过文件夹名称判断邮件类型
        if 'spam' in mail_file:
            label = 1  # 垃圾邮件标签为1
        else:
            label = 0  # 正常邮件标签为0

        # 打开邮件文件
        with open(os.path.join(DATA_DIR, mail_folder, mail_file), encoding="latin-1") as f:
            data.append(f.read())
            target.append(label)

    return data, target


def preprocess(text):
    text = text.lower()  # 转换为小写
    text = re.sub(f'[{string.punctuation}]', ' ', text)  # 去除标点符号
    text = [word for word in text.split() if word not in stopwords]  # 去除停用词
    return text


class NaiveBayesClassifier():
    def __init__(self):
        self.vocabulary = set()  # 词汇表
        self.class_total = defaultdict(int)  # 每个类别的文档数
        self.word_total = defaultdict(int)  # 每个类别中所有单词出现次数之和
        self.word_given_class = defaultdict(lambda: defaultdict(int))  # 每个类别中每个单词出现次数

    def fit(self, X, y):
        for text, label in zip(X, y):
            words = preprocess(text)
            self.class_total[label] += 1
            for word in words:
                self.vocabulary.add(word)
                self.word_given_class[label][word] += 1
                self.word_total[label] += 1

    def predict(self, X):
        log_priors = {}
        for c in self.class_total.keys():
            log_priors[c] = math.log(self.class_total[c] / sum(self.class_total.values()))
            predictions = []
        for text in X:
            words = preprocess(text)
            log_probs = {}
        for c in self.class_total.keys():
            log_probs[c] = log_priors[c]
        for word in words:
            # 对未见过的单词进行平滑处理
            log_probs[c] += math.log((self.word_given_class[c][word] + 1) / (self.word_total[c] + len(self.vocabulary)))
            predictions.append(max(log_probs, key=log_probs.get))
        return predictions


# 加载数据集
X, y = get_data(DATA_DIR)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建实例并训练模型
clf = NaiveBayesClassifier()
clf.fit(X_train, y_train)

# 对新邮件进行分类
new_email = 'Subject: et & s photo contest - announcing the winners\nCongratulations to the following winners of the 2001 ET & S photo contest. Over 200 entries were submitted! The winning photos will be displayed in the 2001 ET & S public education calendar.'
prediction = clf.predict([new_email])[0]

# 在测试集上进行预测并计算准确率
predictions = clf.predict(X_test)
accuracy = np.sum(np.array(predictions) == np.array(y_test)) / len(y_test)
# 创建一个列表来存储每封邮件的预测结果
predicted_emails = []

# 遍历每封测试邮件,并将预测结果添加到列表中
for i, prediction_index in enumerate(predictions):
    predicted_emails.append((i + 1, target_names[prediction_index]))

# 打印预测结果
for email_no, prediction in predicted_emails:
    print(f'Email {email_no}: Prediction: {prediction}')

print(f'Prediction for new email: {target_names[prediction]}')
print(f'Accuracy: {accuracy:.2f}')

目的是对待分类邮件进行预测,2000封只运行出来500多封,运行结果出来还全是正常邮件,并且还报错。请问代码哪里出错了?

img

  • 写回答

2条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-06-09 13:08
    关注

    引自免费微信小程序:皆我百晓生

    看起来您的代码有一些错误和缺失的部分。让我们逐步解决它们。

    首先,让我们修复accuracy计算部分的警告。这是由于Python在比较数组时发出的警告,因为这在未来可能会引发错误。我们可以简单地使用NumPy的equal函数替换等于运算符,如下所示:

    accuracy = np.mean(np.equal(np.array(predictions), np.array(y_test)))
    

    接下来,我们解决TypeError。当您尝试访问target_names列表时,使用了字符串作为索引,但列表索引应为整数。这是因为prediction是一个整数(0 或 1),而不是字符串。要解决这个问题,请修改打印预测结果的部分,如下所示:

    print(f'Prediction for new email: {target_names[int(prediction)]}')
    

    现在,让我们检查一下为什么只有500多封邮件被处理。这可能是由于您的数据集中只有这么多训练样本。为了确保正确处理所有数据,我们需要确保get_data()函数正确读取了所有的邮件文件。在all_files变量中,您可以尝试打印文件名,确认是否包含了所有预期的文件:

    for mail_file in all_files:
        print(mail_file)
    

    如果文件数量不足,您可能需要检查数据集结构或文件命名规则是否与代码中的逻辑匹配。另外,确保在运行代码之前,您的数据集路径指向正确的文件夹位置。

    最后,关于预测结果都是正常邮件的问题,这可能是因为训练数据不平衡,即正常邮件的数量远大于垃圾邮件。在这种情况下,朴素贝叶斯分类器更倾向于预测大多数类别的标签,也就是正常邮件。要改善这种情况,可以考虑对数据进行重新采样(例如,过采样少数类或欠采样多数类),或者调整模型参数。此外,评估模型性能时,除了准确性外,还可以查看混淆矩阵、召回率和F1分数等指标,以便更好地理解模型的表现。

    以下是修复后的代码:

    # ... (其他代码保持不变)
    
    # 打印所有邮件文件名,以确认是否都已加载
    for mail_file in all_files:
        print(mail_file)
    
    # 计算准确率,修复警告
    accuracy = np.mean(np.equal(np.array(predictions), np.array(y_test)))
    
    # 打印预测结果,修复TypeError
    print(f'Prediction for new email: {target_names[int(prediction)]}')
    
    print(f'Accuracy: {accuracy:.2f}')
    

    运行这段代码后,您可以观察输出以了解问题所在。如果仍然存在问题,请提供有关数据集结构和文件数量的更多信息,以便进一步分析。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 6月9日

悬赏问题

  • ¥15 FileNotFoundError 解决方案
  • ¥15 uniapp实现如下图的图表功能
  • ¥15 u-subsection如何修改相邻两个节点样式
  • ¥30 vs2010开发 WFP(windows filtering platform)
  • ¥15 服务端控制goose报文控制块的发布问题
  • ¥15 学习指导与未来导向啊
  • ¥15 求多普勒频移瞬时表达式
  • ¥15 如果要做一个老年人平板有哪些需求
  • ¥15 k8s生产配置推荐配置及部署方案
  • ¥15 matlab提取运动物体的坐标