Обработка естественного языка для автоматизированной разработки функций

Как применить библиотеку nlp-primitives с помощью Featuretools.

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

В Featuretools примитивные функции используются для автоматического создания функций для различных типов данных, что позволяет моделям машинного обучения максимально использовать данные из вашего набора данных.

В этой статье я исследую использование библиотеки примитивов nlp для создания функций из текстовых данных, используя пример набора данных для исследования этих дополнительных функций в модели машинного обучения. Затем я объясняю, почему эти примитивы так сильно влияют на точность модели.

Демонстрация машинного обучения с использованием nlp-примитивов

В этой демонстрации я буду использовать данные из этого набора данных Kaggle, который содержит 100 отзывов о 57 ресторанах в районе Сан-Франциско. Набор данных относительно невелик, но его достаточно для демонстрации проектирования функций с помощью Featuretools и библиотеки nlp-primitives. Вы можете следить за этим, используя Jupyter Notebook из этого репозитория.

Во-первых, давайте установим задачу: определить мнение каждого рецензента о ресторане на основе их отзывов. Об успехе модели будут судить по тому, насколько точно она может предсказать рейтинг, выставленный каждым рецензентом на основе предоставленных данных и обзора. В наборе данных есть 5 возможных значений отзывов, от 1 до 5 звезд, поэтому проблема заключается в классификации по 5 классам.

Чтобы оценить эффективность примитивов НЛП, я также создал базовую матрицу признаков, используя Deep Feature Synthesis (DFS) без этих новых примитивных функций, чтобы я мог видеть, насколько эффективны эти новые примитивы. С помощью этой базовой матрицы функций я создал модель машинного обучения с оценкой точности около 50%.

baseline_feature_matrix, baseline_features = ft.dfs(entityset=es,
                                            target_entity='reviews',
                                            verbose=True,
                                            ignore_variables=ignore)
built 33 features
base_rfc = RandomForestClassifier(n_estimators=100,
                                  class_weight = "balanced", 
                                  n_jobs=-1)
base_rfc.fit(baseline_train_fm, baseline_y_train)
base_rfc.score(baseline_test_fm, baseline_y_test)
0.5156462585034014

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

Между базовой моделью и моделью, использующей примитивы НЛП, изменился только один фактор: использование библиотеки nlp-primitives.

trans = [DiversityScore, LSA, MeanCharactersPerWord, 
         PartOfSpeechCount, PolarityScore, PunctuationCount, 
         StopwordCount, TitleWordCount, UniversalSentenceEncoder,      
         UpperCaseCount]

features = ft.dfs(entityset=es, target_entity='reviews', 
                  trans_primitives=trans, verbose=True,
                  features_only=True, ignore_variables=ignore,
                  drop_contains=drop_contains, max_depth=4)
Built 333 features

Благодаря этому небольшому изменению в вызове DFS количество сгенерированных функций увеличилось в 10 раз.

Эту библиотеку было чрезвычайно легко включить, и только несколько строк дополнительного кода были задействованы для импорта библиотеки и примитивов и последующего добавления этих примитивов к примитивам по умолчанию, используемым функцией ft.dfs для создания функций. И в базовой модели, и в модели nlp-примитивов DFS использовалась для поиска функций, хотя nlp-примитивы имели модифицированное поле глубины, которое позволяло DFS создавать примитивы, которые накладывались поверх функций NLP.

После запуска DFS и создания результирующей матрицы функций мы можем разделить данные на обучающие и тестовые наборы и использовать эти наборы в моделях машинного обучения sklearn для проверки их точности.

vot = VotingClassifier(voting='soft', 
                       estimators=[('lgr', lgr),('rfc', rfc),   
                                  ('hgbc', hgbc)],
                       weights=[3, 1, 6])
vot.fit(train_feature_matrix, y_train)
vot.score(test_feature_matrix, y_test)
0.6925170068027211

При использовании библиотеки nlp-primitives модели смогли достичь точности около 70%, при этом матрица ошибок распределялась точно (темно-синий цвет представляет предположения), а большинство неверных предположений были очень близки (± 1 - обозначено значком более темный синий цвет на более очевидной диагональной линии) к фактическому ответу (в идеальном алгоритме будет 1 на нисходящей диагонали, представляющей согласование предсказанной и истинной метки, и 0 в каждой другой категории - подробнее о матрицах путаницы здесь ).

