Pull to refresh

Comments 24

Похоже, я перестарался с теорией :). Длинные формулы режут глаза.
По мне так нормальное количество формул.
Хотя я только вчера сдал экзамен по основам теории прогнозирования (кстати в том числе и про байесовский классификатор спрашивали), так что по сравнению с теми ужасами — у Вас формулы вовсе, а так, формулки=)
Да, сами формулы несложные. Просто хабр — не математический журнал, и здесь больше популярны практичные статьи.
Зря Вы так: формулы простые, хорошо оформленные и понятные. Я никогда не интересовался классификаторами, но все понял. Одного кода было бы недостаточно.
Спасибо!
А чем это сильно отличается от алгоритма описанного в книге «Программируем коллективный разум»? — там кстати тоже на питоне код.
Не знаю. Я не читал. Там похожий код?

Знаю хорошую реализацию в nltk. Но там посложнее. Я же хотел написать максимально просто и коротко.
немного, хотя я на питоне не пишу, поэтому утверждать не могу
Но если не читали эту книгу то рекомендую — тем более — там все примеры на питоне.
Да, хорошая книжка. Кое где поверхностно на мой взгляд, но довольно просто все объясняет.
Спасибо, почитаю.
> Я протестировал классификатор на части исходного корпуса с именами.

Исходный корпус — это names.txt, то есть обучающая выборка? Если так, то результат завышен.
Лучше хотя бы случайным образом разбить исходный names.txt на две части train.txt и test.txt, обучать на одной части, тестировать на другой.
Так и сделал :). Разбил на два корпуса. Стандартная, вобщем, практика. names.txt — файлик создавался шафлом по списку женских и мужских имен.

А в чем результат завышен?

Ниже — код для тестирования.

def test(classifier, test_set):
    hits = 0
    for feats, label in test_set:
        if label == classify(classifier, feats):
            hits += 1
    return hits/len(test_set)

def get_features(sample): return (
        'll: %s' % sample[-1],          # get last letter
        'fl: %s' % sample[1],           # get first letter
        'sl: %s' % sample[0],           # get second letter
        )

if __name__ == '__main__':
    samples = (line.decode('utf-8').split() for line in open('names.txt'))
    features = [(get_features(feat), label) for feat, label in samples]
    train_set, test_set = features[:-100], features[-100:]

    classifier = train(train_set)
    print 'Accuracy: ', test(classifier, test_set)
Глядя на этот код, понимаю что всё ОК.

Просто в тексте статьи приведен пример обучения классификатора — там для обучения используется весь names.txt а не его часть, и ниже сказано «Я протестировал классификатор на части исходного корпуса с именами». Выглядит, как будто вы тестировали классификатор на обучающих данных.
Понятно. Просто если бы включил код для тестирования, это было бы больше чем 25 строк :).
В некоторых источниках встречал название этого алгоритма не как «наивный», а «упрощенный» и кажется, что последнее наименование больше подходит.
Мне кажется, статью стоило вынести из-под замка. Очень интересная, на мой взгляд. Хотя, конечно, это личное право автора. Да и хомячки бы вряд ли оценили.
Можно и опубликовать. Только куда? :)

«В функции train первые пять строк производят подсчет количества классов C»
1ая мысль: «а С то тут при чем ?» 2ая:«вот пельмень, это же из формулы» ;)
Да, в коде все очень прямолинейно.
в функции классификаторе (classify) не хватает проверки — есть ли пересечения тестируемого набора фич с фичами классификатора (prob).

т.к. иначе в тесте можно получить неверный результат, если проверять сбойный вариант (для приведенного теста — «ЫЫЫЫЫ»).
Хорошая статья, спасибо. Я у себя в блоге тоже описал байесовский классификатор, но с большим упором на теорию. В частности более подробно написал про проблему неизвестных слов (additive smoothing, то зачем вы использовали 10^-7).
«Если я вам скажу “темно как у негра в …”, вы сразу поймете о каком месте чем идет речь, даже если я не закончу фразу. Так происходит потому что в натуральном языке вероятность появления слова сильно зависит от контекста. Байесовский же классификатор представляет документ как набор слов вероятности которых условно не зависят друг от друга.»
отлично расписано!!! )))
Спасибо за статью!
Я только начал изучать машинное обучение немного удивлён тому, что NBC классификатор реализуется достаточно просто.

Кстати, если будет интересно, я на основе твоего кода и выборки обучил решающее дерево (DecisionTreeClassifier из scikit-learn), которое показало точность 97%:

from sklearn.tree import DecisionTreeClassifier

# ...

def get_features(sample): return (
    ord(sample[-1]),  # get last letter
    ord(sample[0]),  # get first letter
    ord(sample[1]),  # get second letter
)

# ...

clf = DecisionTreeClassifier()
clf.fit(
    [i[0] for i in train_set],
    [i[1] for i in train_set]
)

hits = 0
for feats, label in test_set:
    if label == clf.predict([feats]):
        hits += 1
print 'Accurancy DecisionTreeClassifier: ', hits/len(test_set)

Сюда ещё оценка точности, полноты:
Accuracy, Precision, Recall NBC: (0.96, 0.9821428571428571, 0.9482758620689655)
Accuracy, Precision, Recall CDT: (0.97, 0.9824561403508771, 0.9655172413793104)
Sign up to leave a comment.

Articles

Change theme settings