{"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":"markdown","source":"# Introduction:\n\n* Session = user, Aid = product\n\nThe competition's objective is to predict e-commerce clicks, cart additions, and orders using information from previous user session events. There are three types of interactions and 1671803 unique sessions overall (Clicks, Carts and Orders). Therefore, 5015409 predictions (1671803*3) would be made.\n\nDetails could be found in this page: https://www.kaggle.com/competitions/otto-recommender-system/overview/evaluation\n\n# In short: \n\nThe only product that needs to be predicted for the click prediction is the **next one** the user will click, for instances: aid1. However, we can submit a list of up to 20 products for prediction; **as long as aid1 is on the list, the score will be awarded.**\n\nWe could also submit a list of products (maximum 20) for prediction for cart and orders.  For example, the user adds **30** products into **cart**, and **order 3** products.\n\nThe maximum size of a prediction is 20, so **even though there are 30 products in the cart, the full score can still be obtained as long as every item on the prediction list appears in the cart**.\n\nSince 3 products were ordered, I can still **receive a full score as long as all three appear on the prediction list.**\n\n# Result:\n\nObtained a very low score","metadata":{}},{"cell_type":"markdown","source":"# Method:\n\nI would predict the next aid(s) by constructing a co-visitaion table and also the last 10 aids that the users have interacted with.\n","metadata":{}},{"cell_type":"code","source":"print('Start')\n\n!pip install polars\nimport polars as pl\n#import os\n#import numpy as np\nimport sys\nimport gc\nimport pandas as pd\nfrom tqdm import tqdm\nfrom collections import defaultdict, Counter\nimport dill\nimport pickle\nfrom itertools import chain\n\n#Load Data\ntrain = pl.read_parquet('/kaggle/input/otto-full-optimized-memory-footprint/train.parquet')\nconvertlist = ['clicks','carts','orders']\nprint('Finish')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Covisitation function","metadata":{}},{"cell_type":"code","source":"def getcovisitation(dataset, bywhich_num,guesswhich_num,timedelta,sample_size = 0):\n    aidcount = defaultdict(Counter)\n    totalrow = dataset.shape[0]\n    bywhich = convertlist[bywhich_num]\n    guesswhich = convertlist[guesswhich_num]\n    print(\"Start_\"+str(bywhich)+'_'+str(guesswhich))\n    for j in tqdm(range(0, totalrow, chunk_size)):\n        covisit_train_seg = dataset[j:min(totalrow-1, j+chunk_size-1)]\n        covisit_train_seg = covisit_train_seg.join(covisit_train_seg,on = \"session\",how=\"inner\").filter((pl.col(\"aid\")!=pl.col(\"aid_right\"))&(pl.col('type')==bywhich_num)&(pl.col('type_right')==guesswhich_num)&(pl.col('ts_right')>pl.col('ts'))&((pl.col('ts_right')-pl.col('ts'))<timedelta))\n        covisit_train_seg = covisit_train_seg.unique(subset = ['session','aid','aid_right']).drop_nulls()\n        \n        if sample_size != 0:\n            covisit_train_seg = covisit_train_seg.groupby('session').agg([\n                pl.all().sample(n=sample_size)\n                ]).explode(['aid','aid_right'])\n            covisit_train_seg = covisit_train_seg.drop_nulls()\n            \n        for aid_x, aid_y in zip(covisit_train_seg[\"aid\"],covisit_train_seg[\"aid_right\"]):\n            aidcount[aid_x][aid_y] += 1\n    with open(str(bywhich)+'_'+str(guesswhich) +'_covisitation.pkl', 'wb') as f:\n        dill.dump(aidcount, f)\n    print(\"End_\"+str(bywhich)+'_'+str(guesswhich))\n    return \n\ntimedelta = 8*60*60\nchunk_size = 500000\n\n                                                                                                        \n                                                                                                ","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create Covisitation\nfor bywhich_num in range(3):\n    for guesswhich_num in range(3):\n        getcovisitation(train, bywhich_num,guesswhich_num,timedelta)\n        \n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prediction","metadata":{}},{"cell_type":"code","source":"## Create Strong Aids Table for cold-start users, and recommend the hot items (highest count of items' interactions)\n\ndef strongaids(typenum):\n    typeconvert = convertlist[typenum]\n    strong_order = train.filter((pl.col(\"type\")==typenum))\n    strong_order = strong_order.groupby(\"aid\").agg([pl.col('aid').count().alias('count_final')]).sort('count_final',reverse=True)\n    strong_order = strong_order.with_columns(pl.col('aid').cast(pl.Utf8, strict=False))\n    strong_order.write_parquet(\"strong_\"+str(typeconvert)+\".parquet\")\n        \nfor i in range(3):\n    strongaids(i)\nprint(\"finish\")\n        ","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# # # # Load Data\n\ntest = pl.read_parquet('/kaggle/input/otto-full-optimized-memory-footprint/test.parquet').sort('ts',reverse=True).unique(subset=[\"session\",\"aid\"]).drop('ts')\ntest_order = test.filter(pl.col('type')==2).drop('type').groupby('session').agg_list()\ntest_cart = test.filter(pl.col('type')==1).drop('type').groupby('session').agg_list()\ntest_click = test.filter(pl.col('type')==0).drop('type').groupby('session').agg_list()\n\nsessionlist_order = test_order['session'].to_list()\nsessionlist_cart = test_cart['session'].to_list()\nsessionlist_click = test_click['session'].to_list()\naidslist_order = test_order['aid'].to_list()\naidslist_cart = test_cart['aid'].to_list()\naidslist_click = test_click['aid'].to_list()\n\nprint('length of order: ',len(sessionlist_order))\nprint('length of cart: ',len(sessionlist_cart))\nprint('length of click',len(sessionlist_click))\n\n                        \n## Last nth actions of each session to pickle\ntestpd = pd.read_parquet('/kaggle/input/otto-full-optimized-memory-footprint/test.parquet')\nlastaction_raw = testpd.sort_values([\"session\", \"type\", \"ts\"]).groupby([\"session\"]).apply(\n    lambda x: x.tail(20).aid.tolist().drop('type').drop('ts')\n    )\n\n#del test,test_order,test_cart,test_click","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Function Part\n\ndef gettop20(covisitation,aids,strongaid,strongaid_list,weighting=1):\n    lst = []\n    \n    for jj in aids:\n        try:\n            thedict = covisitation.get(jj, {})\n            if bool(thedict):\n                lst += thedict.most_common(20)\n        except:\n            print(\"There is a bug, this is not str\")\n\n        \n    if bool(lst):\n        commondf = pl.DataFrame()\n        commondf[['aid','count']] = pl.DataFrame(lst)\n        commondf = commondf.drop_nulls().with_columns(pl.col('aid').cast(pl.Utf8, strict=False))\n        commondf = commondf.groupby('aid').agg([pl.col('count').sum()]).sort(by='count',reverse=True).with_columns(pl.col(\"count\")*1000000)\n        commondf  = strongaid.join(commondf,on='aid')\n        \n        commondf = commondf.unique(subset=[\"aid\"]).with_columns([\n            ((pl.col(\"count_final\")/100000) + pl.col(\"count\")*weighting)\n        ]).sort(by='count_final',reverse=True)\n        \n        commondf = commondf.with_columns([pl.col('aid') + \"_\" + (pl.col('count_final'))])\n        commondf  = commondf['aid'].to_list()[:20]            \n\n    else:\n        commondf = []\n    return commondf\n\ndef predict(bywhichnum,guesswhichnum,covisitation,aidslist,sessionlist,weightinglist,strongaid,strongaid_list):\n    guesswhich = convertlist[guesswhichnum]\n    bywhich = convertlist[bywhichnum]\n    weighting = weightinglist[bywhichnum]\n    \n    suggestiondict = defaultdict(list)\n    zipped = zip(sessionlist,aidslist)\n    \n    for session,aids in zipped:\n        recommended_order = gettop20(covisitation,aids,strongaid,strongaid_list,weighting)\n        suggestiondict[str(session)+'_'+str(guesswhich)] = recommended_order\n        \n    totalsessionlist = list(suggestiondict.keys())\n    totalaidslist = list(suggestiondict.values())\n    \n    polarsdata = pd.DataFrame({'session':totalsessionlist,\"aids\":totalaidslist}) #Here change pd also if not working\n    polarsdata.to_pickle(str(bywhich)+\"_\"+str(guesswhich)+\"_predict_.pkl\")\n    return polarsdata\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create Prediction","metadata":{}},{"cell_type":"code","source":"## Prediction\n\nfor guesswhichnum in range(1):\n    guesswhich = convertlist[guesswhichnum]\n    print(guesswhich)\n    with open('/kaggle/input/folder-of-output/orders_'+str(guesswhich)+'_covisitation.pkl', 'rb') as handle:\n        orders_covisitation = pickle.load(handle)\n    print('finish1')\n    with open('/kaggle/input/folder-of-output/carts_'+str(guesswhich)+'_covisitation.pkl', 'rb') as handle:\n        carts_covisitation = pickle.load(handle)\n    print('finish2')\n    with open('/kaggle/input/folder-of-output/clicks_'+str(guesswhich)+'_covisitation.pkl', 'rb') as handle:\n        clicks_covisitation = pickle.load(handle)\n    print('finish3')\n    \n\n    lastaction['session'] = lastaction_raw['session'].astype(str) + \"_\" + str(guesswhich)\n    lastaction['aids'] = lastaction_raw['aids'].astype(str) + \"_\" + str('999')\n    \n    strongaid = pl.read_parquet('/kaggle/input/folder-of-output/strong_'+str(guesswhich)+'.parquet')\n    strongaid_list = strongaid['aid'].to_list()[:20]\n\n    print('start Final Step')\n    orders_predict = predict(2,guesswhichnum,orders_covisitation,aidslist_order,sessionlist_order,weightinglist,strongaid,strongaid_list)\n    print('finish order')\n    carts_predict = predict(1,guesswhichnum,carts_covisitation,aidslist_cart,sessionlist_cart,weightinglist,strongaid,strongaid_list)\n    print('finish cart')\n    clicks_predict = predict(0,guesswhichnum,clicks_covisitation,aidslist_click,sessionlist_click,weightinglist,strongaid,strongaid_list)\n    print('finish click')\n    \n    #If this dont work, change pd\n    # Below ALL PANDAS\n    combination = pd.concat(  \n    [\n        orders_predict,\n        carts_predict\n        clicks_predict,\n        \n    ]\n    )\n    combination = combination.explode('aids')\n    combination = pd.concat(  \n    [\n        combination,\n        lastaction\n    ]\n    )\n    \n    new =  combination['aids'].str.split(\"_\", n = 1, expand = True)\n    combination['aids'] = new[0]\n    combination['score'] = new[1]\n    combination = combination.groupby('session',group_keys=False, as_index=False,sort='score')['aids'].agg({'aids': list})\n    combination['labels'] = combination['aids'].apply(lambda x: (x + strongaid_list)[:20])\n    combination = combination.drop('aids',axis = 1)\n    print('Pickling')\n    combination.to_pickle(str(guesswhich)+\".pkl\")\n    print(combination)\n    \n\n# orders_predict = pd.read_pickle('/kaggle/working/orders.parquet')\n# carts_predict = pd.read_pickle('/kaggle/working/carts.parquet')\n# clicks_predict = pd.read_pickle('/kaggle/working/clicks.parquet')\n\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Combine prediction for each action (Insufficant RAM method)","metadata":{}},{"cell_type":"code","source":"from collections import OrderedDict\ndef combine_predict(Lastnth,guesswhichnum,orders_predict,carts_predict,clicks_predict):\n    \n    guesswhich = convertlist[guesswhichnum]\n    strongaid = pl.read_parquet('/kaggle/input/folder-of-output/strong_'+str(guesswhich)+'.parquet')\n    strongaid_list = strongaid['aid'].to_list()[:20]\n    \n    lastaction = test.filter(pl.col('type')==guesswhichnum).drop('type').groupby('session').agg([\n        pl.col('aid').head(Lastnth)\n    ]).sort('session').explode('aid')\n\n    sessionlist_last_clicks = lastaction['session'].to_list()\n    aidslist_last_clicks = lastaction['aid'].to_list()\n    lastaction = pd.DataFrame({'session':sessionlist_last_clicks,'aids':aidslist_last_clicks})\n    lastaction['session'] = lastaction['session'].astype(str) + \"_\" + str(guesswhich)\n    lastaction['aids'] = lastaction['aids'].astype(str) + \"_\" + str('999')\n    \n    combination = pd.concat(  \n    [\n        orders_predict,\n        carts_predict,\n        clicks_predict,\n        \n    ]\n    )\n    combination = combination.explode('aids')\n    combination = pd.concat(  \n    [\n        combination,\n        lastaction\n    ]\n    )\n    \n    new =  combination['aids'].str.split(\"_\", n = 1, expand = True)\n    combination['aids'] = new[0]\n    combination['score'] = new[1]\n    combination = combination.fillna(0)\n    combination.astype({'score': 'float32'})\n    combination['score'] = pd.to_numeric(combination['score'])\n    print(combination.dtypes)\n    print('Before')\n    print(combination)\n    print(\"==\"*32)\n    combination['score'] = combination['score'].where(combination['score'] < 1000,combination['score']/20000000)\n    combination = combination.groupby('session',group_keys=False, as_index=False,sort='score')['aids'].agg({'aids': list})\n    combination['labels'] = combination['aids'].apply(lambda x: list(OrderedDict.fromkeys(x).keys())[:20])\n    combination = combination.drop('aids',axis = 1)\n    print('Pickling')\n    combination.to_pickle(str(guesswhich)+\".pkl\")\n    print(combination)\n    return combination\n    \nLastnth = 10\nfor guesswhichnum in range(3):\n    guesswhich = convertlist[guesswhichnum]\n    print(guesswhich)\n    orders_predict = pd.read_pickle('/kaggle/input/folder-of-output/orders_'+str(guesswhich)+'_predict_.pkl')\n    print('finish1')\n    carts_predict = pd.read_pickle('/kaggle/input/folder-of-output/carts_'+str(guesswhich)+'_predict_.pkl')\n    print('finish2')\n    clicks_predict = pd.read_pickle('/kaggle/input/folder-of-output/clicks_'+str(guesswhich)+'_predict_.pkl')\n    print('finish3')\n    combine_predict(Lastnth,guesswhichnum,orders_predict,carts_predict,clicks_predict)\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Check whether there are missing session_type","metadata":{}},{"cell_type":"code","source":"orders_predict = pd.read_pickle('/kaggle/working/orders.pkl')\ncarts_predict = pd.read_pickle('/kaggle/working/carts.pkl')\nclicks_predict = pd.read_pickle('/kaggle/working/clicks.pkl')\n\nsubmission = pd.concat(  \n    [\n        orders_predict,\n        carts_predict,\n        clicks_predict,\n        \n    ])\nsubmission = submission.rename(columns={'session': 'session_type'})\nsubmissionlist = submission['session_type'].tolist()\n\n# Load sample csv\nsampleexcel = pd.read_csv('/kaggle/input/otto-recommender-system/sample_submission.csv')\nsamplelist = sampleexcel['session_type'].tolist()\n\n# Compare two list\nmissing = list(set(samplelist) - set(submissionlist))\nprint(missing)\nmissingaids = []\nstrongaid = pl.read_parquet('/kaggle/input/folder-of-output/strong_orders.parquet')\nstrongaid_list = strongaid['aid'].to_list()[:20]\n\n# Fill missing session_type with top 20 strongaid\nfor i in missing:\n    missingaids.append(strongaid_list)\n    \n\nmissingframe = pd.DataFrame({'session_type':missing,'labels':missingaids})\nsubmission = pd.concat([submission,missingframe])\nsubmission['labels'] = submission['labels'].apply(lambda x:' '.join(str(i) for i in x))\nprint(submission)\nsubmission.to_csv('submission.csv', index=False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Download Submission","metadata":{}},{"cell_type":"code","source":"import os\nos.chdir(r'/kaggle/working')\nfrom IPython.display import FileLink\n\n\nFileLink(r'submission.csv') \n","metadata":{},"execution_count":null,"outputs":[]}]}