{"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":"import numpy as np\nimport pandas as pd\n\nfrom math import sqrt\nfrom pathlib import Path\nfrom tqdm import tqdm\ntqdm.pandas()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-04-17T04:03:46.802188Z","iopub.execute_input":"2022-04-17T04:03:46.802573Z","iopub.status.idle":"2022-04-17T04:03:46.806714Z","shell.execute_reply.started":"2022-04-17T04:03:46.802542Z","shell.execute_reply":"2022-04-17T04:03:46.805963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_path = Path('../input/reduced25')\nN = 12","metadata":{"execution":{"iopub.status.busy":"2022-04-17T04:03:46.812639Z","iopub.execute_input":"2022-04-17T04:03:46.813367Z","iopub.status.idle":"2022-04-17T04:03:46.826522Z","shell.execute_reply.started":"2022-04-17T04:03:46.813319Z","shell.execute_reply":"2022-04-17T04:03:46.825645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Read the transactions data","metadata":{}},{"cell_type":"code","source":"df = pd.read_csv(data_path / 'transactions25short.csv',\n                 usecols = ['t_dat', 'customer_id', 'article_id'],\n                 dtype={'article_id': str})\n\ndf['t_dat'] = pd.to_datetime(df['t_dat'])\nlast_ts = df['t_dat'].max()","metadata":{"execution":{"iopub.status.busy":"2022-04-17T04:03:46.833158Z","iopub.execute_input":"2022-04-17T04:03:46.833579Z","iopub.status.idle":"2022-04-17T04:03:47.640064Z","shell.execute_reply.started":"2022-04-17T04:03:46.833547Z","shell.execute_reply":"2022-04-17T04:03:47.639294Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Add the last day of billing week","metadata":{}},{"cell_type":"code","source":"df['ldbw'] = df['t_dat'].progress_apply(lambda d: last_ts - (last_ts - d).floor('7D'))\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2022-04-17T04:03:47.641505Z","iopub.execute_input":"2022-04-17T04:03:47.641703Z","iopub.status.idle":"2022-04-17T04:04:24.863686Z","shell.execute_reply.started":"2022-04-17T04:03:47.641679Z","shell.execute_reply":"2022-04-17T04:04:24.862848Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Count the number of transactions per week ","metadata":{}},{"cell_type":"code","source":"weekly_sales = df.drop('customer_id', axis=1).groupby(['ldbw', 'article_id']).count()\nweekly_sales = weekly_sales.rename(columns={'t_dat': 'count'})\nweekly_sales.head()","metadata":{"execution":{"iopub.status.busy":"2022-04-17T04:04:24.864930Z","iopub.execute_input":"2022-04-17T04:04:24.865542Z","iopub.status.idle":"2022-04-17T04:04:25.012315Z","shell.execute_reply.started":"2022-04-17T04:04:24.865496Z","shell.execute_reply":"2022-04-17T04:04:25.011282Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = df.join(weekly_sales, on=['ldbw', 'article_id'], lsuffix='_left', rsuffix='_right')\nprint(df)\ndf['count'].value_counts().hist();","metadata":{"execution":{"iopub.status.busy":"2022-04-17T04:04:25.014546Z","iopub.execute_input":"2022-04-17T04:04:25.014963Z","iopub.status.idle":"2022-04-17T04:04:25.351439Z","shell.execute_reply.started":"2022-04-17T04:04:25.014907Z","shell.execute_reply":"2022-04-17T04:04:25.350559Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Let's assume that in the target week sales will be similar to the last week of the training data","metadata":{}},{"cell_type":"code","source":"weekly_sales = weekly_sales.reset_index().set_index('article_id')\nlast_day = last_ts.strftime('%Y-%m-%d')\n\ndf = df.join(\n    weekly_sales.loc[weekly_sales['ldbw']==last_day, ['count']],\n    on='article_id', rsuffix=\"_targ\")\n\ndf['count_targ'].fillna(0, inplace=True)\ndel weekly_sales","metadata":{"execution":{"iopub.status.busy":"2022-04-17T04:04:25.352692Z","iopub.execute_input":"2022-04-17T04:04:25.353073Z","iopub.status.idle":"2022-04-17T04:04:25.450281Z","shell.execute_reply.started":"2022-04-17T04:04:25.353009Z","shell.execute_reply":"2022-04-17T04:04:25.449366Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Calculate sales rate adjusted for changes in product popularity ","metadata":{}},{"cell_type":"code","source":"df['quotient'] = df['count_targ'] / df['count']","metadata":{"execution":{"iopub.status.busy":"2022-04-17T04:04:25.453040Z","iopub.execute_input":"2022-04-17T04:04:25.455288Z","iopub.status.idle":"2022-04-17T04:04:25.463787Z","shell.execute_reply.started":"2022-04-17T04:04:25.455244Z","shell.execute_reply":"2022-04-17T04:04:25.462385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Take supposedly popular products","metadata":{}},{"cell_type":"code","source":"target_sales = df.drop('customer_id', axis=1).groupby('article_id')['quotient'].sum()\ngeneral_pred = target_sales.nlargest(N).index.tolist()\ndel target_sales","metadata":{"execution":{"iopub.status.busy":"2022-04-17T04:04:25.465532Z","iopub.execute_input":"2022-04-17T04:04:25.465922Z","iopub.status.idle":"2022-04-17T04:04:25.561919Z","shell.execute_reply.started":"2022-04-17T04:04:25.465875Z","shell.execute_reply":"2022-04-17T04:04:25.561084Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Fill in purchase dictionary","metadata":{}},{"cell_type":"code","source":"purchase_dict = {}\n\nfor i in tqdm(df.index):\n    cust_id = df.at[i, 'customer_id']\n    art_id = df.at[i, 'article_id']\n    t_dat = df.at[i, 't_dat']\n\n    if cust_id not in purchase_dict:\n        purchase_dict[cust_id] = {}\n\n    if art_id not in purchase_dict[cust_id]:\n        purchase_dict[cust_id][art_id] = 0\n    \n    x = max(1, (last_ts - t_dat).days)\n\n    a, b, c, d = 2.5e4, 1.5e5, 2e-1, 1e3\n    y = a / np.sqrt(x) + b * np.exp(-c*x) - d\n\n    value = df.at[i, 'quotient'] * max(0, y)\n    purchase_dict[cust_id][art_id] += value","metadata":{"execution":{"iopub.status.busy":"2022-04-17T04:04:25.563507Z","iopub.execute_input":"2022-04-17T04:04:25.563800Z","iopub.status.idle":"2022-04-17T04:04:40.108712Z","shell.execute_reply.started":"2022-04-17T04:04:25.563760Z","shell.execute_reply":"2022-04-17T04:04:40.107388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Make a submission","metadata":{}},{"cell_type":"code","source":"sub = pd.read_csv('../input/reduced25/customers25short.csv')\n\npred_list = []\nfor cust_id in tqdm(sub['customer_id']):\n    if cust_id in purchase_dict:\n        series = pd.Series(purchase_dict[cust_id])\n        series = series[series > 0]\n        l = series.nlargest(N).index.tolist()\n        if len(l) < N:\n            l = l + general_pred[:(N-len(l))]\n    else:\n        l = general_pred\n    pred_list.append(' '.join(l))\n\nsub['prediction'] = pred_list\nsub.to_csv('default_submission.csv', index=None)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-04-17T04:04:40.109763Z","iopub.execute_input":"2022-04-17T04:04:40.109969Z","iopub.status.idle":"2022-04-17T04:04:40.428972Z","shell.execute_reply.started":"2022-04-17T04:04:40.109944Z","shell.execute_reply":"2022-04-17T04:04:40.428213Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}