Обе эти модели используют аналогичные шаги обучения и тестирования (базовая модель использует немного менее сложную функцию, потому что более сложные функции не влияют на точность), но точность модели с функциями НЛП примерно на 40% выше, чем базовая. . Поскольку все остальное осталось прежним, очевидно, что библиотека NLP Primitives ответственна за такое значительное повышение точности. Более того, когда мы исследуем важность функций, мы видим, что функции, использующие примитивы NLP, получают наивысший рейтинг (см. блокнот для более подробной информации).

Почему эти примитивы имеют значение?

Данные должны быть отформатированы как числа, чтобы модель машинного обучения могла «учиться» на них. Текст трудно выразить числами или, по крайней мере, трудно выразить числами, не потеряв при этом большого смысла. Например, довольно просто получить количество слов в основной части текста, но часто это не является адекватной мерой значения. Хотя иногда это может быть полезной функцией, текст - это гораздо больше, чем количество содержащихся в нем слов.

Итак, какое решение? Как можно осмысленно преобразовать текст в числа? Одно из решений - векторизовать значение текста. Примитивы НЛП, такие как UniversalSentenceEncoder, LSA (скрытый семантический анализ) и PartOfSpeechCount используют этот метод. Оба они являются примитивами с несколькими выводами, что означает, что они берут одно поле и создают объект с множеством полей. В этом случае эти поля представляют собой размеры вектора. В приведенном ниже примере каждая строка текста соответствует двум выходным данным, поскольку LSA (скрытый семантический анализ) создает вектор длины два для каждой заданной строки.

from nlp_primitives import LSA
import pandas as pd
data = ["hello, this is a new featuretools library",
        "this will add new natural language primitives",
        "we hope you like it!"]
lsa = LSA()
pd.DataFrame(lsa(data).tolist()).T

В следующем примере примитив PartOfSpeechCount генерирует 15 значений для каждого ввода. Каждое измерение этого вектора представляет часть речи, и количество раз, когда эта часть речи появляется в текстовом поле ввода.

from nlp_primitives import PartOfSpeechCount
data = ["hello, this is a new featuretools library",
        "this will add new natural language primitives",
        "we hope you like it!"]
pscount = PartOfSpeechCount()
pd.DataFrame(pscount(data).tolist()).T

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

Однако часто бывает сложно иметь дело со многими выходами, особенно при попытке сложить примитивы в стек - чтобы использовать выходы одних примитивов в качестве входов других. Это создает больше информации, когда существует много сущностей или источников данных. Featuretools справляется с этим очень хорошо, и это позволяет пользователям собирать информацию по объектам, а также внутри них, чтобы максимально использовать имеющиеся данные. Это дополнительно дополняется способностью Featuretools автоматически складывать примитивы », что еще больше расширяет возможности любого отдельного примитивного повернутого элемента на этапе проектирования элемента.

Ключевые выводы

  1. Библиотека nlp-primitives повышает точность моделей при работе с текстовыми данными. Эта дополнительная точность связана с кодированием смысла текста, а не с простым расчетом его простых описательных показателей.
  2. Использование правильного инструмента упрощает процесс машинного обучения. Когда мы изменили несколько строк, добавив библиотеку nlp-primitives, точность повысилась, а сложность кода осталась прежней.
  3. Корректность можно оценить несколькими способами. Важно понимать, что идет не так, когда модель неточна - это просто неверно (например, базовая модель) или это неверно, но близко к правде (например, модель nlp-primitives)?

Последние мысли

Эта библиотека была выпущена и может быть установлена сама по себе или через Featuretools с использованием pip. Но он все еще находится на начальной стадии разработки, и мы будем приветствовать любые отзывы о нем. Кроме того, область обработки естественного языка быстро развивается, поэтому, если вы видите возможность добавить новый примитив, предложите это как проблему GitHub или попробуйте создать его самостоятельно - библиотека с открытым исходным кодом, так что каждый может внести свой вклад!

Первоначально опубликовано на https://blog.featurelabs.com 23 августа 2019 г.