基于PSO与ABC优化朴素贝叶斯实现垃圾邮件分类遇TypeError求助
解决PSO/ABC优化朴素贝叶斯时的TypeError问题
我帮你排查了这个报错的原因,其实问题出在对Hive库的返回值理解有误,还有几个小细节需要调整,具体如下:
错误原因分析
从报错回溯能清晰看到,问题出在Utilities.ConvergencePlot(cost)这一行:
- 你把
model.run()返回的单个成本值传给了这个函数,但ConvergencePlot需要的是包含每一轮迭代中best和mean成本序列的字典,而不是单个数值/字符串。当函数尝试用cost["best"]访问字典键时,自然就触发了TypeError: string indices must be integers。 - 另外你的TF-IDF处理还有个小bug:
email_test_tf = tf.fit_transform(email_test_dtm)是错误的,这种写法会在测试集上重新拟合TF-IDF,引入数据泄露,严重影响模型的泛化能力。
解决方法与修正代码
1. 修正ConvergencePlot的输入参数
把Utilities.ConvergencePlot(cost)改成Utilities.ConvergencePlot(model.history["cost"]),因为model.history["cost"]才是Hive库记录的、包含每轮迭代best和mean成本的字典数据。
2. 修正TF-IDF的处理流程
正确的TF-IDF处理应该先在训练集上拟合,再转换训练集和测试集:
from sklearn.feature_extraction.text import TfidfVectorizer tf = TfidfVectorizer() # 先在训练集上拟合,再转换训练集 email_train_tf = tf.fit_transform(email_train) # 测试集只做转换,不拟合 email_test_tf = tf.transform(email_test)
3. 完整修正后的代码
# 数据拆分(先确保这一步是正确的) from sklearn.model_selection import train_test_split email_train, email_test, spam_train, spam_test = train_test_split(dfTotal.Email, dfTotal.Spam, test_size=0.3, random_state=0) # 修正TF-IDF处理 from sklearn.feature_extraction.text import TfidfVectorizer tf = TfidfVectorizer() email_train_tf = tf.fit_transform(email_train) email_test_tf = tf.transform(email_test) # ABC算法相关代码 from Hive import Hive from Hive import Utilities from sklearn.metrics import log_loss from sklearn.naive_bayes import MultinomialNB def run(lowBounds, upBounds, evaluator): model = Hive.BeeHive(lower=lowBounds, upper=upBounds, fun=evaluator, numb_bees=100, max_itrs=2,) # run()返回的是最优成本值和最优解数组 best_cost, sol = model.run() # 传入模型的历史成本数据,而不是单个best_cost Utilities.ConvergencePlot(model.history["cost"]) print("Fitness Value ABC: {0}".format(best_cost)) # 用最优解创建朴素贝叶斯模型 ABC_model = MultinomialNB(alpha=10**sol[0]).fit(email_train_tf, spam_train) result = ABC_model.predict(email_test_tf) return sol, result # 定义适应度函数 def evaluator(params): nBayes = MultinomialNB(alpha=10**params[0]).fit(email_train_tf, spam_train) pred_proba = nBayes.predict_proba(email_test_tf) return log_loss(spam_test, pred_proba) # 调用run函数 sol, result3 = run([-2], [1], evaluator)
额外注意事项
- 如果调整后还是有问题,可以打印
model.history查看具体的键结构,不同版本的Hive库可能略有差异。 - 确保
spam_train和spam_test是数值型标签(比如0表示正常邮件,1表示垃圾邮件),log_loss要求标签必须是数值型,否则会触发其他错误。
内容的提问来源于stack exchange,提问作者lololololol
相关产品推荐
相关产品推荐

