Время прочтения: 4 мин.
Для задач NLP, как мы знаем, недостаточно положить в модель голый текст. Датасет возьмем с кеггла (https://www.kaggle.com/rishisankineni/text-similarity) — оставим тренировочную часть и попробуем предобработать данные для наших моделей. Надеюсь, это моя не последняя статья и далее мы разберем уже конкретные модели, но сегодня остановимся на предобработке.
Импортируем нужные библиотеки и создаем Спарк-сессию:
from pyspark.sql import SparkSession
import pyspark.sql.functions as f
spark = SparkSession.builder \
.master("local[*]") \
.appName('testForNTA') \
.getOrCreate()
Возьмем данные с соревнования по определению тональности текстов. Загружаем датасет (подробнее о работе с данными и их загрузке можно прочитать в первой статье):
df = spark.read.format('csv') \
.option('header', True) \
.load('text-similarity.csv')
Для переименования столбца можем сделать его select, выделить нужный столбец и сопоставить нужный alias. Переименуем наш столбец description_x для удобства в text:
df = df.select(f.col('description_x').alias('text'))
Посмотрим на наши данные:
df.show(5, vertical = True)
Для начала рассмотрим разбивку на токены и TF-IDF (тк у нас ознакомительная статья, разбирать это не будем, ознакомиться с математическим смыслом можно тут: https://ru.wikipedia.org/wiki/TF-IDF). Импортируем нужные библиотеки:
from pyspark.ml.feature import HashingTF, IDF, Tokenizer
В следующем сегменте кода мы начинаем с набора предложений. Мы разбиваем каждое предложение на слова, используя Tokenizer. Для каждого предложения (набора слов) мы используем HashingTFхеширование предложения в вектор признаков. Мы используем IDFдля масштабирования векторов признаков; это обычно повышает производительность при использовании текста в качестве функций. Затем наши векторы признаков можно было бы передать алгоритму обучения.
Перейдем к коду, начнем с набора текста. Разобъем кадлное предложение на слова, используя Tokenizer.
Давайте разобьем наш текст на отдельные токены и запишем их в столбец text_words. В Tokenizer передаем столбец входных данных и название результирующего столбца. Далее с помощью transform модифицируем наши данные:
tokenizer = Tokenizer(inputCol = 'text', outputCol = 'text_words')
data_words = tokenizer.transform(df)
data_words.show(5)
Все верно, но по-хорошему надо было бы сделать предобработку и удалить ненужные символы, но статья не об этом.
Далее используем хеширование в вектор признаков, для масштабирования используем IDF, затем наши признаки можно было бы передавать алгоритму машинного обучения.
hash_tf = HashingTF(inputCol = 'text_words', outputCol = 'text_words_features', numFeatures = 20)
data_featurized = hash_tf.transform(data_words)
data_featurized.show(5)
В features запишем конечный результат:
idf = IDF(inputCol = 'text_words_features', outputCol = 'features')
idf_model = idf.fit(data_featurized)
data_scaled = idf_model.transform(data_featurized)
Посмотрим на результат:
data_scaled.show(5)
Давайте разберем еще один метод предобработки — Word2Vec. Почитать подробнее можно тут: https://ru.wikipedia.org/wiki/Word2vec Он преобразует каждое слово в уникальные вектор заданного размера. По сути, на выходе мы получаем векторное представление слов на естественном языке. После этого мы можем использовать, допустим, для расчета сходства документов или других NLP-задач. Давайте обработаем наш текст, импортируем нужное, важное и загрузим датасет заново.
from pyspark.ml.feature import Word2Vec
df = spark.read.format('csv') \
.option('header', True) \
.load('text-similarity.csv')
df = df.select(f.col('description_x').alias('text'))
Разбить текст можем и обычным сплитом, создадим 1 колонку:
df = df.withColumn('text_list', (f.split(df['text'], ' ')))
При создании Word2Vec можем задать размерность нашего вектора, давайте сделаем его равным 3:
word2Vec = Word2Vec(vectorSize = 3, minCount = 0, inputCol = 'text_list', outputCol = 'result')
model = word2Vec.fit(df)
result = model.transform(df)
Давайте проверим результат:
result.show(5)
Убедимся, что в колонке result лежат трехмерные вектора:
result.take(1)[0]['result']
Отлично, все получилось.
Перейдем к следующему методу — CountVectorizer, о нем читаем тут: https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html Он помогает преобразовать набор документов (текствовых), в векторы количества токенов с этом тексте. Модель создает разреженную матрицу для наших документов.
Если кратко, на выходе мы получаем таблицу со столбцами-словами, которые встречаются в тексте, а на пересечении, соответственно, их количество в определенном тексте. Импортируем нужное.
from pyspark.ml.feature import CountVectorizer
df = spark.read.format('csv') \
.option('header', True) \
.load('text-similarity.csv')
df = df.select(f.col('description_x').alias('text'))
df = df.withColumn('text_list', (f.split(df['text'], ' ')))
Необязательный параметр minDFтакже влияет на процесс подбора, указывая минимальное количество (или долю, если < 1,0) документов, в которых термин должен появиться, чтобы быть включенным в словарь.
Заполним столбцы на входе и на выходе:
cv = CountVectorizer(inputCol = 'text_list', outputCol = 'features')
model = cv.fit(df)
result = model.transform(df)
result.show(5, vertical = True)
Давайте посмотрим на первую строчку. Она состоит из двух разных слов, соответственно, в разреженной матрице должно быть две единички и остальные нули.
result.take(1)[0]['features']
Отлично, получили две единички.
Сегодня мы рассмотрели базовые методы предобработки данных для моделей машинного обучения. Наверное, это некий бейзлайн, без которого не получится поработать с текстом.
Не забудьте остановить спарк-сессию.
spark.stop()