{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":31254,"databundleVersionId":3103714,"sourceType":"competition"}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install implicit scikit-surprise --quiet\n\n# Импорт библиотек\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom scipy.sparse import csr_matrix\nfrom implicit.als import AlternatingLeastSquares\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.base import BaseEstimator, TransformerMixin\nfrom tqdm import tqdm\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Загрузка данных\ndef load_data():\n    paths = [\n        '/kaggle/input/h-and-m-personalized-fashion-recommendations/transactions_train.csv',\n        '../input/h-and-m-personalized-fashion-recommendations/transactions_train.csv'\n    ]\n    for path in paths:\n        try:\n            transactions = pd.read_csv(path, dtype={'article_id': str}, parse_dates=['t_dat'])\n            customers = pd.read_csv(path.replace('transactions_train', 'customers'))\n            articles = pd.read_csv(path.replace('transactions_train', 'articles'), dtype={'article_id': str})\n            print(f\"Данные загружены из {path}\")\n            return transactions, customers, articles\n        except:\n            continue\n    raise FileNotFoundError(\"Не удалось загрузить данные\")\n\ntransactions, customers, articles = load_data()\n\n# Быстрый EDA анализ\nprint(\"═\"*50)\nprint(f\"📊 Транзакции: {len(transactions):,} записей\")\nprint(f\"👥 Клиенты: {transactions.customer_id.nunique():,} уникальных\")\nprint(f\"👕 Товары: {transactions.article_id.nunique():,} уникальных\")\n\n# Топ-10 популярных товаров\ntop_items = transactions.article_id.value_counts().head(10)\nplt.figure(figsize=(10, 5))\nsns.barplot(x=top_items.values, y=top_items.index)\nplt.title('Топ-10 популярных товаров')\nplt.show()\n\n# Класс для предобработки данных\nclass HMDataPreprocessor(BaseEstimator, TransformerMixin):\n    def __init__(self, last_n_days=90, min_purchases=3):\n        self.last_n_days = last_n_days\n        self.min_purchases = min_purchases\n        self.popular_items = None\n        \n    def fit(self, X, y=None):\n        return self\n        \n    def transform(self, transactions):\n        # Фильтрация по дате\n        last_date = transactions.t_dat.max()\n        mask = transactions.t_dat > (last_date - pd.Timedelta(days=self.last_n_days))\n        recent_trans = transactions[mask].copy()\n        \n        # Фильтрация неактивных пользователей\n        user_counts = recent_trans.customer_id.value_counts()\n        active_users = user_counts[user_counts >= self.min_purchases].index\n        filtered_trans = recent_trans[recent_trans.customer_id.isin(active_users)]\n        \n        # Сохраняем популярные товары для холодных пользователей\n        self.popular_items = filtered_trans.article_id.value_counts().head(12).index.tolist()\n        \n        return filtered_trans\n\n# Класс для ALS модели\nclass ALSRecommender(BaseEstimator, TransformerMixin):\n    def __init__(self, factors=50, iterations=15, regularization=0.01):\n        self.factors = factors\n        self.iterations = iterations\n        self.regularization = regularization\n        self.model = None\n        self.user_map = None\n        self.item_map = None\n        self.popular_items = None  # Добавляем атрибут для хранения популярных товаров\n        \n    def fit(self, transactions, popular_items=None):  # Добавляем параметр popular_items\n        # Сохраняем популярные товары\n        self.popular_items = popular_items\n        \n        # Создание mappings\n        users = transactions.customer_id.unique()\n        items = transactions.article_id.unique()\n        \n        self.user_map = {u: i for i, u in enumerate(users)}\n        self.item_map = {a: i for i, a in enumerate(items)}\n        \n        # Построение sparse матрицы\n        rows = [self.user_map[u] for u in transactions.customer_id]\n        cols = [self.item_map[a] for a in transactions.article_id]\n        data = np.ones(len(transactions))\n        \n        interactions = csr_matrix((data, (rows, cols)), shape=(len(users), len(items)))\n        \n        # Обучение модели\n        self.model = AlternatingLeastSquares(\n            factors=self.factors,\n            iterations=self.iterations,\n            regularization=self.regularization,\n            random_state=42\n        )\n        self.model.fit(interactions)\n        \n        return self\n    \n    def recommend(self, customer_ids, k=12):\n        \"\"\"Генерация рекомендаций для списка пользователей\"\"\"\n        if self.popular_items is None:\n            raise ValueError(\"Popular items not set. Please provide popular items during fit.\")\n            \n        all_recs = []\n        item_ids = np.arange(len(self.item_map))\n        \n        for customer_id in tqdm(customer_ids, desc=\"Генерация рекомендаций\"):\n            if customer_id in self.user_map:\n                user_idx = self.user_map[customer_id]\n                scores = self.model.user_factors[user_idx] @ self.model.item_factors.T\n                top_items = np.argsort(-scores)[:k]\n                recs = [list(self.item_map.keys())[i] for i in top_items]\n            else:\n                recs = self.popular_items[:k]  # Используем сохраненные популярные товары\n            \n            all_recs.append(' '.join(recs))\n        \n        return pd.DataFrame({'customer_id': customer_ids, 'prediction': all_recs})\n\n# Создание и обучение пайплайна\nprint(\"🛠 Подготовка данных и обучение модели...\")\npreprocessor = HMDataPreprocessor(last_n_days=180)\nfiltered_trans = preprocessor.fit_transform(transactions)\n\n# Получаем популярные товары из препроцессора\npopular_items = preprocessor.popular_items\n\nmodel = ALSRecommender(factors=64, iterations=20)\nmodel.fit(filtered_trans, popular_items=popular_items)  # Передаем популярные товары\n\n# Генерация рекомендаций (для демонстрации 10% пользователей)\nsample_customers = customers.sample(frac=0.1, random_state=42).customer_id\nsubmission = model.recommend(sample_customers)\n\n# Сохранение и анализ результатов\nsubmission.to_csv('submission_als.csv', index=False)\nprint(\"✅ Сабмит сохранен как submission_als.csv\")\n\n# Визуализация рекомендаций\nplt.figure(figsize=(10, 6))\nrec_counts = submission.prediction.str.split().explode().value_counts().head(20)\nsns.barplot(y=rec_counts.index, x=rec_counts.values)\nplt.title('Самые часто рекомендуемые товары')\nplt.xlabel('Количество рекомендаций')\nplt.show()\n\n# Пример рекомендаций\nprint(\"\\nПример рекомендаций для 3 пользователей:\")\nfor i in range(3):\n    user_id = submission.iloc[i].customer_id\n    items = submission.iloc[i].prediction.split()\n    print(f\"\\n👤 {user_id}:\")\n    print(articles[articles.article_id.isin(items)][['article_id', 'prod_name']].to_string(index=False))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-04T10:43:36.852934Z","iopub.execute_input":"2025-04-04T10:43:36.853433Z","iopub.status.idle":"2025-04-04T11:02:35.040289Z","shell.execute_reply.started":"2025-04-04T10:43:36.853399Z","shell.execute_reply":"2025-04-04T11:02:35.038901Z"}},"outputs":[],"execution_count":null}]}