如何改进朴素贝叶斯算法的结果?

数据挖掘 机器学习 Python 监督学习 朴素贝叶斯分类器 朴素贝叶斯算法
2022-02-19 10:01:59

我在改善运行朴素贝叶斯算法的结果方面遇到了一些困难。我的数据集由 39 列组成(一些是分类的,一些是数字的)。然而,我只考虑了主要变量,即文本,它包含所有的垃圾邮件和非垃圾邮件。

既然是垃圾邮件过滤,我觉得这个字段可以不错。因此,我在删除停用词后使用了 countvectorizer 并使用它们进行拟合变换。

我得到了 60% 的准确率,非常低!你认为什么可能导致这个低结果?有什么我可以做的来改进它吗?

这些是我正在考虑的 39 列中的列:

Index(['Date', 'Username', 'Subject', 'Target',  'Country', 'Website','Text', 'Capital', 'Punctuation'],
      dtype='object')

Date是日期格式 (eg 2018-02-06) Username是字符串 (eg Math) Subject是字符串 (eg I need your help) Target是二进制变量 ( 1-spam 或 -not 0spam) Country是字符串 (eg US) Website是字符串 (eg www.viagra.com) Text是电子邮件的语料库和它是一个字符串 (eg I need your HELP!!) Capital是一个字符串 (eg HELP) Punctuation是字符串 ( !!)

我所做的如下:

  • 删除文本中的停用词:

    def clean_text(文本):

      lim_pun = [char for char in string.punctuation if char in "&#^_"]
      nopunc = [char for char in text if char not in lim_pun]
    
      nopunc = ''.join(nopunc)
    
      other_stop=['•','...in','...the','...you\'ve','–','—','-','⋆','...','C.','c','|','...The','...The','...When','...A','C','+','1','2','3','4','5','6','7','8','9','10', '2016',  'speak','also', 'seen','[5].',  'using', 'get',  'instead',  "that's",  '......','may', 'e', '...it', 'puts', '...over', '[✯]','happens', "they're",'hwo',  '...a', 'called',  '50s','c;', '20',  'per', 'however,','it,', 'yet', 'one', 'bs,', 'ms,', 'sr.',  '...taking',  'may', '...of', 'course,', 'get', 'likely', 'no,']
    
      ext_stopwords=stopwords.words('english')+other_stop
    
      clean_words = [word for word in nopunc.split() if word.lower() not in ext_stopwords]
      return clean_words
    

然后将这些更改应用于我的数据集:

from sklearn.feature_extraction.text import CountVectorizer
import string
from nltk.corpus import stopwords

df=df.dropna(subset=['Subject', 'Text']) 
df['Corpus']=df['Subject']+df['Text']
mex = CountVectorizer(analyzer=clean_text).fit_transform(df['Corpus'].str.lower())

并将我的数据集拆分为训练和测试:

X_train, X_test, y_train, y_test = train_test_split(mex, df['Target'], test_size = 0.80, random_state = 0)

df包括 1110 封电子邮件和 322 封垃圾邮件。

然后我考虑我的分类器:

# Multinomial Naive Bayes 

from sklearn.naive_bayes import MultinomialNB

classifier = MultinomialNB()
classifier.fit(X_train, y_train)

print(classifier.predict(X_train))

print(y_train.values)

# Train data set

    from sklearn.metrics import classification_report,confusion_matrix, accuracy_score
    from sklearn.metrics import accuracy_score
    
    pred = classifier.predict(X_train)
    
    print(classification_report(y_train ,pred ))
    print('Confusion Matrix: \n',confusion_matrix(y_train,pred))
    print()
    
    print("MNB Accuracy Score -> ",accuracy_score(y_train, pred)*100)
    
    print('Predicted value: ',classifier.predict(X_test))
    
    print('Actual value: ',y_test.values)

并在测试集上评估模型:

from sklearn.metrics import classification_report,confusion_matrix, accuracy_score

pred = classifier.predict(X_test)

print(classification_report(y_test ,pred ))
print('Confusion Matrix: \n', confusion_matrix(y_test,pred))
print()
print("MNB Accuracy Score -> ",accuracy_score(y_test, pred)*100)

得到大约 60%,这一点都不好。输出:

  precision    recall  f1-score   support

         0.0       0.77      0.34      0.47       192
         1.0       0.53      0.88      0.66       164

    accuracy                           0.59       356
   macro avg       0.65      0.61      0.57       356
weighted avg       0.66      0.59      0.56       356

Confusion Matrix: 
 [[ 66 126]
 [ 20 144]]

我不知道问题是停用词还是我只考虑文本或语料库作为列的事实(将大写字母和标点符号作为模型中的变量也很好)。

1个回答

你的模型肯定过拟合了。主要问题可能是包含在很少出现的单词的特征中(尤其是那些在语料库中只出现一次的单词):

  • 只出现一次的词根本无助于分类,如果只是因为它们永远无法再次匹配。更一般地说,很少出现的单词更有可能是偶然出现的,因此将它们用作特征会导致过度拟合。
  • 朴素贝叶斯对过度拟合非常敏感,因为它独立考虑所有特征。
  • 也很可能最终特征(单词)的数量相对于实例的数量太高了。低比率的实例/单词会导致过度拟合。

解决方案是过滤掉出现次数少于ñ数据中的次数。你应该尝试几个值ñ, 从...开始ñ=2.

另一个问题:在您当前的过程中,数据在训练集和测试集之间进行拆分之前会进行预处理,这可能会导致数据泄漏。请注意,应仅使用训练数据过滤掉低频词,然后仅在测试集上选择相同的词(忽略任何其他词)。