{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\ninput_trans = '/kaggle/input/h-and-m-personalized-fashion-recommendations/'\ninput_eda = '/kaggle/input/eda-analysis/'","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-03-29T09:29:39.324186Z","iopub.execute_input":"2022-03-29T09:29:39.324562Z","iopub.status.idle":"2022-03-29T09:29:39.350139Z","shell.execute_reply.started":"2022-03-29T09:29:39.324474Z","shell.execute_reply":"2022-03-29T09:29:39.349437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transactions_path = input_trans + 'transactions_train.csv'\ntransactions = pd.read_csv(transactions_path, parse_dates=['t_dat'])\ntransactions.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-29T09:29:41.711584Z","iopub.execute_input":"2022-03-29T09:29:41.711991Z","iopub.status.idle":"2022-03-29T09:30:45.963180Z","shell.execute_reply.started":"2022-03-29T09:29:41.711961Z","shell.execute_reply":"2022-03-29T09:30:45.962599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"articles_by_customers = transactions.groupby('customer_id').article_id.apply(set).to_dict()\narticles_popularity = transactions.groupby('article_id').customer_id.nunique().sort_values(ascending=False)\nmost_popular = articles_popularity.index","metadata":{"execution":{"iopub.status.busy":"2022-03-29T09:45:00.454759Z","iopub.execute_input":"2022-03-29T09:45:00.455091Z","iopub.status.idle":"2022-03-29T09:46:08.575989Z","shell.execute_reply.started":"2022-03-29T09:45:00.455045Z","shell.execute_reply":"2022-03-29T09:46:08.575084Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"art_path = input_eda + 'scaled_articles.csv'\ncust_path = input_eda + 'scaled_customers.csv'\nscaled_articles = pd.read_csv(art_path, index_col='article_id')\nscaled_customers = pd.read_csv(cust_path, index_col='customer_id')","metadata":{"execution":{"iopub.status.busy":"2022-03-29T09:47:25.998002Z","iopub.execute_input":"2022-03-29T09:47:25.998603Z","iopub.status.idle":"2022-03-29T09:47:28.912825Z","shell.execute_reply.started":"2022-03-29T09:47:25.998558Z","shell.execute_reply":"2022-03-29T09:47:28.911790Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.neighbors import NearestNeighbors\n\nNR_PREDS = 12\n\nmodel_art = NearestNeighbors(n_neighbors=NR_PREDS, n_jobs=-1).fit(scaled_articles)\nmodel_cust = NearestNeighbors(n_neighbors=NR_PREDS, n_jobs=-1).fit(scaled_customers)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T09:48:27.566616Z","iopub.execute_input":"2022-03-29T09:48:27.567118Z","iopub.status.idle":"2022-03-29T09:48:30.449393Z","shell.execute_reply.started":"2022-03-29T09:48:27.567069Z","shell.execute_reply":"2022-03-29T09:48:30.448503Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds_art = model_art.kneighbors(scaled_articles)\npreds_cust = model_cust.kneighbors(scaled_customers)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dists_articles = pd.DataFrame(preds_art[0], index=scaled_articles.index)\nsimilar_articles = pd.DataFrame([[dists_articles.index[x] for x in y] for y in preds_art[1]], index=scaled_articles.index)\n\n\ndists_users = pd.DataFrame(preds_cust[0], index=scaled_customers.index)\nsimilar_users = pd.DataFrame([[dists_users.index[x] for x in y] for y in preds_cust[1]], index=scaled_customers.index)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Take the predictions based on articles and users and compute the distance metric between each entity (article or customer) and their closest neighbours. Used for sorting in order to choose the articles to recommend to each user.","metadata":{}},{"cell_type":"code","source":"choices = {}\nfor customer in scaled_customers.index:\n    if customer not in articles_by_customers:\n        choices[customer] = most_popular[:NR_PREDS]\n    else:\n        similar_to_bought = set()\n        for article_id in articles_by_customers[customer]:\n            similar_to_bought.update(list(zip(dists_articles.loc[article_id].to_list(), similar_articles.loc[article_id].to_list())))\n        similar_to_bought = sorted(list(similar_to_bought), key=lambda x: x[0])\n        customer_choices = []\n        for _, article in similar_to_bought:\n            if article not in customer_choices and article not in articles_by_customers[customer]:\n                customer_choices.append(article)\n                if len(customer_choices) == NR_PREDS:\n                    break\n        if len(customer_choices) < NR_PREDS:\n            for _, article in similar_to_bought:\n                if article not in customer_choices:\n                    customer_choices.append(article)\n                    if len(customer_choices) == NR_PREDS:\n                        break\n        if len(customer_choices) < NR_PREDS:\n            for article in most_popular:\n                if article not in customer_choices:\n                    customer_choices.append(article)\n                    if len(customer_choices) == NR_PREDS:\n                        break\n        choices[customer] = customer_choices\n\npd.DataFrame({'customer_id': choices.keys(), 'prediction': list(' '.join(map(str, x)) for x in choices.values())}).to_csv('submission_art.csv', index=False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Articles based selection: for each customer, we select the bought articles and look for the ones similar to them. We sort them by similarity with the original ones and select the most similar 12 that the customer hasn't bought (if that's not possible, we'll also add bought articles to get 12 predictions, if that's also not enough, we'll add from the most_popular list)","metadata":{}},{"cell_type":"code","source":"choices = {}\nfor customer in scaled_customers.index:\n    customer_choices = []\n    for sim_user in similar_users.loc[customer]:\n        if sim_user in articles_by_customers:\n            for article in articles_by_customers[sim_user]:\n                if article not in customer_choices and article not in articles_by_customers.get(customer, set()):\n                    customer_choices.append(article)\n                    if len(customer_choices) == NR_PREDS:\n                        break\n            if len(customer_choices) == NR_PREDS:\n                break\n    if len(customer_choices) < NR_PREDS:\n        for article in most_popular:\n            if article not in customer_choices:\n                customer_choices.append(article)\n                if len(customer_choices) == NR_PREDS:\n                    break\n    choices[customer] = customer_choices\n\n\npd.DataFrame({'customer_id': choices.keys(), 'prediction': list(' '.join(map(str, x)) for x in choices.values())}).to_csv('submission_cust.csv', index=False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Customer based selection: for each customer, we select the most similar customers and look for products that our customer hasn't bought. If we can't find 12 such products, we'll add from the list of the most popular ones.","metadata":{}}]}