{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Открытый курс по машинному обучению\n", "
Автор: [Дмитрий Дрёмов](https://www.kaggle.com/dremovd)\n", " \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Простой бенчмарк в соревновании по категоризации покупок\n", "\n", "[Kaggle Inclass](https://www.kaggle.com/c/receipt-categorisation) и отдельная [ссылка](https://www.kaggle.com/t/73f1a2eb0be9443ba1f8d2f283adc444) для участия. Недавно на чеках появились QR коды. Пока еще не все с этим знакомы, но по информации из этого кода можно получить полное содержание чека. Это дает возможность вести расходы, учитывая каждый отдельный товар, включая расходы, сделанные наличными. Как следствие наличия полной информации, можно анализировать изменения характера расходов и инфляцию по собственной продуктовой корзине. Названия товаров не стандартизованы: у одного товара в разных магазинах существенно отличаются названия; отдельные слова могут сокращаться; названия могут содержать опечатки. В магазины постоянно добавляются новые товары. Это делает простое составление каталога всех товаров с категориями нереалистичным.\n", "\n", "Данные публикуются впервые, а обученные на них модели используются в [production](https://play.google.com/store/apps/details?id=com.dremovd.fnschecks&hl=ru). Задача, которую предлагается решить — это разбиение всех покупок чека по небольшому набору понятных человеку категорий." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "import pandas as pd\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Загрузка данных" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "PATH_TO_DATA = 'data'\n", "RANDOM_STATE = 17" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!ls $PATH_TO_DATA" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "train = pd.read_csv(os.path.join(PATH_TO_DATA, 'train.csv.gz'))\n", "train_checks = pd.read_csv(os.path.join(PATH_TO_DATA, 'train_checks.csv.gz'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(train.shape, train_checks.shape)\n", "print(train.columns.values)\n", "print(train_checks.columns.values)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "train.fillna('', inplace=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Подготовка данных" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.feature_extraction.text import CountVectorizer\n", "\n", "vectorizer = CountVectorizer()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X = vectorizer.fit_transform(train.name)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i, word in enumerate(vectorizer.vocabulary_):\n", " print(word)\n", " if i > 10:\n", " break" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X.shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.preprocessing import LabelEncoder\n", "\n", "labeler = LabelEncoder()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "y = labeler.fit_transform(train.category)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Валидация" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.linear_model import LogisticRegression\n", "from sklearn.model_selection import cross_val_score\n", "from sklearn.model_selection import GroupShuffleSplit\n", "\n", "gkf = list(GroupShuffleSplit(n_splits=5, random_state=RANDOM_STATE).split(X, y, train.check_id.values))\n", "score = cross_val_score(LogisticRegression(random_state=RANDOM_STATE), X, y, scoring='neg_log_loss',\n", " cv=gkf, n_jobs=-1)\n", "\"%.3f +- %.4f\" % (-np.mean(score), np.std(score))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Подготовка сабмита" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model = LogisticRegression(random_state=RANDOM_STATE)\n", "model.fit(X, y)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test = pd.read_csv(os.path.join(PATH_TO_DATA, 'test.csv.gz'))\n", "test_checks = pd.read_csv(os.path.join(PATH_TO_DATA, 'test_checks.csv.gz'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X_test = vectorizer.transform(test.name)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "p_test = model.predict_proba(X_test)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test = test[['id']]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i, c in enumerate(labeler.classes_):\n", " test[c] = list(map(lambda x: '%.3f' % x, p_test[:, i]))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test.to_csv('base_solution.csv.gz', compression='gzip', index = False, encoding='utf-8')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "У такой посылки результат – 0.65081 в [публичном рейтинге](https://www.kaggle.com/c/receipt-categorisation/leaderboard) соревнования, бенчмарк \"Стартер\"." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.1" } }, "nbformat": 4, "nbformat_minor": 2 }