{
  "id": 382772,
  "title": "116th place write up",
  "url": "/competitions/otto-recommender-system/writeups/hidehisa-arai-116th-place-write-up",
  "author_name": "",
  "post_date": "2023-02-01T00:16:39.983Z",
  "votes": 36,
  "comment_count": 6,
  "views": 0,
  "content": "<p>First of all, I want to say thank you to Otto to hold such an interesting competition. Since we only have the interaction information, the task was innevitably hard to solve, but I learned a lot of things from that quite challenging task. I'm also involved in recommender systems at work, so I'm sure this experience will help me.</p>\n<p>Handling a large number of sessions (users) was also a hard point of this competition. I'm sure many people suffered from this. Maybe some of you started using cudf or polars instead of the famous pandas. I used BigQuery for joinning large tables, and this was the first time for me to use BQ for Kaggle competition.</p>\n<p>We've seen some sad things happened. Some kaggle GMs and Masters seemed to have been cheating, and it turned out that they have likely been doing so for years. I hope Kaggle will take appropriate actions for this problem.</p>\n<p>Anyway, here's what I did to achieve this place in this competition.</p>\n<h2>Overview</h2>\n<p>I followed the standard candidate re-rank pipeline. I didn't have time to prepare ensembles, so my score comes from single XGBoost Ranker model.</p>\n<p>In the first step, I split the <code>train.jsonl</code> into train data (which I call <code>train split</code> afterwards) and validation data (<code>validation split</code>). This was done using the code from <a href=\"https://github.com/otto-de/recsys-dataset/blob/main/src/testset.py\" target=\"_blank\">host's repository</a>.</p>\n<p>Then, I randomly truncate each session in <code>train split</code> to make labels for it.</p>\n<p>Then, I made three types of co-visitation matrices which was introduced in <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">this notebook</a>. To avoid leak, I made them in three ways. First ones are for training, so I used truncated version of <code>train split</code> and test data (<code>test.jsonl</code>; I'll call this <code>test split</code>) to make three co-visitation matrices. Second ones are for validation, so I used nontrucated version of <code>train split</code> and <code>test split</code>. Third ones are for inference, so I used the whole data.</p>\n<p>I also trained two Word2Vec model in three ways (the same way I used for making co-visitation matrices). One is trained with <code>aid</code> sequences and the other is trained with <code>aid_type</code> sequences (I concatenated <code>aid</code> and <code>type</code>. For example, if there is a record that with <code>aid=0</code> and <code>type='carts'</code>, then <code>aid_carts</code> will be <code>0_carts</code>).</p>\n<p>Then I generate candidates. For each session (user), I use the whole aids in the history, top 50 most co-occurring items to the last item (for each co-visitation matrix), top 50 most similar items to the last item (using word2vec vector), top 50 most similar (co-occuring) items to session's most frequent item, top 50 most similar (co-occuring) items to session's most frequent clicks (carts, orders), and most popular items. For each session, there are average 193 aids (max. 834 items), and candidate recalls are</p>\n<ul>\n<li>clicks: 0.663</li>\n<li>carts: 0.541</li>\n<li>orders: 0.726</li>\n</ul>\n<p>for the <code>validation split</code>.</p>\n<p>I sampled around 200,000 sessions for each targets. Then I created around 50 features. With these features, I trained XGBoost Rankers for each target. Finally I rerank the candidates with this model. The recalls@20 for each target is</p>\n<ul>\n<li>clicks: 0.528</li>\n<li>carts: 0.422</li>\n<li>orders: 0.657</li>\n<li>overall: 0.574</li>\n</ul>\n<p>This gave me 0.586 on public LB.</p>\n<h2>Features</h2>\n<p>I used 53 features in total. </p>\n<h3>Rank features from public notebook</h3>\n<p>The ranking of <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">this notebook</a> was pretty good. I used the rank of each items in the result of the notebook. In the notebook, there are two types of list (list for clicks target and list for buys target), so I used aid rank from both list. These are called <code>clicks_rank</code> and <code>buys_rank</code> respectively.</p>\n<h3>history features</h3>\n<p>Some candidate items come from session's history, so I made some history features. I made some group inside each session. It is said that what is called a <code>session</code> is in fact a <code>user</code> in general meaning, so I used a simple method to detect <code>session</code> (general meaning) and called them <code>groups</code> (I used a method similar to the way introduced in <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/366138\" target=\"_blank\">this discussion</a>.)</p>\n<p>For each <code>aid</code> I generated 16 history features.</p>\n<ul>\n<li>clicks count</li>\n<li>orders count</li>\n<li>carts count</li>\n<li>events count <ul>\n<li>(clicks_count + orders_count + carts_count)</li></ul></li>\n<li>clicks group count<ul>\n<li>the number of groups which contains 'carts' event of the item</li></ul></li>\n<li>orders group count</li>\n<li>carts group count</li>\n<li>events group count</li>\n<li>time elapsed from last clicks</li>\n<li>time elapsed from last orders</li>\n<li>time elapsed from last carts</li>\n<li>time elapsed from last events</li>\n<li>events count from last clicks<ul>\n<li>the number of actions taken to the other items after the user took 'clicks' action to the item</li></ul></li>\n<li>events count from last orders</li>\n<li>events count from last carts</li>\n<li>events count from last events</li>\n</ul>\n<h3>co-visitation matrices' weights features</h3>\n<ul>\n<li>buy2buy covisitation matrix weight of the item to user's last item</li>\n<li>buy2buy covisitation matrix weight of the item to the most frequently actioned item in the user's history</li>\n<li>carts_orders covisitation matrix weight of the item to user's last item</li>\n<li>carts_orders covisitation matrix weight of the item to the most frequently actioned item in the user's history</li>\n<li>clicks covisitation matrix weight of the item to user's last item</li>\n<li>clicks covisitation matrix weight of the item to the most frequently actioned item in the user's history</li>\n</ul>\n<h3>popularity features</h3>\n<ul>\n<li>global carts count (counted in three ways to avoid leak)</li>\n<li>global orders count</li>\n<li>global clicks count</li>\n<li>number of sessions who clicked the item</li>\n<li>number of sessions who put the item into cart</li>\n<li>number of sessions who ordered the item</li>\n</ul>\n<h3>cosine similarity features</h3>\n<ul>\n<li>items word2vec vector similarity to the last item of the session</li>\n<li>items word2vec vector similarity to the last item of the session</li>\n<li>aid_type word2vec vector similarity to the last aid_type of the session<ul>\n<li>concatenate the candidate aid and actions (clicks, carts, orders)</li></ul></li>\n<li>aid_type word2vec vector similarity to the mean of aid_types in the last group of the session<ul>\n<li>concatenate the candidate aid and actions (clicks, carts, orders)</li></ul></li>\n<li>aid_type word2vec vector similarity to the mean of unique aid_types in the last group of the session</li>\n<li>max aid_type word2vec vector similarity to the aid_types in the last group of the session</li>\n<li>aid_type word2vec vector similarity to the mean of aid_types in the session</li>\n<li>aid_type word2vec vector similarity to the mean of unique aid_types in the session</li>\n<li>max aid_type word2vec vector similarity ot the aid_types in the session</li>\n</ul>\n<h2>XGBoost Ranker</h2>\n<p>I used the following parameters to train my XGBoost model</p>\n<pre><code>params = {\n    : ,\n    : ,\n    : ,\n    : ,\n    : ,\n    : ,\n    : ,\n}\n</code></pre>\n<p>I put aside 20,000 sessions at random to use them for early stopping.</p>\n<p>Here's the F-score plot for carts model</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F748998b852c018b77c0079b3f42a8a75%2Fcarts.png?generation=1675210503694228&amp;alt=media\" alt=\"\"></p>\n<p>and here's the one for orders model</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F062ed3117586218146f4ed9599c67a16%2Forders.png?generation=1675210547893838&amp;alt=media\" alt=\"\"></p>\n<p>and here's the one for clicks model</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F6cefdba258d07289198de30823cc331b%2Fclicks.png?generation=1675210576351554&amp;alt=media\" alt=\"\"></p>",
  "messages": [
    {
      "id": "2124335",
      "postDate": "02/01/2023 00:16:18",
      "content": "<p>First of all, I want to say thank you to Otto to hold such an interesting competition. Since we only have the interaction information, the task was innevitably hard to solve, but I learned a lot of things from that quite challenging task. I'm also involved in recommender systems at work, so I'm sure this experience will help me.</p>\n<p>Handling a large number of sessions (users) was also a hard point of this competition. I'm sure many people suffered from this. Maybe some of you started using cudf or polars instead of the famous pandas. I used BigQuery for joinning large tables, and this was the first time for me to use BQ for Kaggle competition.</p>\n<p>We've seen some sad things happened. Some kaggle GMs and Masters seemed to have been cheating, and it turned out that they have likely been doing so for years. I hope Kaggle will take appropriate actions for this problem.</p>\n<p>Anyway, here's what I did to achieve this place in this competition.</p>\n<h2>Overview</h2>\n<p>I followed the standard candidate re-rank pipeline. I didn't have time to prepare ensembles, so my score comes from single XGBoost Ranker model.</p>\n<p>In the first step, I split the <code>train.jsonl</code> into train data (which I call <code>train split</code> afterwards) and validation data (<code>validation split</code>). This was done using the code from <a href=\"https://github.com/otto-de/recsys-dataset/blob/main/src/testset.py\" target=\"_blank\">host's repository</a>.</p>\n<p>Then, I randomly truncate each session in <code>train split</code> to make labels for it.</p>\n<p>Then, I made three types of co-visitation matrices which was introduced in <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">this notebook</a>. To avoid leak, I made them in three ways. First ones are for training, so I used truncated version of <code>train split</code> and test data (<code>test.jsonl</code>; I'll call this <code>test split</code>) to make three co-visitation matrices. Second ones are for validation, so I used nontrucated version of <code>train split</code> and <code>test split</code>. Third ones are for inference, so I used the whole data.</p>\n<p>I also trained two Word2Vec model in three ways (the same way I used for making co-visitation matrices). One is trained with <code>aid</code> sequences and the other is trained with <code>aid_type</code> sequences (I concatenated <code>aid</code> and <code>type</code>. For example, if there is a record that with <code>aid=0</code> and <code>type='carts'</code>, then <code>aid_carts</code> will be <code>0_carts</code>).</p>\n<p>Then I generate candidates. For each session (user), I use the whole aids in the history, top 50 most co-occurring items to the last item (for each co-visitation matrix), top 50 most similar items to the last item (using word2vec vector), top 50 most similar (co-occuring) items to session's most frequent item, top 50 most similar (co-occuring) items to session's most frequent clicks (carts, orders), and most popular items. For each session, there are average 193 aids (max. 834 items), and candidate recalls are</p>\n<ul>\n<li>clicks: 0.663</li>\n<li>carts: 0.541</li>\n<li>orders: 0.726</li>\n</ul>\n<p>for the <code>validation split</code>.</p>\n<p>I sampled around 200,000 sessions for each targets. Then I created around 50 features. With these features, I trained XGBoost Rankers for each target. Finally I rerank the candidates with this model. The recalls@20 for each target is</p>\n<ul>\n<li>clicks: 0.528</li>\n<li>carts: 0.422</li>\n<li>orders: 0.657</li>\n<li>overall: 0.574</li>\n</ul>\n<p>This gave me 0.586 on public LB.</p>\n<h2>Features</h2>\n<p>I used 53 features in total. </p>\n<h3>Rank features from public notebook</h3>\n<p>The ranking of <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">this notebook</a> was pretty good. I used the rank of each items in the result of the notebook. In the notebook, there are two types of list (list for clicks target and list for buys target), so I used aid rank from both list. These are called <code>clicks_rank</code> and <code>buys_rank</code> respectively.</p>\n<h3>history features</h3>\n<p>Some candidate items come from session's history, so I made some history features. I made some group inside each session. It is said that what is called a <code>session</code> is in fact a <code>user</code> in general meaning, so I used a simple method to detect <code>session</code> (general meaning) and called them <code>groups</code> (I used a method similar to the way introduced in <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/366138\" target=\"_blank\">this discussion</a>.)</p>\n<p>For each <code>aid</code> I generated 16 history features.</p>\n<ul>\n<li>clicks count</li>\n<li>orders count</li>\n<li>carts count</li>\n<li>events count <ul>\n<li>(clicks_count + orders_count + carts_count)</li></ul></li>\n<li>clicks group count<ul>\n<li>the number of groups which contains 'carts' event of the item</li></ul></li>\n<li>orders group count</li>\n<li>carts group count</li>\n<li>events group count</li>\n<li>time elapsed from last clicks</li>\n<li>time elapsed from last orders</li>\n<li>time elapsed from last carts</li>\n<li>time elapsed from last events</li>\n<li>events count from last clicks<ul>\n<li>the number of actions taken to the other items after the user took 'clicks' action to the item</li></ul></li>\n<li>events count from last orders</li>\n<li>events count from last carts</li>\n<li>events count from last events</li>\n</ul>\n<h3>co-visitation matrices' weights features</h3>\n<ul>\n<li>buy2buy covisitation matrix weight of the item to user's last item</li>\n<li>buy2buy covisitation matrix weight of the item to the most frequently actioned item in the user's history</li>\n<li>carts_orders covisitation matrix weight of the item to user's last item</li>\n<li>carts_orders covisitation matrix weight of the item to the most frequently actioned item in the user's history</li>\n<li>clicks covisitation matrix weight of the item to user's last item</li>\n<li>clicks covisitation matrix weight of the item to the most frequently actioned item in the user's history</li>\n</ul>\n<h3>popularity features</h3>\n<ul>\n<li>global carts count (counted in three ways to avoid leak)</li>\n<li>global orders count</li>\n<li>global clicks count</li>\n<li>number of sessions who clicked the item</li>\n<li>number of sessions who put the item into cart</li>\n<li>number of sessions who ordered the item</li>\n</ul>\n<h3>cosine similarity features</h3>\n<ul>\n<li>items word2vec vector similarity to the last item of the session</li>\n<li>items word2vec vector similarity to the last item of the session</li>\n<li>aid_type word2vec vector similarity to the last aid_type of the session<ul>\n<li>concatenate the candidate aid and actions (clicks, carts, orders)</li></ul></li>\n<li>aid_type word2vec vector similarity to the mean of aid_types in the last group of the session<ul>\n<li>concatenate the candidate aid and actions (clicks, carts, orders)</li></ul></li>\n<li>aid_type word2vec vector similarity to the mean of unique aid_types in the last group of the session</li>\n<li>max aid_type word2vec vector similarity to the aid_types in the last group of the session</li>\n<li>aid_type word2vec vector similarity to the mean of aid_types in the session</li>\n<li>aid_type word2vec vector similarity to the mean of unique aid_types in the session</li>\n<li>max aid_type word2vec vector similarity ot the aid_types in the session</li>\n</ul>\n<h2>XGBoost Ranker</h2>\n<p>I used the following parameters to train my XGBoost model</p>\n<pre><code>params = {\n    : ,\n    : ,\n    : ,\n    : ,\n    : ,\n    : ,\n    : ,\n}\n</code></pre>\n<p>I put aside 20,000 sessions at random to use them for early stopping.</p>\n<p>Here's the F-score plot for carts model</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F748998b852c018b77c0079b3f42a8a75%2Fcarts.png?generation=1675210503694228&amp;alt=media\" alt=\"\"></p>\n<p>and here's the one for orders model</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F062ed3117586218146f4ed9599c67a16%2Forders.png?generation=1675210547893838&amp;alt=media\" alt=\"\"></p>\n<p>and here's the one for clicks model</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F6cefdba258d07289198de30823cc331b%2Fclicks.png?generation=1675210576351554&amp;alt=media\" alt=\"\"></p>",
      "rawMarkdown": "First of all, I want to say thank you to Otto to hold such an interesting competition. Since we only have the interaction information, the task was innevitably hard to solve, but I learned a lot of things from that quite challenging task. I'm also involved in recommender systems at work, so I'm sure this experience will help me.\n\nHandling a large number of sessions (users) was also a hard point of this competition. I'm sure many people suffered from this. Maybe some of you started using cudf or polars instead of the famous pandas. I used BigQuery for joinning large tables, and this was the first time for me to use BQ for Kaggle competition.\n\nWe've seen some sad things happened. Some kaggle GMs and Masters seemed to have been cheating, and it turned out that they have likely been doing so for years. I hope Kaggle will take appropriate actions for this problem.\n\nAnyway, here's what I did to achieve this place in this competition.\n\n## Overview\n\nI followed the standard candidate re-rank pipeline. I didn't have time to prepare ensembles, so my score comes from single XGBoost Ranker model.\n\nIn the first step, I split the `train.jsonl` into train data (which I call `train split` afterwards) and validation data (`validation split`). This was done using the code from [host's repository](https://github.com/otto-de/recsys-dataset/blob/main/src/testset.py).\n\nThen, I randomly truncate each session in `train split` to make labels for it.\n\nThen, I made three types of co-visitation matrices which was introduced in [this notebook](https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575). To avoid leak, I made them in three ways. First ones are for training, so I used truncated version of `train split` and test data (`test.jsonl`; I'll call this `test split`) to make three co-visitation matrices. Second ones are for validation, so I used nontrucated version of `train split` and `test split`. Third ones are for inference, so I used the whole data.\n\nI also trained two Word2Vec model in three ways (the same way I used for making co-visitation matrices). One is trained with `aid` sequences and the other is trained with `aid_type` sequences (I concatenated `aid` and `type`. For example, if there is a record that with `aid=0` and `type='carts'`, then `aid_carts` will be `0_carts`).\n\nThen I generate candidates. For each session (user), I use the whole aids in the history, top 50 most co-occurring items to the last item (for each co-visitation matrix), top 50 most similar items to the last item (using word2vec vector), top 50 most similar (co-occuring) items to session's most frequent item, top 50 most similar (co-occuring) items to session's most frequent clicks (carts, orders), and most popular items. For each session, there are average 193 aids (max. 834 items), and candidate recalls are\n\n* clicks: 0.663\n* carts: 0.541\n* orders: 0.726\n\nfor the `validation split`.\n\nI sampled around 200,000 sessions for each targets. Then I created around 50 features. With these features, I trained XGBoost Rankers for each target. Finally I rerank the candidates with this model. The recalls@20 for each target is\n\n* clicks: 0.528\n* carts: 0.422\n* orders: 0.657\n* overall: 0.574\n\nThis gave me 0.586 on public LB.\n\n## Features\n\nI used 53 features in total. \n\n### Rank features from public notebook\n\nThe ranking of [this notebook](https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575) was pretty good. I used the rank of each items in the result of the notebook. In the notebook, there are two types of list (list for clicks target and list for buys target), so I used aid rank from both list. These are called `clicks_rank` and `buys_rank` respectively.\n\n### history features\n\nSome candidate items come from session's history, so I made some history features. I made some group inside each session. It is said that what is called a `session` is in fact a `user` in general meaning, so I used a simple method to detect `session` (general meaning) and called them `groups` (I used a method similar to the way introduced in [this discussion](https://www.kaggle.com/competitions/otto-recommender-system/discussion/366138).)\n\nFor each `aid` I generated 16 history features.\n\n* clicks count\n* orders count\n* carts count\n* events count \n    - (clicks_count + orders_count + carts_count)\n* clicks group count\n    - the number of groups which contains 'carts' event of the item\n* orders group count\n* carts group count\n* events group count\n* time elapsed from last clicks\n* time elapsed from last orders\n* time elapsed from last carts\n* time elapsed from last events\n* events count from last clicks\n    - the number of actions taken to the other items after the user took 'clicks' action to the item\n* events count from last orders\n* events count from last carts\n* events count from last events\n\n### co-visitation matrices' weights features\n\n* buy2buy covisitation matrix weight of the item to user's last item\n* buy2buy covisitation matrix weight of the item to the most frequently actioned item in the user's history\n* carts_orders covisitation matrix weight of the item to user's last item\n* carts_orders covisitation matrix weight of the item to the most frequently actioned item in the user's history\n* clicks covisitation matrix weight of the item to user's last item\n* clicks covisitation matrix weight of the item to the most frequently actioned item in the user's history\n\n### popularity features\n\n* global carts count (counted in three ways to avoid leak)\n* global orders count\n* global clicks count\n* number of sessions who clicked the item\n* number of sessions who put the item into cart\n* number of sessions who ordered the item\n\n### cosine similarity features\n\n* items word2vec vector similarity to the last item of the session\n* items word2vec vector similarity to the last item of the session\n* aid_type word2vec vector similarity to the last aid_type of the session\n    - concatenate the candidate aid and actions (clicks, carts, orders)\n* aid_type word2vec vector similarity to the mean of aid_types in the last group of the session\n    - concatenate the candidate aid and actions (clicks, carts, orders)\n* aid_type word2vec vector similarity to the mean of unique aid_types in the last group of the session\n* max aid_type word2vec vector similarity to the aid_types in the last group of the session\n* aid_type word2vec vector similarity to the mean of aid_types in the session\n* aid_type word2vec vector similarity to the mean of unique aid_types in the session\n* max aid_type word2vec vector similarity ot the aid_types in the session\n\n## XGBoost Ranker\n\nI used the following parameters to train my XGBoost model\n\n```python\nparams = {\n    \"verbosity\": 1,\n    \"nthread\": 24,\n    \"eta\": 0.05,\n    \"subsample\": 0.6,\n    \"colsample_bytree\": 0.8,\n    \"tree_method\": \"gpu_hist\",\n    \"objective\": \"rank:pairwise\",\n}\n```\n\nI put aside 20,000 sessions at random to use them for early stopping.\n\nHere's the F-score plot for carts model\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F748998b852c018b77c0079b3f42a8a75%2Fcarts.png?generation=1675210503694228&alt=media)\n\nand here's the one for orders model\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F062ed3117586218146f4ed9599c67a16%2Forders.png?generation=1675210547893838&alt=media)\n\nand here's the one for clicks model\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F6cefdba258d07289198de30823cc331b%2Fclicks.png?generation=1675210576351554&alt=media)",
      "votes": null
    },
    {
      "id": "2124378",
      "postDate": "02/01/2023 00:58:07",
      "content": "<p>\"Rank features from public notebook\": can this be considered as stacking?</p>\n<p>Congrats!</p>",
      "rawMarkdown": "\"Rank features from public notebook\": can this be considered as stacking?\n\nCongrats!",
      "votes": null
    },
    {
      "id": "2124543",
      "postDate": "02/01/2023 04:17:12",
      "content": "<p>Congrats <a href=\"https://www.kaggle.com/hidehisaarai1213\" target=\"_blank\">@hidehisaarai1213</a>, thanks for sharing! From what you said \"For each session, there are average 193 aids (max. 834 items)\", I wonder whether you use all aids for each session or have a strategy to truncate the session has more than 193 aids?</p>",
      "rawMarkdown": "Congrats @hidehisaarai1213, thanks for sharing! From what you said \"For each session, there are average 193 aids (max. 834 items)\", I wonder whether you use all aids for each session or have a strategy to truncate the session has more than 193 aids?",
      "votes": null
    },
    {
      "id": "2124988",
      "postDate": "02/01/2023 11:00:17",
      "content": "<p>Thank you for your report!</p>\n<ul>\n<li>You used top50 candidates to generate inputs for the Ranker, right?</li>\n<li>I see you only used co-visitation matrices comparing candidate to a single aid. You used BigQuery and still considered it would take too much time to calculate sum/mean weights for candidate in comparison to 5/10/15 last aids from session?</li>\n</ul>",
      "rawMarkdown": "Thank you for your report!\n- You used top50 candidates to generate inputs for the Ranker, right?\n- I see you only used co-visitation matrices comparing candidate to a single aid. You used BigQuery and still considered it would take too much time to calculate sum/mean weights for candidate in comparison to 5/10/15 last aids from session?",
      "votes": null
    },
    {
      "id": "2125036",
      "postDate": "02/01/2023 11:31:15",
      "content": "<blockquote>\n  <p>For each session, there are average 193 aids (max. 834 items)</p>\n</blockquote>\n<p>This is about the number of candidates for each session!</p>",
      "rawMarkdown": "> For each session, there are average 193 aids (max. 834 items)\n\nThis is about the number of candidates for each session!",
      "votes": null
    },
    {
      "id": "2125042",
      "postDate": "02/01/2023 11:36:43",
      "content": "<blockquote>\n  <p>You used top50 candidates to generate inputs for the Ranker, right?</p>\n</blockquote>\n<p>It isn't. Here's the way I generated the candidates.</p>\n<pre><code> I use the whole aids in the history, top 50 most co-occurring items to the last item (for each co-visitation matrix), top 50 most similar items to the last item (using word2vec vector), top 50 most similar (co-occuring) items to session's most frequent item, top 50 most similar (co-occuring) items to session's most frequent clicks (carts, orders), and most popular items.\n</code></pre>\n<p>The number of candidates varies between sessions (avg: 193, max: 834).</p>\n<blockquote>\n  <p>I see you only used co-visitation matrices comparing candidate to a single aid. You used BigQuery and still considered it would take too much time to calculate sum/mean weights for candidate in comparison to 5/10/15 last aids from session?</p>\n</blockquote>\n<p>Calculating Co-visitation matrices was done on my local PC (with cudf, which was the way Chris introduced). I used BigQuery for merging features to the candidate pairs.</p>",
      "rawMarkdown": "> You used top50 candidates to generate inputs for the Ranker, right?\n\nIt isn't. Here's the way I generated the candidates.\n\n```\n I use the whole aids in the history, top 50 most co-occurring items to the last item (for each co-visitation matrix), top 50 most similar items to the last item (using word2vec vector), top 50 most similar (co-occuring) items to session's most frequent item, top 50 most similar (co-occuring) items to session's most frequent clicks (carts, orders), and most popular items.\n```\n\nThe number of candidates varies between sessions (avg: 193, max: 834).\n\n> I see you only used co-visitation matrices comparing candidate to a single aid. You used BigQuery and still considered it would take too much time to calculate sum/mean weights for candidate in comparison to 5/10/15 last aids from session?\n\nCalculating Co-visitation matrices was done on my local PC (with cudf, which was the way Chris introduced). I used BigQuery for merging features to the candidate pairs.",
      "votes": null
    },
    {
      "id": "2125521",
      "postDate": "02/01/2023 17:32:03",
      "content": "<p>Thank you, understood it about number of features.</p>\n<p>Applying matrix to all the pairs of history aids and candidates takes more time and memory than calculating the matrix itself.</p>",
      "rawMarkdown": "Thank you, understood it about number of features.\n\nApplying matrix to all the pairs of history aids and candidates takes more time and memory than calculating the matrix itself.",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 2124378,
      "author_name": "hinepo",
      "author_url": "",
      "post_date": "02/01/2023 00:58:07",
      "content": "<p>\"Rank features from public notebook\": can this be considered as stacking?</p>\n<p>Congrats!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2124543,
      "author_name": "huyduong7101",
      "author_url": "",
      "post_date": "02/01/2023 04:17:12",
      "content": "<p>Congrats <a href=\"https://www.kaggle.com/hidehisaarai1213\" target=\"_blank\">@hidehisaarai1213</a>, thanks for sharing! From what you said \"For each session, there are average 193 aids (max. 834 items)\", I wonder whether you use all aids for each session or have a strategy to truncate the session has more than 193 aids?</p>",
      "votes": null,
      "replies": [
        {
          "id": 2125036,
          "author_name": "hidehisaarai1213",
          "author_url": "",
          "post_date": "02/01/2023 11:31:15",
          "content": "<blockquote>\n  <p>For each session, there are average 193 aids (max. 834 items)</p>\n</blockquote>\n<p>This is about the number of candidates for each session!</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2124988,
      "author_name": "artemfedorov",
      "author_url": "",
      "post_date": "02/01/2023 11:00:17",
      "content": "<p>Thank you for your report!</p>\n<ul>\n<li>You used top50 candidates to generate inputs for the Ranker, right?</li>\n<li>I see you only used co-visitation matrices comparing candidate to a single aid. You used BigQuery and still considered it would take too much time to calculate sum/mean weights for candidate in comparison to 5/10/15 last aids from session?</li>\n</ul>",
      "votes": null,
      "replies": [
        {
          "id": 2125042,
          "author_name": "hidehisaarai1213",
          "author_url": "",
          "post_date": "02/01/2023 11:36:43",
          "content": "<blockquote>\n  <p>You used top50 candidates to generate inputs for the Ranker, right?</p>\n</blockquote>\n<p>It isn't. Here's the way I generated the candidates.</p>\n<pre><code> I use the whole aids in the history, top 50 most co-occurring items to the last item (for each co-visitation matrix), top 50 most similar items to the last item (using word2vec vector), top 50 most similar (co-occuring) items to session's most frequent item, top 50 most similar (co-occuring) items to session's most frequent clicks (carts, orders), and most popular items.\n</code></pre>\n<p>The number of candidates varies between sessions (avg: 193, max: 834).</p>\n<blockquote>\n  <p>I see you only used co-visitation matrices comparing candidate to a single aid. You used BigQuery and still considered it would take too much time to calculate sum/mean weights for candidate in comparison to 5/10/15 last aids from session?</p>\n</blockquote>\n<p>Calculating Co-visitation matrices was done on my local PC (with cudf, which was the way Chris introduced). I used BigQuery for merging features to the candidate pairs.</p>",
          "votes": null,
          "replies": [
            {
              "id": 2125521,
              "author_name": "artemfedorov",
              "author_url": "",
              "post_date": "02/01/2023 17:32:03",
              "content": "<p>Thank you, understood it about number of features.</p>\n<p>Applying matrix to all the pairs of history aids and candidates takes more time and memory than calculating the matrix itself.</p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    }
  ],
  "raw_markdown_by_id": {
    "2124335": "First of all, I want to say thank you to Otto to hold such an interesting competition. Since we only have the interaction information, the task was innevitably hard to solve, but I learned a lot of things from that quite challenging task. I'm also involved in recommender systems at work, so I'm sure this experience will help me.\n\nHandling a large number of sessions (users) was also a hard point of this competition. I'm sure many people suffered from this. Maybe some of you started using cudf or polars instead of the famous pandas. I used BigQuery for joinning large tables, and this was the first time for me to use BQ for Kaggle competition.\n\nWe've seen some sad things happened. Some kaggle GMs and Masters seemed to have been cheating, and it turned out that they have likely been doing so for years. I hope Kaggle will take appropriate actions for this problem.\n\nAnyway, here's what I did to achieve this place in this competition.\n\n## Overview\n\nI followed the standard candidate re-rank pipeline. I didn't have time to prepare ensembles, so my score comes from single XGBoost Ranker model.\n\nIn the first step, I split the `train.jsonl` into train data (which I call `train split` afterwards) and validation data (`validation split`). This was done using the code from [host's repository](https://github.com/otto-de/recsys-dataset/blob/main/src/testset.py).\n\nThen, I randomly truncate each session in `train split` to make labels for it.\n\nThen, I made three types of co-visitation matrices which was introduced in [this notebook](https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575). To avoid leak, I made them in three ways. First ones are for training, so I used truncated version of `train split` and test data (`test.jsonl`; I'll call this `test split`) to make three co-visitation matrices. Second ones are for validation, so I used nontrucated version of `train split` and `test split`. Third ones are for inference, so I used the whole data.\n\nI also trained two Word2Vec model in three ways (the same way I used for making co-visitation matrices). One is trained with `aid` sequences and the other is trained with `aid_type` sequences (I concatenated `aid` and `type`. For example, if there is a record that with `aid=0` and `type='carts'`, then `aid_carts` will be `0_carts`).\n\nThen I generate candidates. For each session (user), I use the whole aids in the history, top 50 most co-occurring items to the last item (for each co-visitation matrix), top 50 most similar items to the last item (using word2vec vector), top 50 most similar (co-occuring) items to session's most frequent item, top 50 most similar (co-occuring) items to session's most frequent clicks (carts, orders), and most popular items. For each session, there are average 193 aids (max. 834 items), and candidate recalls are\n\n* clicks: 0.663\n* carts: 0.541\n* orders: 0.726\n\nfor the `validation split`.\n\nI sampled around 200,000 sessions for each targets. Then I created around 50 features. With these features, I trained XGBoost Rankers for each target. Finally I rerank the candidates with this model. The recalls@20 for each target is\n\n* clicks: 0.528\n* carts: 0.422\n* orders: 0.657\n* overall: 0.574\n\nThis gave me 0.586 on public LB.\n\n## Features\n\nI used 53 features in total. \n\n### Rank features from public notebook\n\nThe ranking of [this notebook](https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575) was pretty good. I used the rank of each items in the result of the notebook. In the notebook, there are two types of list (list for clicks target and list for buys target), so I used aid rank from both list. These are called `clicks_rank` and `buys_rank` respectively.\n\n### history features\n\nSome candidate items come from session's history, so I made some history features. I made some group inside each session. It is said that what is called a `session` is in fact a `user` in general meaning, so I used a simple method to detect `session` (general meaning) and called them `groups` (I used a method similar to the way introduced in [this discussion](https://www.kaggle.com/competitions/otto-recommender-system/discussion/366138).)\n\nFor each `aid` I generated 16 history features.\n\n* clicks count\n* orders count\n* carts count\n* events count \n    - (clicks_count + orders_count + carts_count)\n* clicks group count\n    - the number of groups which contains 'carts' event of the item\n* orders group count\n* carts group count\n* events group count\n* time elapsed from last clicks\n* time elapsed from last orders\n* time elapsed from last carts\n* time elapsed from last events\n* events count from last clicks\n    - the number of actions taken to the other items after the user took 'clicks' action to the item\n* events count from last orders\n* events count from last carts\n* events count from last events\n\n### co-visitation matrices' weights features\n\n* buy2buy covisitation matrix weight of the item to user's last item\n* buy2buy covisitation matrix weight of the item to the most frequently actioned item in the user's history\n* carts_orders covisitation matrix weight of the item to user's last item\n* carts_orders covisitation matrix weight of the item to the most frequently actioned item in the user's history\n* clicks covisitation matrix weight of the item to user's last item\n* clicks covisitation matrix weight of the item to the most frequently actioned item in the user's history\n\n### popularity features\n\n* global carts count (counted in three ways to avoid leak)\n* global orders count\n* global clicks count\n* number of sessions who clicked the item\n* number of sessions who put the item into cart\n* number of sessions who ordered the item\n\n### cosine similarity features\n\n* items word2vec vector similarity to the last item of the session\n* items word2vec vector similarity to the last item of the session\n* aid_type word2vec vector similarity to the last aid_type of the session\n    - concatenate the candidate aid and actions (clicks, carts, orders)\n* aid_type word2vec vector similarity to the mean of aid_types in the last group of the session\n    - concatenate the candidate aid and actions (clicks, carts, orders)\n* aid_type word2vec vector similarity to the mean of unique aid_types in the last group of the session\n* max aid_type word2vec vector similarity to the aid_types in the last group of the session\n* aid_type word2vec vector similarity to the mean of aid_types in the session\n* aid_type word2vec vector similarity to the mean of unique aid_types in the session\n* max aid_type word2vec vector similarity ot the aid_types in the session\n\n## XGBoost Ranker\n\nI used the following parameters to train my XGBoost model\n\n```python\nparams = {\n    \"verbosity\": 1,\n    \"nthread\": 24,\n    \"eta\": 0.05,\n    \"subsample\": 0.6,\n    \"colsample_bytree\": 0.8,\n    \"tree_method\": \"gpu_hist\",\n    \"objective\": \"rank:pairwise\",\n}\n```\n\nI put aside 20,000 sessions at random to use them for early stopping.\n\nHere's the F-score plot for carts model\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F748998b852c018b77c0079b3f42a8a75%2Fcarts.png?generation=1675210503694228&alt=media)\n\nand here's the one for orders model\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F062ed3117586218146f4ed9599c67a16%2Forders.png?generation=1675210547893838&alt=media)\n\nand here's the one for clicks model\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F1489975%2F6cefdba258d07289198de30823cc331b%2Fclicks.png?generation=1675210576351554&alt=media)",
    "2124378": "\"Rank features from public notebook\": can this be considered as stacking?\n\nCongrats!",
    "2124543": "Congrats @hidehisaarai1213, thanks for sharing! From what you said \"For each session, there are average 193 aids (max. 834 items)\", I wonder whether you use all aids for each session or have a strategy to truncate the session has more than 193 aids?",
    "2124988": "Thank you for your report!\n- You used top50 candidates to generate inputs for the Ranker, right?\n- I see you only used co-visitation matrices comparing candidate to a single aid. You used BigQuery and still considered it would take too much time to calculate sum/mean weights for candidate in comparison to 5/10/15 last aids from session?",
    "2125036": "> For each session, there are average 193 aids (max. 834 items)\n\nThis is about the number of candidates for each session!",
    "2125042": "> You used top50 candidates to generate inputs for the Ranker, right?\n\nIt isn't. Here's the way I generated the candidates.\n\n```\n I use the whole aids in the history, top 50 most co-occurring items to the last item (for each co-visitation matrix), top 50 most similar items to the last item (using word2vec vector), top 50 most similar (co-occuring) items to session's most frequent item, top 50 most similar (co-occuring) items to session's most frequent clicks (carts, orders), and most popular items.\n```\n\nThe number of candidates varies between sessions (avg: 193, max: 834).\n\n> I see you only used co-visitation matrices comparing candidate to a single aid. You used BigQuery and still considered it would take too much time to calculate sum/mean weights for candidate in comparison to 5/10/15 last aids from session?\n\nCalculating Co-visitation matrices was done on my local PC (with cudf, which was the way Chris introduced). I used BigQuery for merging features to the candidate pairs.",
    "2125521": "Thank you, understood it about number of features.\n\nApplying matrix to all the pairs of history aids and candidates takes more time and memory than calculating the matrix itself."
  },
  "source": "meta"
}