Проблема
В нашем продукте (сочетании поисковой системы для электронной коммерции и торговой площадки) нам приходится ежедневно модерировать множество данных, собранных из различных источников. Различные типы данных для нескольких вариантов использования. Одним из таких случаев является модерация торговых марок. Продавцы, как правило, используют буквально что угодно в качестве названия бренда в своих потоках данных. С другой стороны, мы хотим предоставить нашим покупателям удобный пользовательский интерфейс и отфильтровать ненужные названия брендов в пользовательском интерфейсе.
На данный момент мы собрали множество «строк», которые помечены как «бренд»/«не бренд» в нашей базе данных, и у нас появилась идея использовать эти данные для лучшей поддержки модерации (прогнозирования предполагаемого результата модерации). ).
Данные
В нашем эксперименте мы будем использовать 30 000 строк, помеченных как «одобренные» (подлинный бренд), и 30 000 строк, помеченных как «черный список» (плохое название бренда). Мы вычислим различные числовые характеристики для каждой строки и сохраним их в виде CSV-файла.
К сожалению, я не могу поделиться набором данных, но надеюсь, что основные принципы разработки признаков, которые были выполнены на данных, понятны. Хорошую статью о разработке функций вы можете найти, перейдя по ссылке ниже.
Модель
Мы решили попробовать поиграть с логистической регрессией для бинарной классификации (бренд/небренд).
import pandas as pd features = ['number_of_characters', 'number_of_unique_characters', 'number_of_alnum_characters', 'number_of_numeric_characters', 'number_of_capital_characters', 'number_of_commas', 'pct_of_alnum_characters', 'pct_of_numeric_characters', 'pct_of_capital_characters', 'pct_of_unique_tokens', 'pct_of_commas', 'pct_of_unique_characters', 'number_of_tokens', 'number_of_unique_tokens'] columns = ['status', ] + features data = pd.read_csv("nr2.txt", header=None, names=columns) data.head()
Затем мы определяем, в каком столбце хранится прогнозируемое значение, а в каких — функции.
X = data[features] # features y = data.status # actual class
Нам нужно разделить наш набор данных на две части — обучающую (75% данных) и тестовую (25% данных).
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=16)
Наконец, мы готовы обучить нашу модель.
from sklearn.linear_model import LogisticRegression model = LogisticRegression(random_state=16) model.fit(X_train.values, y_train)
Вы можете проверить, насколько «хороша» наша модель в классификации потенциальных названий брендов и какие веса модель «выучила» для наших функций.
Тест
Я протестирую двух кандидатов: «98,5% katoen, 1,5% elastaan Kleur» (фактическая строка, отправленная продавцами в наш пайплайн в качестве значения атрибута бренда продукта) и «Apple».
Особенности этих строк:
[33, 18, 24, 5, 1, 3, 0.73, 0.15, 0.03, 1.0, 0.09, 0.55, 5, 5] [5, 4, 5, 0, 1, 0, 1.0, 0.0, 0.2, 1.0, 0.0, 0.8, 1, 1]
Хорошо, но насколько хороша ваша модель в этих прогнозах?
Ручная проверка случайной строки — хороший подход, но насколько хороша модель в масштабе? Мы проверим несколько стандартных показателей, используемых для классификаторов оценки, чтобы измерить это.
from sklearn.metrics import classification_report target_names = ['brand', 'not brand'] print(classification_report(y_test, y_pred, target_names=target_names))
Эти цифры по всем показателям можно считать очень хорошими.
Подробнее о показателях:
https://en.wikipedia.org/wiki/Precision_and_recall
https://en.wikipedia.org/wiki/F-score
Матрица
Еще один способ измерить качество классификатора — запутанная матрица.
from sklearn import metrics y_pred = model.predict(X_test.values) matrix = metrics.confusion_matrix(y_test, y_pred) print(matrix)
Для визуализации матрицы мы можем построить график.
import numpy as np import matplotlib.pyplot as plt import seaborn as sns class_names = ['brand', 'not brand'] fig, ax = plt.subplots() tick_marks = np.arange(len(class_names)) plt.xticks(tick_marks, class_names) plt.yticks(tick_marks, class_names) sns.heatmap(pd.DataFrame(matrix), annot=True, cmap="YlGnBu", fmt='g') ax.xaxis.set_label_position("top") plt.tight_layout() plt.title('Confusion matrix', y=1.1) plt.ylabel('Actual label') plt.xlabel('Predicted label') plt.show()
https://en.wikipedia.org/wiki/Confusion_matrix
Кривая ROC
y_pred_proba = model.predict_proba(X_test)[::,1] fpr, tpr, _ = metrics.roc_curve(y_test, y_pred_proba, pos_label='blacklisted') auc = metrics.roc_auc_score(y_test, y_pred_proba) plt.plot(fpr,tpr,label="data 1, auc="+str(auc)) plt.legend(loc=4) plt.show()
Результат просто отличный (по словам моей жены, которая является настоящим ученым-статистиком)…
Подробнее об этом https://en.wikipedia.org/wiki/Receiver_operating_characteristic
Как запустить в производство?
ИМО, это будет самая утомительная и очевидная часть статьи. Давай засолим!
import pickle filename = 'brands_classifier.sav' pickle.dump(model, open(filename, 'wb'))
Например, вы можете сохранить полученный файл в S3, а затем загрузить/использовать его в своем веб-сервисе Flask/Sanic/FastAPI, в своем процессоре Faust для потока Kafka и т. д. Оставьте комментарий, если хотите, чтобы об этом была отдельная запись в блоге.
import pickle filename = 'brands_classifier.sav' loaded_model = pickle.load(open(filename, 'rb')) loaded_model.predict([[29,18,26,0,2,1,0.9,0.0,0.07,1.0,0.03,0.62,3,3]])