На этом шаге мы рассмотрим способ ускорения нахождения результата.
Теперь, давайте посмотрим, можно ли улучшить процесс извлечения слов. CountVectorizer извлекает токены с помощью регулярных выражений. По умолчанию используется регулярное выражение "\b\w\w+\b". Для тех, кто не знаком с регулярными выражениями, поясним: это выражение позволяет найти все последовательности символов, которые состоят как минимум из двух букв или цифр (\w) и отделены друг от друга границами слов (\b). Его не интересуют слова, состоящие из одного символа, сокращения типа "doesn't" или "bit.ly" оно разбивает на два слова, однако последовательность символов "h8ter" будет обработана как отдельное слово. Затем CountVectorizer преобразует все буквы в строчные, поэтому слова "soon", "Soon" и "sOon" соответствуют одному и тому же токену (и, следовательно, одному и тому же признаку). Этот простой принцип достаточно хорошо работает на практике, однако, как мы уже видели ранее, можно получить массу неинформативных признаков (например, числа). Один из способов решить эту проблему - использовать только те токены, которые встречаются по крайней мере в двух документах (или по крайней мере в пяти документах и т.д.). Токен, который встретился только в одном документе, вряд ли встретится в тестовом наборе и поэтому бесполезен. С помощью параметра min_df мы можем задать минимальное количество документов, в котором должен появиться токен.
[In 17]: vect = CountVectorizer(min_df=5).fit(text_train) X_train = vect.transform(text_train) print("X_train с min_df: {}".format(repr(X_train))) X_train с min_df: <75000x44532 sparse matrix of type '' with 10191240 stored elements in Compressed Sparse Row format>
Задав min_df=5, мы уменьшаем количество признаков до 44532, и если сравнить этот результат с предыдущим выводом, теперь мы используем лишь треть исходных признаков. Давайте снова взглянем на токены:
[In 18]: feature_names = vect.get_feature_names() print("Первые 50 признаков:\n{}".format(feature_names[:50])) print("Признаки с 20010 по 20030:\n{}".format(feature_names[20010:20030])) print("Каждый 700-й признак:\n{}".format(feature_names[::700])) Первые 50 признаков: ['00', '000', '001', '007', '00am', '00pm', '00s', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '100', '1000', '1001', '100k', '100th', '100x', '101', '101st', '102', '103', '104', '105', '106', '107', '108', '109', '10am', '10pm', '10s', '10th', '10x', '11', '110', '1100', '110th', '111', '112', '1138', '115', '116', '117', '11pm', '11th'] Признаки с 20010 по 20030: ['inert', 'inertia', 'inescapable', 'inescapably', 'inevitability', 'inevitable', 'inevitably', 'inexcusable', 'inexcusably', 'inexhaustible', 'inexistent', 'inexorable', 'inexorably', 'inexpensive', 'inexperience', 'inexperienced', 'inexplicable', 'inexplicably', 'inexpressive', 'inextricably'] Каждый 700-й признак: ['00', 'accountability', 'alienate', 'appetite', 'austen', 'battleground', 'bitten', 'bowel', 'burton', 'cat', 'choreographing', 'collide', 'constipation', 'creatively', 'dashes', 'descended', 'dishing', 'dramatist', 'ejaculation', 'epitomize', 'extinguished', 'figment', 'forgot', 'garnished', 'goofy', 'gw', 'hedy', 'hormones', 'imperfect', 'insomniac', 'janitorial', 'keira', 'lansing', 'linfield', 'mackendrick', 'masterworks', 'miao', 'moorehead', 'natassia', 'nude', 'ott', 'particulars', 'phillipines', 'pop', 'profusely', 'raccoons', 'redolent', 'responding', 'ronno', 'satirist', 'seminal', 'shrews', 'smashed', 'spendthrift', 'stocked', 'superman', 'tashman', 'tickets', 'travelling', 'uncomfortable', 'uprising', 'vivant', 'whine', 'x2']
Четко видно, что намного реже стали встречаться числа и, похоже, что исчезли некоторые странные или неправильно написанные слова. Давайте оценим качество нашей модели, вновь выполнив решатчатый поиск:
[In 19]: grid = GridSearchCV(LogisticRegression(), param_grid, cv=5) grid.fit(X_train, y_train) print("Наилучшее значение перекр проверки: {:.2f}".format(grid.best_score_)) Наилучшее значение перекр проверки: 0.87
Наилучшее значение правильности, полученное в ходе перекрестной проверки, по-прежнему равно 87%. Мы не смогли улучшить качество нашей модели, однако сокращение количества признаков ускорит предварительную обработку, а исключение бесполезных признаков, возможно, улучшит интерпретабельность модели.
На следующем шаге мы рассмотрим стоп-слова.