[НЕТ ЗВУКА] В
этом видео мы разберем с вами пример,
в котором попробуем использовать методы кластеризации на практике.
Кластеризовать мы будем письма.
Письма на разные темы.
Для этого нам потребуется выборка 20newsgroups.
Она может быть загружена функцией встроенной sklearn.
Ну давайте посмотрим, какие темы там представлены.
Тем, действительно, много.
Ну и давайте не будем работать сразу со всеми, а для начала сделаем себе простую
выборку, в которой будет всего три темы, очень сильно отличающихся друг от друга.
Ну например, что-нибудь про Маки, про религию,
в частности христианство, и про спорт, в частности хоккей.
Ну казалось бы, что может быть более различным?
Уж наверное здесь у нас все получится.
Подготовим датасет и посмотрим, что в нем внутри.
Как видите, письмо действительно вроде бы как про Мак,
и, в общем-то,
можно посмотреть на другие классы.
Все классы здесь отображаются ноликами, единичками и двоечками,
поэтому давайте попробуем понять, что значат эти единички и двоечки.
Если мы посмотрим на последний элемент, у него класс 2, то увидим, что здесь,
скорее всего, про христианство, а если посмотрим на предпоследний элемент,
то увидим, что это, по ходу, переписка каких-то ребят из NASA,
однако это переписка про хоккей.
Ну и давайте посмотрим, сколько у нас вообще объектов в выборке.
Не очень много, 1777.
Ну и приступим к тому, чтобы подготовить какие-то признаки.
Итак, давайте попробуем для начала просто частоты слов.
Посмотрим на нашу матрицу.
Матрица получилась количество объектов на 3767.
Так вышло из-за того, что мы задали пороги для максимальной
документной частоты слов и для минимальной.
То есть мы в этой ситуации не хотели видеть слова,
которые встречаются больше чем в 500 документах, ну для того,
чтобы как-то более-менее удобно различать разные кластеры.
Наверняка во всех кластерах есть слова from, subject и тому подобное.
А с другой стороны, мы не хотели смотреть на слишком редкие слова,
чтобы у нас не получалась слишком большая матрица.
Ну и давайте попробуем воспользоваться ну например агломеративной
кластеризацией, потому что в ней мы можем задать используемую метрику
или функцию близости и, в частности, можем использовать косинусную меру, которая,
казалось бы, так неплохо должна подходить к тексту.
Давайте это все просто запустим.
Обратите внимание: перед тем, как делать fit_predict,
я преобразую матрицу к другому формату.
Дело в том, что матрица после извлечения признаков получится в разреженном формате.
И конечно, в таком формате с ней работать удобнее, ведь в ней много нулей.
Зачем нам хранить все эти нули,
если можно хранить только значения в тех местах, где не ноль?
Но, к сожалению, реализация алгоритма не поддерживает
разреженные матрицы, и поэтому приходится приводить к плотному виду и,
естественно, расходовать очень много памяти.
Посмотрим на результаты.
Результаты выглядят более чем ужасно.
Действительно, у нас везде практически кластер 0.
Есть небольшие вкрапления кластера 1, кластера 2,
но не это мы ожидали в этой задаче.
Давайте попробуем все же вместо частот
слов использовать взвешенные частоты с помощью tf-idf векторайзеров.
Подробнее о разных признаках в анализе текстов мы еще поговорим в пятом курсе
нашей специализации.
Давайте это снова запустим.
Давайте снова запустим обучаться.
Что еще могло нас подвести?
Может быть, мы использовали недостаточно жесткие параметры для отсечения.
Может быть, недостаточно мягкие.
Может быть, нужно увеличить параметр max document frequency,
а может быть уменьшить.
Это мы тоже можем попробовать.
Тем временем у нас отработал алгоритм и мы можем снова посмотреть на результаты.
Результаты по-прежнему не впечатляют.
Давайте проверим наши гипотезы насчет уменьшения или увеличения параметров.
Ну давайте попробуем смотреть только на те слова,
которые встретились хотя бы в 100 документах.
Если подумать, то в предположении, что наши кластеры примерно одинакового
размера, каждый кластер будет больше 100 документов и, может быть,
какие-то слова все же получится выцепить.
Давайте сделаем минимальную документную частоту на 10, а 100, запустим это все,
посмотрим на матрицу, увидим что теперь у нас всего 333 признака.
На самом деле это, может быть, уже подозрительно,
но выполним код и посмотрим на результаты.
Конечно, при таком количестве признаков все отработает еще быстрее.
Ну и здесь все совсем безнадежно.
Смотрите, просто практически одни нули.
Хорошо, можно попробовать изменить первый параметр.
Давайте сделаем так, чтобы признаков все же было чуть побольше.
Ну как вы видите, не сильно все поменялось.
Давайте наконец убедимся, что эти признаки тоже не исправили всю ситуацию.
Смотрим результат.
Ну в какой-то степени, может быть, стало и получше, но сложно судить визуально.
Давайте вернем все как было,
потому что ничего лучше мы пока не сделали.
[МОЛЧИТ] Тем временем можно подумать,
что еще можно предпринять, чтобы как-то справиться с этой задачей.
Ну, может быть, мы допустили где-нибудь ошибку, когда строили признаки.
Может быть, стоит посмотреть на конкретные письма,
на конкретные признаки и проверить, что все работает правильно.
Давайте посмотрим на нулевой объект из выборки.
И вот мы видим, что у него есть признак с индексом 877 и
давайте для примера на него и посмотрим.
Можно посмотреть, какие признаки у нас в принципе есть.
Ну вот видно, что это разные слова.
И видно, что есть много всякого мусора.
Непонятно, мусор мешает нам сейчас или нет,
но посмотрим сначала на вот этот признак.
Этот признак соответствует вполне конкретному слову.
Посмотрим на сам текст.
Слово в нем есть, значит вроде бы все более-менее правильно.
Тогда остается последняя страшная мысль.
Видимо, у нас очень много всякого шума.
У нас очень плохие признаки из вот этих всяких чисел и нужно
как-то фильтровать признаки.
Мы бы могли этим сейчас заняться, и тогда бы это видео длилось не 15 минут,
а может быть 3 часа, но мы своевременно вспомним, что существуют и другие методы
кластеризации, в частности, очень простой метод кластеризации k-средних.
Давайте попробуем его.
Итак, мы видим, что получились какие-то прогнозы.
Да, обратите внимание, количество кластеров задано равным трем,
и также я задал random_state для того, чтобы результаты были воспроизводимы.
Это нужно исключительно для того, чтобы понимать, какие метки будут у
кластеров для того, чтобы не переписывать код, который будет ниже.
Ну давайте посмотрим, какие ответы должны были получиться.
Смотрите, безумно похоже.
Нули на том же месте, а вместо двойки хотелось бы поставить единицу,
вместо единицы — двойку.
Ну то есть получается, что мы просто не угадали с тем,
как пометить кластер, но это не важно.
Нам же важна суть.
Но кластеризация похожа на правду.
Давайте возьмем и сделаем отображение, в котором двойка перейдет в единицу,
единица — в двойку, а нолик останется.
И посмотрим, в какой доле случаев мы неверно угадываем кластер.
Просто фантастика, 4,6 %.
То есть мы практически с точностью 96 %, ну даже,
точнее, 95 %, угадываем кластеры.
Это просто потрясающе, при том что у нас не было обучающей выборки с ответами.
Давайте для примера сравним это все с классификатором.
Уж классификатор-то знает, какие ответы на обучающей выборке.
И, если посмотреть на качество логистической регрессии в кросс-валидации,
можно увидеть 98,5 %.
То есть, в принципе, 95 % от 98 не сильно далеко ушло,
и это по-прежнему удивительно.
Ну наверное дело в том, что мы взяли очень простую выборку.
Давайте попробуем что-то более сложное, например,
на этот раз выберем три темы, которые близки друг к другу.
Пусть они все будут про компьютеры, и сразу же попробуем
на них применить метод K средних.
[БЕЗ ЗВУКА] Конечно,
здесь уже отличить тему будет сложнее,
мы не ожидаем, что качество будет таким же.
Более того, не очень понятно, какие числа куда отображать.
Но, вообще, если присмотреться, можно увидеть, что, наверно, нолик в двойку,
двойку в ноль и единицу в единицу.
Хотя вот даже уже среди этих примеров мы видим ошибку.
Ну давайте попробуем так сделать и посмотреть на качество.
Смотрите, теперь уже ошибок 26 %.
В принципе, тоже не очень много, потому что у нас даже не два кластера,
а три кластера.
И самое главное, наш алгоритм кластеризации совершенно не догадывается,
по какому принципу мы делим тексты на группы,
ведь это можно сделать кучей разных способов.
И если мы хотим как-то передать это знание нашему алгоритму кластеризации,
нужно просто выбирать правильным образом признаки.
Вот, оказывается, те признаки, которые мы выбрали,
достаточно близки к тому, что нам нужно.
Давайте посмотрим на качество классификатора.
Классификатор здесь уже существенно обгоняет, тут, конечно,
качество не 70 %, а 91, даже почти 92.
Но, оказывается, что и это качество можно чуточку улучшить, ведь у нас сейчас очень
много признаков, можно попробовать уменьшить количество признаков,
воспользовавшись сингулярным разложением матриц, то есть SVD.
Мы уже знакомились с SVD в первом курсе и еще будем продолжать
знакомство в этом курсе.
Давайте сейчас просто воспользуемся им и попробуем оставить всего 1000 признаков.
После этого
нам опять же потребуется как-то сопоставить полученные кластеры
с правильными ответами и вновь посмотреть на качество.
Смотрите, качество стало 20 %.
Всего 20 % ошибок!
Удивительно!
Кстати говоря, давайте попробуем оставить не 1000 компонент, а 200.
Казалось бы, мы очень сильно понизим размерность пространства признаков,
наверняка уже все сломается.
Здесь уже реализована простенькая функция,
которая просто выводит все результаты в зависимости от разных перестановок,
то есть мы можем отображать двойку в некоторую переменную a,
единичку в некоторую переменную b, нолик в некоторую переменную c.
Здесь мы перебираем все возможные перестановки нолика,
единички и двойки и выводим результаты.
И, смотрите, самая лучшая перестановка дает опять-таки 20 % ошибок.
То есть, мы оставили всего 200 признаков,
200 признаков из более чем трех тысяч, и по-прежнему качество у нас такое же.
На самом деле не стоит быть слишком уж доверчивым к этому всему.
Дело в том, что здесь я выбрал очень удачный random_state,
а с другим random_state могут получится и совсем другие результаты.
Давайте посмотрим.
Ну вот, лучший результат 26 %.
Подведем итог.
Мы с вами смогли получить интерпретируемый результат кластеризации текстов.
При этом мы это сделали как на простой выборке, так и на более сложной выборке.
Но в то же время надо помнить, что у нас было всего три темы,
а реальность намного более сурова.
Часто мы даже не знаем, сколько у нас тем,
и мы не можем так легко воспользоваться, например, K Means.
Мы попробовали агломеративную кластеризацию и вовремя догадались
использовать K Means.
Здесь нас очень выручило то, что мы знали, сколько кластеров должно получиться.