Логистический, регуляризованный линейный, SVM, ANN, KNN, случайный лес, LGBM и наивный байесовский классификатор, какой из них лучше всего справляется с классификацией газетных статей?
Все эти классификаторы машинного обучения в scikit-learn и light GBM могут эффективно обрабатывать матрицу scipy.sparse, которая является выходом TfidfVectorizer. TfidfVectorizer — это экстрактор функций НЛП, который использует стратегии мешка слов. Сначала он применяет CountVectorizer, а затем применяет TfidfTransformer для нормализации. В этой статье обсуждается TF-IDF.
Давайте проверим набор данных и посмотрим, в чем заключается задача!
data_train = fetch_20newsgroups(subset='train', categories=categories,shuffle=True, random_state=42,remove=remove) data_test = fetch_20newsgroups(subset='test', categories=categories, shuffle=True, random_state=42, remove=remove)
Набор данных 20 групп новостей включает 11 314 новостных статей в обучающей выборке и 7 532 в тестовой выборке. Разделение между обучающей выборкой и тестовой выборкой не является случайным и основано на дате публикации новостной статьи.
Всего 18 846 новостных статей разбиты на эти 20 групп:
['alt.atheism', 'comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.ibm.pc.hardware', 'comp.sys.mac.hardware', 'comp.windows.x', 'misc.forsale', 'rec.autos', 'rec.motorcycles', 'rec.sport.baseball', 'rec.sport.hockey', 'sci.crypt', 'sci.electronics', 'sci.med', 'sci.space', 'soc.religion.christian', 'talk.politics.guns', 'talk.politics.mideast', 'talk.politics.misc', 'talk.religion.misc']
Угадайте, как машина «прочитает» подобную новостную статью, а затем классифицирует ее:
От кого: «[email protected] (Дэвид Най)\nТема: Re: Нужна консультация по проблеме взаимоотношений между врачом и пациентом\nИдентификатор статьи: cnsvax.1993Apr17.012019.6087\nОрганизация: Университет Висконсина О-Клэр\nЛинии: 12\n\n[ответ на [email protected] (Майкл Ковингтон)]\n \n›Похоже, его сердце на правильном месте, но он не умеет\n›выражать это . То, что вы получили, было _задумано_ как глубокое извинение.\n›Извинения, произнесенные переутомленными застенчивыми людьми, часто выглядят так...\n \nМне этот парень не показался слишком застенчивым. Он звучал как придурок. Я говорю: бросьте\nего кого-нибудь более знающего и чуткого.\n\nДэвид Най ([email protected]). Клиника Мидельфорт, О-Клэр, Висконсин.\nЭто откровенный абсурд; но кто хочет стать философом,\nдолжен научиться не пугаться нелепостей. — Бертран Рассел\n”
Какой алгоритм работает лучше всего? Скоро узнаем!
vectorizer = TfidfVectorizer(sublinear_tf=True, max_df=0.5, stop_words='english') X_train = vectorizer.fit_transform(data_train.data) X_test = vectorizer.transform(data_test.data)
TfidfVectorizer извлекает функции из матрицы количества токенов. Он удаляет все английские стоп-слова и просматривает только те токены, которые появляются менее чем в 50% документов (это делается для того, чтобы отфильтровать токены, которые появляются очень часто, что может создавать помехи для алгоритмов и приводить к переобучению).
Всего в обучающем наборе найдено 101 322 токена (токены, которые видны только в тестовом наборе, но не в обучающем наборе, будут игнорироваться). Некоторые жетоны для проверок:
(vectorizer.get_feature_names()[::1000])
вывод:
[‘00’, ‘0h’, ‘11100001’, ‘16339’, ‘1qi83b’, ‘25x30’, ‘2x4s’, ‘3h’, ‘491’, ‘5685’, ‘639’, ‘6us’, ‘7l4e’, ‘8ffzu’, ‘9a8’, ‘_does’, ‘a89’, ‘adv21’, ‘allotment’, ‘apml’, ‘assyria’, ‘b3r’, ‘beast’, ‘bkdd’, ‘breakdown’, ‘c1i’, ‘cated’, ‘chipkeyk1’, ‘cmcl2’, ‘concurrence’, ‘cots’, ‘cursing’, ‘dcc’, ‘deselected’, ‘disinformation’, ‘drawed’, ‘ebrandt’, ‘emrick’, ‘ethiopians’, ‘f3fg’, ‘ff1zv’, ‘foolproof’, ‘fwmr’, ‘geode06’, ‘gq30tb’, ‘h378’, ‘heaters’, ‘holograph’, ‘hzrcj’, ‘imbecile’, ‘innacurate’, ‘irx’, ‘jerseys’, ‘jz75vzneut’, ‘khojaly’, ‘kxp2124’, ‘legatus’, ‘llat’, ‘m13sm’, ‘magnanamous’, ‘mbes’, ‘meteosat’, ‘mitcc7_b_’, ‘morpl’, ‘musil’, ‘nbc’, ‘nko’, ‘o5hp1en’, ‘ooops’, ‘ovk9lg’, ‘patl7a’, ‘phono’, ‘poley’, ‘princess’, ‘purporting’, ‘quandaries’, ‘razmella’, ‘relations’, ‘rfi’, ‘rotate’, ‘sadist’, ‘scx_sy’, ‘shickley’, ‘slaughter’, ‘spearhead’, ‘stavropol’, ‘suggestionas’, ‘t3dlib’, ‘tenour’, ‘tl1mm’, ‘triple’, ‘ucssun1’, ‘unloved’, ‘v108’, ‘vices’, ‘w1t45w’, ‘westboro’, ‘worn’, ‘xds’, ‘xuo’, ‘ysjp0r’, ‘zp9w’]
Токены разнообразны, корпус охватывает всего понемногу. Этот реальный набор данных разнообразен и охватывает множество различных областей.
Как мы видим из вышеизложенного, многие токены не имеют смысла сами по себе. Мне не терпится увидеть, как машины интерпретируют их.
Может быть интересно также попробовать включить биграммы, чтобы посмотреть, улучшит ли это результаты, но это резко увеличит количество функций и время выполнения. Для простоты в этом упражнении мы будем использовать только униграммы.
После всех подготовительных работ, описанных выше, теперь дело доходит до сути этой статьи! Давайте попробуем множество классификаторов, чтобы увидеть, какой из них работает лучше всего!
Во-первых, попробуйте некоторые базовые классификаторы:
(RidgeClassifier(tol=1e-2, solver="sag"), "Ridge Classifier"), (Perceptron(max_iter=50), "Perceptron"), (MLPClassifier(random_state=1,max_iter=300,early_stopping=True,hidden_layer_sizes=(200,100)),"MLP"), (LogisticRegression(random_state=0,n_jobs=-1),"Logistic"), (PassiveAggressiveClassifier(max_iter=50),"Passive-Aggressive"), (KNeighborsClassifier(n_neighbors=5), "kNN"), (RandomForestClassifier(), "Random forest"))
Линейные модели с различными регуляризациями:
for penalty in ["l2", "l1"]: # Train Liblinear model (LinearSVC(penalty=penalty, dual=False,tol=1e-3)) # Train SGD model benchmark(SGDClassifier(alpha=.0001, max_iter=50, penalty=penalty))
Линейная модель с регуляризацией эластичной сети:
SGDClassifier(alpha=.0001, max_iter=50, penalty="elasticnet"))
Легкий ГБМ:
LGBMClassifier()
Ближайший центроид:
NearestCentroid()
Когда ближайший центроид используется для классификации текста с векторами tf-idf, этот классификатор также известен как классификатор Роккио.
Различные версии наивных байесовских классификаторов
MultinomialNB(alpha=.01) BernoulliNB(alpha=.01) ComplementNB(alpha=.1)
LinearSVC с выбором функций на основе L1:
Pipeline( [('feature_selection',SelectFromModel(LinearSVC(penalty="l1", dual=False,tol=1e-3))), ('classification', LinearSVC(penalty="l2"))])
Напоминаем, что функции разрежены, и обучающий набор, и тестовый набор имеют 101 322 измерения, так что это явно непростая задача.
Давайте посмотрим, как работают наши классификаторы:
==================================================================== Ridge Classifier ____________________________________________________________________ Training: RidgeClassifier(solver='sag', tol=0.01) train time: 5.077s test time: 0.028s accuracy: 0.703 density: 0.999998 ==================================================================== Perceptron ____________________________________________________________________ Training: Perceptron(max_iter=50) train time: 0.769s test time: 0.039s accuracy: 0.634 density: 0.118555 ==================================================================== MLP ____________________________________________________________________ Training: MLPClassifier(early_stopping=True, hidden_layer_sizes=(200, 100), max_iter=300, random_state=1) train time: 610.054s test time: 0.201s accuracy: 0.696 ==================================================================== Logistic ____________________________________________________________________ Training: LogisticRegression(n_jobs=-1, random_state=0) train time: 32.092s test time: 0.022s accuracy: 0.695 ==================================================================== Passive-Aggressive ____________________________________________________________________ Training: PassiveAggressiveClassifier(max_iter=50) train time: 1.259s test time: 0.033s accuracy: 0.680 ==================================================================== kNN ____________________________________________________________________ Training: KNeighborsClassifier() train time: 0.006s test time: 3.676s accuracy: 0.071 ==================================================================== Random forest ____________________________________________________________________ Training: RandomForestClassifier() train time: 69.612s test time: 1.232s accuracy: 0.627 ==================================================================== L2 penalty ____________________________________________________________________ Training: LinearSVC(dual=False, tol=0.001) train time: 3.832s test time: 0.025s accuracy: 0.697 ____________________________________________________________________ Training: SGDClassifier(max_iter=50) train time: 1.019s test time: 0.031s accuracy: 0.699 ==================================================================== L1 penalty ____________________________________________________________________ Training: LinearSVC(dual=False, penalty='l1', tol=0.001) train time: 4.014s test time: 0.017s accuracy: 0.666 ____________________________________________________________________ Training: SGDClassifier(max_iter=50, penalty='l1') train time: 1.641s test time: 0.032s accuracy: 0.620 ==================================================================== Elastic-Net penalty ____________________________________________________________________ Training: SGDClassifier(max_iter=50, penalty='elasticnet') train time: 2.741s test time: 0.022s accuracy: 0.693 ==================================================================== NearestCentroid (aka Rocchio classifier) ____________________________________________________________________ Training: NearestCentroid() train time: 0.037s test time: 0.027s accuracy: 0.643 ==================================================================== Naive Bayes ____________________________________________________________________ Training: MultinomialNB(alpha=0.01) train time: 0.098s test time: 0.024s accuracy: 0.696 ____________________________________________________________________ Training: BernoulliNB(alpha=0.01) train time: 0.101s test time: 0.098s accuracy: 0.567 ____________________________________________________________________ Training: ComplementNB(alpha=0.1) train time: 0.120s test time: 0.020s accuracy: 0.708 ==================================================================== LinearSVC with L1-based feature selection ____________________________________________________________________ Training: Pipeline(steps=[('feature_selection', SelectFromModel(estimator=LinearSVC(dual=False, penalty='l1', tol=0.001))), ('classification', LinearSVC())]) train time: 4.601s test time: 0.024s accuracy: 0.681 ==================================================================== lgbm ____________________________________________________________________ Training: LGBMClassifier() train time: 426.488s test time: 7.752s accuracy: 0.610
Барабанная дробь…… и победитель……
Комплементарный наивный байесовский метод (CNB) является победителем благодаря высочайшей точности и короткому времени обучения.
CNB известен своими способностями к задачам классификации текста, и в этой области он регулярно превосходит мультиномиальный байесовский алгоритм.
RidgeClassifier на втором месте, а один из SGDClassifiers на третьем:
Давайте рассмотрим время, необходимое классификаторам для обработки стольких измерений.
Неудивительно, что более высокие затраты времени не обеспечивают более высокую отдачу от точности. Нам нужно найти правильную модель для конкретной задачи, с которой мы сталкиваемся.
Для справки, эта статья является расширением этой. Надеюсь, вам понравилось. И все коды сохраняются здесь.