Классификация документов по категориям - PullRequest
33 голосов
/ 24 июня 2010

В базе данных Postgres хранится около 300 тыс. Документов, помеченных категориями тем (всего их около 150). У меня есть еще 150 тысяч документов, у которых еще нет категорий. Я пытаюсь найти лучший способ их программной классификации.

Я изучал NLTK и его наивный байесовский классификатор. Похоже, хорошая отправная точка (если вы можете предложить лучший алгоритм классификации для этой задачи, я весь слух).

Моя проблема в том, что у меня недостаточно оперативной памяти для обучения NaiveBayesClassifier сразу по всем 150 категориям документов / 300 КБ (для обучения по 5 категориям использовалось 8 ГБ). Кроме того, точность классификатора, кажется, падает, когда я тренируюсь на большем количестве категорий (точность 90% с 2 категориями, 81% с 5, 61% с 10).

Должен ли я просто тренировать классификатор по 5 категориям за раз и запускать все 150 тыс. Документов через классификатор, чтобы увидеть, есть ли совпадения? Кажется, что это сработает, за исключением того, что будет много ложных срабатываний, когда документы, которые на самом деле не соответствуют ни одной из категорий, попадают в классификатор только из-за того, что это лучшее из доступных совпадений ... способ иметь опцию «ничего из вышеперечисленного» для классификатора на случай, если документ не вписывается ни в одну из категорий?

Вот мой тестовый класс http://gist.github.com/451880

Ответы [ 3 ]

33 голосов
/ 25 июня 2010

Вы должны начать с преобразования ваших документов в TF-log (1 + IDF) векторов : частоты терминов редки, поэтому вы должны использовать python dict с термином в качестве ключей и считать как значения, а затем делить на общеесчитать, чтобы получить глобальные частоты.

Другое решение состоит в том, чтобы использовать abs (хэш (термин)), например, в качестве положительных целочисленных ключей.Затем вы используете векторы scipy.sparse, которые более удобны и более эффективны для выполнения операций линейной алгебры, чем диктон python.

Также постройте 150 векторов частот, усредняя частоты всех помеченных документов, принадлежащих к той же категории,Затем для нового документа для метки вы можете вычислить косинусное сходство между вектором документа и каждым вектором категории и выбрать наиболее похожую категорию в качестве метки для вашего документа.

Если это не хорошодостаточно, тогда вы должны попытаться обучить модель логистической регрессии, используя штраф L1, как объяснено в этом примере из scikit-learn (это оболочка для liblinear, как объяснено @ephes),Векторы, используемые для обучения вашей модели логистической регрессии, должны быть ранее введенными векторами TD-log (1 + IDF), чтобы получить хорошую производительность (точность и отзыв).Библиотека scikit learn предлагает модуль sklearn.metrics с подпрограммами для вычисления этих показателей для данной модели и данного набора данных.

Для больших наборов данных: вам следует попробовать vowpal wabbit , который, вероятно,Самый быстрый кролик в мире для крупномасштабных задач классификации документов (но не простой в использовании упаковщиков Python AFAIK).

11 голосов
/ 25 июня 2010

Насколько большими (количество слов) ваши документы? Потребление памяти при обучении 150K не должно быть проблемой.

Наивный Байес - хороший выбор, особенно когда у вас много категорий с несколькими примерами тренировок или очень шумными тренировочными данными. Но в целом линейные машины опорных векторов работают намного лучше.

Является ли ваша проблема мультиклассом (документ относится только к одной категории) или мультиметкой (документ относится к одной или нескольким категориям)?

Точность - плохой выбор для оценки работы классификатора. Вы должны скорее использовать точность против отзыва, точную точку безубыточности отзыва (prbp), f1, auc и взглянуть на кривую точность против отзыва, где функция возврата (x) построена в зависимости от точности (y) на основе значения вашего доверительного порога (документ относится к категории или нет). Обычно вы создаете один двоичный классификатор для каждой категории (положительные примеры обучения одной категории по сравнению со всеми другими примерами обучения, которые не относятся к вашей текущей категории). Вам нужно будет выбрать оптимальный порог достоверности для каждой категории. Если вы хотите объединить эти отдельные показатели для каждой категории в глобальный показатель эффективности, вам придется использовать микро (суммировать все истинные положительные значения, ложные положительные результаты, ложные отрицательные значения и истинные отрицательные значения и рассчитывать комбинированные оценки) или макрос (рассчитать оценку по категориям затем усредните эти оценки по всем категориям) в среднем.

У нас есть корпус из десятков миллионов документов, миллионов обучающих примеров и тысяч категорий (многослойных). Поскольку мы сталкиваемся с серьезными проблемами с временем обучения (количество документов, новых, обновленных или удаленных в день, довольно велико), мы используем модифицированную версию liblinear . Но при небольших проблемах использование одной из оболочек python вокруг liblinear ( liblinear2scipy или scikit-learn ) должно работать нормально.

2 голосов
/ 25 июня 2010

Есть ли способ иметь "ни один из выше "вариант для классификатора просто в случае, если документ не вписывается в любая из категорий?

Вы можете получить этот эффект, просто тренируя псевдо-категорию «ни один из вышеперечисленных» каждый раз. Если максимум, который вы можете обучить, составляет 5 категорий (хотя я не уверен, почему он потребляет так много оперативной памяти), обучите 4 фактическим категориям из их фактических 2K документов в каждой, и одну «ни одну из вышеперечисленных» с 2K документами. взято случайным образом из всех остальных 146 категорий (по 13-14 из каждой, если вы хотите использовать подход «стратифицированной выборки», который может быть более надежным).

По-прежнему ощущается что-то вроде клочья, и вам, возможно, будет лучше с совершенно другим подходом - найдите многомерную меру документа, которая определяет ваши предварительно помеченные документы объемом 300 тыс. В 150 разумно разделенных кластеров, а затем просто назначьте каждый другие, еще не маркированные, документы для соответствующего кластера, как определено таким образом. Я не думаю, что у NLTK есть что-то напрямую доступное для поддержки такого рода вещей, но, эй, NLTK рос настолько быстро, что я, возможно, что-то упустил ...; -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...