2015-05-23 2 views
1

В настоящее время я создаю простой спам-фильтр для электронной почты с помощью Naive Bayles.Как я могу сделать nltk.NaiveBayesClassifier.train() работать с моим словарем

Чтобы понять мою логику алгоритма: у меня есть папка с большим количеством файлов os, которые являются примерами спама/сообщений ham. У меня также есть два других файла в этой папке, содержащие заголовки всех моих примеров ветчины, а другой - заголовки всех моих примеров спама. Я организовал это так, чтобы я мог правильно открывать и читать эти письма.

Я помещаю все слова, которые, как я сужу, важны в структуре словаря, с меткой «спам» или «ветчина» в зависимости от того, из какого рода файлов я их извлекал.

Тогда я использую nltk.NaiveBayesClassifier.train(), так что я могу тренировать классификатор, но я получаю сообщение об ошибке:

для featureset, этикетки в labeled_featuresets: ValueError: слишком много значений в unpack

Я не знаю, почему это происходит. Когда я искал решение, я обнаружил, что строки не хешируются, и я использовал список, чтобы сделать это, а затем превратил его в словарь, который, насколько мне известно, хэшируется, но он продолжает получать эту ошибку. Кто-то знает, как его решить? Благодаря!

Весь мой код приведен ниже:

import nltk 
import re 
import random 

stopwords = nltk.corpus.stopwords.words('english') #Words I should avoid since they have weak value for classification 
my_file  = open("spam_files.txt", "r") #my_file now has the name of each file that contains a spam email example 
word  = {} #a dictionary where I will storage all the words and which value they have (spam or ham) 

for lines in my_file: #for each name of file (which will be represenetd by LINES) of my_file 
with open(lines.rsplit('\n')[0]) as email: #I will open the file pointed by LINES, and then, read the email example that is inside this file 
    for phrase in email: #After that, I will take every phrase of this email example I just opened 
     try: #and I'll try to tokenize it 
      tokens = nltk.word_tokenize(phrase) 
     except: 
      continue #I will ignore non-ascii elements 
     for c in tokens: #for each token 
      regex = re.compile('[^a-zA-Z]') #I will also exclude numbers 
      c = regex.sub('', c) 
      if (c): #If there is any element left 
       if (c not in stopwords): #And if this element is a not a stopword 
        c.lower() 
        word.update({c: 'spam'})#I put this element in my dictionary. Since I'm analysing spam examples, variable C is labeled "spam". 

my_file.close() 
email.close() 

#The same logic is used for the Ham emails. Since my ham emails contain only ascii elements, I dont test it with TRY 
my_file = open("ham_files.txt", "r") 
for lines in my_file: 
with open(lines.rsplit('\n')[0]) as email: 
    for phrase in email: 
     tokens = nltk.word_tokenize(phrase) 
     for c in tokens: 
      regex = re.compile('[^a-zA-Z]') 
      c = regex.sub('', c) 
      if (c): 
       if (c not in stopwords): 
        c.lower() 
        word.update({c: 'ham'}) 

my_file.close() 
email.close() 

#And here I train my classifier 
classifier = nltk.NaiveBayesClassifier.train(word) 
classifier.show_most_informative_features(5) 
+0

Помимо проблемы, которую вы описываете (и которую я рассмотрел ниже), ваш код имеет ряд проблем: вы не должны использовать тот же самый диктофон для сбора слов как от писем спама, так и от ветчины - вместо этого используйте отдельный пакет, слова dict для каждого письма. Кроме того, 'c.lower()' не имеет никакого эффекта - вы должны написать 'c = c.lower()'. – lenz

ответ

1

nltk.NaiveBayesClassifier.train() ожидает «список кортежей (featureset, label)» (смотрите в документации метода train()) Что там не упоминается, что featureset должен быть dict имен функций, отображаемых для значений функций.

Таким образом, в типичной классификации спама/ветчины с моделью мешков слов этикетки являются «спамом»/«ветчиной» или 1/0 или «истинным/ложным»; имена функций - это встречающиеся слова, а значения - это количество раз, когда происходит каждое слово. Например, аргумент метод train() может выглядеть следующим образом:

[({'greetings': 1, 'loan': 2, 'offer': 1}, 'spam'), 
({'money': 3}, 'spam'), 
... 
({'dear': 1, 'meeting': 2}, 'ham'), 
... 
] 

Если набор данные достаточно малы, вы можете заменить фактическое количество слов с 1, чтобы уменьшить разреженность данных.

Смежные вопросы