{
  "id": 383013,
  "title": "3rd Place - Using Only Rules Achieves LB 0.590!",
  "url": "/competitions/otto-recommender-system/discussion/383013",
  "author_name": "Chris Deotte",
  "post_date": "2023-02-01T23:45:34.770000",
  "votes": 151,
  "comment_count": 55,
  "views": 0,
  "content": "<h1>Team G &amp; B &amp; D &amp; T</h1>\n<p>It was a pleasure to work with <a href=\"https://www.kaggle.com/titericz\" target=\"_blank\">@titericz</a> <a href=\"https://www.kaggle.com/benediktschifferer\" target=\"_blank\">@benediktschifferer</a> <a href=\"https://www.kaggle.com/theoviel\" target=\"_blank\">@theoviel</a> . We each made individual models and then ensembled all our work together by adding the ranks of each of our predictions per user target type. Below I describe my individual single model. My teammates will describe their work in their own discussion posts. You can read about Theo's LB 0.6029 model <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/382975\" target=\"_blank\">here</a>! You can read about Benny's LB 0.601 model <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/386497\" target=\"_blank\">here</a>!</p>\n<p>Most of my solution was made public in my notebook <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">here</a> and discussion <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\" target=\"_blank\">here</a> during the competition. There were only 3 significant ideas missing from my public work. Let's discuss how to boost my public work to LB 0.601 single model. (UPDATE: All code published to GitHub <a href=\"https://github.com/cdeotte/Kaggle-OTTO-Comp\" target=\"_blank\">here</a>)</p>\n<h1>How To Score LB 0.601 Single Model</h1>\n<p>It was explained <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/364721\" target=\"_blank\">here</a> and <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\" target=\"_blank\">here</a> that the best approach was \"candidate rerank\" model. My public notebook <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">here</a> shows how to achieve LB 0.575. And my discussion post <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\" target=\"_blank\">here</a> explains how to improve my public notebook by adding a GBT ranker model. Below are the three missing pieces labeled (1), (2), and (3) to achieve LB 0.601</p>\n<h1>(1) Choosing Candidates</h1>\n<p>To build a \"candidate rerank\", we need candidates. Where do we get candidates? The easiest way is to get them from my public notebook. In the <code>def suggest_buys(df)</code> and <code>def suggest_clicks(df)</code> function, the last lines are</p>\n<pre><code>top_aids = [aid for aid, ct in aids_counter.most_common(20)] \nreturn top_aids\n</code></pre>\n<p>To generate 50 candidates, we change 20 to 50 as in</p>\n<pre><code>top_aids = [aid for aid, ct in aids_counter.most_common(50)] \nreturn top_aids\n</code></pre>\n<h1>(2) Choosing Interaction Features</h1>\n<p>We now have 50 candidates per user from our public notebook above. Next we need to make features for our reranker model. The strongest and easiest way to make features is extract our co-visit counts by changing the last two lines of my public notebook to the following:</p>\n<pre><code>top_counts = [ct for aid, ct in aids_counter.most_common(50)] \nreturn top_counts\n</code></pre>\n<p>When we merge these counts to our candidates, we now have an interaction feature for each user item pair. To make more interaction features, we can extract the counts for each co-visit matrix individually. For example, imagine that we have 3 co-visit matrices named covisit2, covisit3, and covist4. Then one by one, we extract each covisit's counts:</p>\n<pre><code>EXTRACT = ['covisit2']\naids_counter = Counter()\nif 'covisit2' in EXTRACT:\n    aids = list(itertools.chain(*[covisit2[aid] for aid in unique_aids if aid in covisit2]))\n    for a in aids: aids_counter[a] += 1\nif 'covisit3' in EXTRACT:\n    aids = list(itertools.chain(*[covisit3[aid] for aid in unique_aids if aid in covisit3]))\n    for a in aids: aids_counter[a] += 1\nif 'covisit4' in EXTRACT:\n    aids = list(itertools.chain(*[covisit4[aid] for aid in unique_aids if aid in covisit4]))\n    for a in aids: aids_counter[a] += 1\ntop_counts = [ct for aid, ct in aids_counter.most_common(50)] \nreturn top_counts\n</code></pre>\n<h1>Reranker Boost CV and LB +0.011</h1>\n<p>First we use the technique above to generate candidates and the technique above to extract covisit counts. Next we add some simple item and user features like counting the number of times an item is click cart or order. When we apply the XGB reranker described <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\" target=\"_blank\">here</a>, our CV and LB will boost by <code>+0.011</code>. For example, the public notebook will boost to LB 0.586.</p>\n<h1>Using Rules Only (without reranker) Scores LB 0.590</h1>\n<p>To score over LB 0.600, we create more co-visit matrices to boost the original notebook's LB score. My public notebook uses 3 covisit matrices and achieves LB 0.575. If we make 17 more covisit matrices, we can boost my public \"rules only\" notebook to LB 0.590 (new notebook published <a href=\"https://www.kaggle.com/cdeotte/rules-only-model-achieves-lb-590\" target=\"_blank\">here</a>). Then when we extract the covisit counts explained above, the XGB reranker will boost +0.011 and achieve LB 0.601</p>\n<h1>(3) Twenty Covisit Matrices</h1>\n<p>Below are a description of my 20 covisit matrices. These covisit matrices are the secret sauce enabling my single XGB ranker model to achieve LB 0.601. The following variable names are from my new LB 0.590 notebook posted <a href=\"https://www.kaggle.com/cdeotte/rules-only-model-achieves-lb-590\" target=\"_blank\">here</a>. (Example code showing how to compute covisit matrices on GPU is <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">here</a>)</p>\n<ul>\n<li><strong>top_20</strong> - this covisit matrix is in my original notebook</li>\n<li><strong>top_20b</strong> - all covisit pair counts are consecutive items. See code below.<br>\n<code>df['k'] = np.arange(len(df))</code><br>\n<code>df = df.merge(df, on=['session'])</code><br>\n<code>df = df.loc[ (df.k_y - df.k_x).abs()==1 ]</code></li>\n<li><strong>top_20c</strong> - all covisit pair counts are <code>(df.k_y - df.k_x).abs()&lt;=2</code></li>\n<li><strong>top_20d</strong> - all covisit pairs are carts/orders and forward at most 3 consecutive<br>\n<code>df = df.loc[df['type'].isin(['carts','orders'])]</code><br>\n<code>df = df.merge(df, on=['session'])</code><br>\n<code>df = df.loc[ (df.k_y - df.k_x &gt; 0) &amp; (df.k_y - df.k_x &lt;= 3) ]</code></li>\n<li><strong>top_20e</strong> - all covisit pairs are <code>(df.k_y - df.k_x).abs()&lt;=3</code> and have time decay with<br>\n<code>df['wgt'] = (1/2)**( (df.ts_x - df.ts_y).abs() /60/60)</code></li>\n<li><strong>top_20f</strong> - same as above but <code>(df.k_y - df.k_x).abs()&lt;=6</code></li>\n<li><strong>top_20_orders</strong> - this covisit matrix is in my original notebook</li>\n<li><strong>top_20_buy2buy</strong> - this covisit matrix is in my original notebook</li>\n<li><strong>top_20_buy2buy2</strong> - use most recent 3 weeks data and only carts/orders. Apply time decay shown above.</li>\n<li><strong>top_20_test</strong> - use most recent 3 weeks data. Only forward in time pairs. Use clicks/carts/orders to carts/orders. Add time decay<br>\n<code>df = df.loc[df.ts &gt;= LAST_3_WEEKS ]</code><br>\n<code>df2 = df.loc[df['type'].isin(['carts','orders'])]</code><br>\n<code>df = df.merge(df2, on=['session'])</code><br>\n<code>df = df.loc[ df.ts_y - df.ts_x &gt; 0 ]</code><br>\n<code>df['wgt'] = (1/2)**( (df.ts_x - df.ts_y).abs() /60/60)</code></li>\n<li><strong>top_20_test2</strong> - use most recent 2 weeks data with time decay.</li>\n<li><strong>top_20_buy</strong> - Limit to forward 2 hours. Use clicks/carts/orders to carts/orders. Apply time decay.</li>\n<li><strong>top_20_new</strong> - Find cold start users in train. Pairs using only their first history item. Use clicks/carts/orders to carts/orders.<br>\n<code>df['x'] = df.groupby('session').ts.transform('min')</code><br>\n<code>df = df.loc[df.x &gt; train.ts.min() + TWO_WEEKS ]</code><br>\n<code>df['n'] = df.groupby('session').cumcount()</code><br>\n<code>df2 = df.loc[df['n']==0]</code><br>\n<code>df3 = df.loc[df['type'].isin(['carts','orders'])]</code><br>\n<code>df = df2.merge(df3, on='session')</code></li>\n<li><strong>top_20_new2</strong> - Find cold start users in train. Pairs using only their first history item. Use clicks/carts/orders to clicks/carts/orders. Apply time decay.</li>\n<li><strong>top_40_day</strong> - Use only last week data. Forward in time. Clicks/carts/orders to carts/orders. Time decay</li>\n<li><strong>top_40_day2</strong> - Use only last week data. Time decay</li>\n<li><strong>top_40_less</strong> - Train users with less than 6 history and test users with less than 3<br>\n<code>df = df.loc[df[COUNT]&lt;THRESHOLD]</code><br>\n<code>df = df.merge(df, on='session')</code></li>\n<li><strong>top_40_more</strong> - Train users with more than 6 history and test users with more than 3</li>\n<li><strong>top_40_less2</strong> - Use item pairs with first item before 2pm. Clicks/carts/orders to carts/orders. Time decay<br>\n<code>df2 = df.loc[df[HOUR]&lt;14]</code><br>\n<code>df = df2.merge(df, on='session')</code></li>\n<li><strong>top_40_more2</strong> - Use item pairs with first item after 2pm. Clicks/carts/orders to carts/orders. Time decay</li>\n</ul>\n<h1>Fast Covisit Experiments With RAPIDS cuDF</h1>\n<p>To find the above 20 covisit matrices, i computed hundreds of covisit matrices and then computed local CV score. To make covisit matrices quickly, I used RAPIDS cuDF to make each covisit matrix on GPU in under 1 minute. Code to make covisit matrix is shown <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">here</a>. Matrices were made using Nvidia 4xV100 32GB GPUs.</p>\n<h1>UPDATE: GitHub Code!</h1>\n<p>I published all 261 jupyter notebooks in my GitHub <a href=\"https://github.com/cdeotte/Kaggle-OTTO-Comp\" target=\"_blank\">here</a>. Specially we can review all the code used to generate co-visititation matices. And we can see the pipeline for building, training, inferring a GBT reranker model. Our team's final Kaggle inference submit notebook is <a href=\"https://www.kaggle.com/code/cdeotte/3rd-place-team-g-b-d-t-0-604\" target=\"_blank\">here</a>. My notebook to generate 100 candidates for reranker is <a href=\"https://www.kaggle.com/cdeotte/rules-only-model-achieves-lb-590\" target=\"_blank\">here</a>. By itself it scores 49th place LB 0.590!</p>",
  "messages": [
    {
      "id": 2125843,
      "postDate": "2023-02-01T23:45:34.770Z",
      "content": "<h1>Team G &amp; B &amp; D &amp; T</h1>\n<p>It was a pleasure to work with <a href=\"https://www.kaggle.com/titericz\" target=\"_blank\">@titericz</a> <a href=\"https://www.kaggle.com/benediktschifferer\" target=\"_blank\">@benediktschifferer</a> <a href=\"https://www.kaggle.com/theoviel\" target=\"_blank\">@theoviel</a> . We each made individual models and then ensembled all our work together by adding the ranks of each of our predictions per user target type. Below I describe my individual single model. My teammates will describe their work in their own discussion posts. You can read about Theo's LB 0.6029 model <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/382975\" target=\"_blank\">here</a>! You can read about Benny's LB 0.601 model <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/386497\" target=\"_blank\">here</a>!</p>\n<p>Most of my solution was made public in my notebook <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">here</a> and discussion <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\" target=\"_blank\">here</a> during the competition. There were only 3 significant ideas missing from my public work. Let's discuss how to boost my public work to LB 0.601 single model. (UPDATE: All code published to GitHub <a href=\"https://github.com/cdeotte/Kaggle-OTTO-Comp\" target=\"_blank\">here</a>)</p>\n<h1>How To Score LB 0.601 Single Model</h1>\n<p>It was explained <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/364721\" target=\"_blank\">here</a> and <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\" target=\"_blank\">here</a> that the best approach was \"candidate rerank\" model. My public notebook <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">here</a> shows how to achieve LB 0.575. And my discussion post <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\" target=\"_blank\">here</a> explains how to improve my public notebook by adding a GBT ranker model. Below are the three missing pieces labeled (1), (2), and (3) to achieve LB 0.601</p>\n<h1>(1) Choosing Candidates</h1>\n<p>To build a \"candidate rerank\", we need candidates. Where do we get candidates? The easiest way is to get them from my public notebook. In the <code>def suggest_buys(df)</code> and <code>def suggest_clicks(df)</code> function, the last lines are</p>\n<pre><code>top_aids = [aid for aid, ct in aids_counter.most_common(20)] \nreturn top_aids\n</code></pre>\n<p>To generate 50 candidates, we change 20 to 50 as in</p>\n<pre><code>top_aids = [aid for aid, ct in aids_counter.most_common(50)] \nreturn top_aids\n</code></pre>\n<h1>(2) Choosing Interaction Features</h1>\n<p>We now have 50 candidates per user from our public notebook above. Next we need to make features for our reranker model. The strongest and easiest way to make features is extract our co-visit counts by changing the last two lines of my public notebook to the following:</p>\n<pre><code>top_counts = [ct for aid, ct in aids_counter.most_common(50)] \nreturn top_counts\n</code></pre>\n<p>When we merge these counts to our candidates, we now have an interaction feature for each user item pair. To make more interaction features, we can extract the counts for each co-visit matrix individually. For example, imagine that we have 3 co-visit matrices named covisit2, covisit3, and covist4. Then one by one, we extract each covisit's counts:</p>\n<pre><code>EXTRACT = ['covisit2']\naids_counter = Counter()\nif 'covisit2' in EXTRACT:\n    aids = list(itertools.chain(*[covisit2[aid] for aid in unique_aids if aid in covisit2]))\n    for a in aids: aids_counter[a] += 1\nif 'covisit3' in EXTRACT:\n    aids = list(itertools.chain(*[covisit3[aid] for aid in unique_aids if aid in covisit3]))\n    for a in aids: aids_counter[a] += 1\nif 'covisit4' in EXTRACT:\n    aids = list(itertools.chain(*[covisit4[aid] for aid in unique_aids if aid in covisit4]))\n    for a in aids: aids_counter[a] += 1\ntop_counts = [ct for aid, ct in aids_counter.most_common(50)] \nreturn top_counts\n</code></pre>\n<h1>Reranker Boost CV and LB +0.011</h1>\n<p>First we use the technique above to generate candidates and the technique above to extract covisit counts. Next we add some simple item and user features like counting the number of times an item is click cart or order. When we apply the XGB reranker described <a href=\"https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\" target=\"_blank\">here</a>, our CV and LB will boost by <code>+0.011</code>. For example, the public notebook will boost to LB 0.586.</p>\n<h1>Using Rules Only (without reranker) Scores LB 0.590</h1>\n<p>To score over LB 0.600, we create more co-visit matrices to boost the original notebook's LB score. My public notebook uses 3 covisit matrices and achieves LB 0.575. If we make 17 more covisit matrices, we can boost my public \"rules only\" notebook to LB 0.590 (new notebook published <a href=\"https://www.kaggle.com/cdeotte/rules-only-model-achieves-lb-590\" target=\"_blank\">here</a>). Then when we extract the covisit counts explained above, the XGB reranker will boost +0.011 and achieve LB 0.601</p>\n<h1>(3) Twenty Covisit Matrices</h1>\n<p>Below are a description of my 20 covisit matrices. These covisit matrices are the secret sauce enabling my single XGB ranker model to achieve LB 0.601. The following variable names are from my new LB 0.590 notebook posted <a href=\"https://www.kaggle.com/cdeotte/rules-only-model-achieves-lb-590\" target=\"_blank\">here</a>. (Example code showing how to compute covisit matrices on GPU is <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">here</a>)</p>\n<ul>\n<li><strong>top_20</strong> - this covisit matrix is in my original notebook</li>\n<li><strong>top_20b</strong> - all covisit pair counts are consecutive items. See code below.<br>\n<code>df['k'] = np.arange(len(df))</code><br>\n<code>df = df.merge(df, on=['session'])</code><br>\n<code>df = df.loc[ (df.k_y - df.k_x).abs()==1 ]</code></li>\n<li><strong>top_20c</strong> - all covisit pair counts are <code>(df.k_y - df.k_x).abs()&lt;=2</code></li>\n<li><strong>top_20d</strong> - all covisit pairs are carts/orders and forward at most 3 consecutive<br>\n<code>df = df.loc[df['type'].isin(['carts','orders'])]</code><br>\n<code>df = df.merge(df, on=['session'])</code><br>\n<code>df = df.loc[ (df.k_y - df.k_x &gt; 0) &amp; (df.k_y - df.k_x &lt;= 3) ]</code></li>\n<li><strong>top_20e</strong> - all covisit pairs are <code>(df.k_y - df.k_x).abs()&lt;=3</code> and have time decay with<br>\n<code>df['wgt'] = (1/2)**( (df.ts_x - df.ts_y).abs() /60/60)</code></li>\n<li><strong>top_20f</strong> - same as above but <code>(df.k_y - df.k_x).abs()&lt;=6</code></li>\n<li><strong>top_20_orders</strong> - this covisit matrix is in my original notebook</li>\n<li><strong>top_20_buy2buy</strong> - this covisit matrix is in my original notebook</li>\n<li><strong>top_20_buy2buy2</strong> - use most recent 3 weeks data and only carts/orders. Apply time decay shown above.</li>\n<li><strong>top_20_test</strong> - use most recent 3 weeks data. Only forward in time pairs. Use clicks/carts/orders to carts/orders. Add time decay<br>\n<code>df = df.loc[df.ts &gt;= LAST_3_WEEKS ]</code><br>\n<code>df2 = df.loc[df['type'].isin(['carts','orders'])]</code><br>\n<code>df = df.merge(df2, on=['session'])</code><br>\n<code>df = df.loc[ df.ts_y - df.ts_x &gt; 0 ]</code><br>\n<code>df['wgt'] = (1/2)**( (df.ts_x - df.ts_y).abs() /60/60)</code></li>\n<li><strong>top_20_test2</strong> - use most recent 2 weeks data with time decay.</li>\n<li><strong>top_20_buy</strong> - Limit to forward 2 hours. Use clicks/carts/orders to carts/orders. Apply time decay.</li>\n<li><strong>top_20_new</strong> - Find cold start users in train. Pairs using only their first history item. Use clicks/carts/orders to carts/orders.<br>\n<code>df['x'] = df.groupby('session').ts.transform('min')</code><br>\n<code>df = df.loc[df.x &gt; train.ts.min() + TWO_WEEKS ]</code><br>\n<code>df['n'] = df.groupby('session').cumcount()</code><br>\n<code>df2 = df.loc[df['n']==0]</code><br>\n<code>df3 = df.loc[df['type'].isin(['carts','orders'])]</code><br>\n<code>df = df2.merge(df3, on='session')</code></li>\n<li><strong>top_20_new2</strong> - Find cold start users in train. Pairs using only their first history item. Use clicks/carts/orders to clicks/carts/orders. Apply time decay.</li>\n<li><strong>top_40_day</strong> - Use only last week data. Forward in time. Clicks/carts/orders to carts/orders. Time decay</li>\n<li><strong>top_40_day2</strong> - Use only last week data. Time decay</li>\n<li><strong>top_40_less</strong> - Train users with less than 6 history and test users with less than 3<br>\n<code>df = df.loc[df[COUNT]&lt;THRESHOLD]</code><br>\n<code>df = df.merge(df, on='session')</code></li>\n<li><strong>top_40_more</strong> - Train users with more than 6 history and test users with more than 3</li>\n<li><strong>top_40_less2</strong> - Use item pairs with first item before 2pm. Clicks/carts/orders to carts/orders. Time decay<br>\n<code>df2 = df.loc[df[HOUR]&lt;14]</code><br>\n<code>df = df2.merge(df, on='session')</code></li>\n<li><strong>top_40_more2</strong> - Use item pairs with first item after 2pm. Clicks/carts/orders to carts/orders. Time decay</li>\n</ul>\n<h1>Fast Covisit Experiments With RAPIDS cuDF</h1>\n<p>To find the above 20 covisit matrices, i computed hundreds of covisit matrices and then computed local CV score. To make covisit matrices quickly, I used RAPIDS cuDF to make each covisit matrix on GPU in under 1 minute. Code to make covisit matrix is shown <a href=\"https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\" target=\"_blank\">here</a>. Matrices were made using Nvidia 4xV100 32GB GPUs.</p>\n<h1>UPDATE: GitHub Code!</h1>\n<p>I published all 261 jupyter notebooks in my GitHub <a href=\"https://github.com/cdeotte/Kaggle-OTTO-Comp\" target=\"_blank\">here</a>. Specially we can review all the code used to generate co-visititation matices. And we can see the pipeline for building, training, inferring a GBT reranker model. Our team's final Kaggle inference submit notebook is <a href=\"https://www.kaggle.com/code/cdeotte/3rd-place-team-g-b-d-t-0-604\" target=\"_blank\">here</a>. My notebook to generate 100 candidates for reranker is <a href=\"https://www.kaggle.com/cdeotte/rules-only-model-achieves-lb-590\" target=\"_blank\">here</a>. By itself it scores 49th place LB 0.590!</p>",
      "rawMarkdown": "# Team G & B & D & T\nIt was a pleasure to work with @titericz @benediktschifferer @theoviel . We each made individual models and then ensembled all our work together by adding the ranks of each of our predictions per user target type. Below I describe my individual single model. My teammates will describe their work in their own discussion posts. You can read about Theo's LB 0.6029 model [here][5]! You can read about Benny's LB 0.601 model [here][8]!\n\nMost of my solution was made public in my notebook [here][3] and discussion [here][2] during the competition. There were only 3 significant ideas missing from my public work. Let's discuss how to boost my public work to LB 0.601 single model. (UPDATE: All code published to GitHub [here][6])\n\n# How To Score LB 0.601 Single Model\nIt was explained [here][1] and [here][2] that the best approach was \"candidate rerank\" model. My public notebook [here][3] shows how to achieve LB 0.575. And my discussion post [here][2] explains how to improve my public notebook by adding a GBT ranker model. Below are the three missing pieces labeled (1), (2), and (3) to achieve LB 0.601\n\n# (1) Choosing Candidates\nTo build a \"candidate rerank\", we need candidates. Where do we get candidates? The easiest way is to get them from my public notebook. In the `def suggest_buys(df)` and `def suggest_clicks(df)` function, the last lines are\n\n    top_aids = [aid for aid, ct in aids_counter.most_common(20)] \n    return top_aids\n\nTo generate 50 candidates, we change 20 to 50 as in\n\n    top_aids = [aid for aid, ct in aids_counter.most_common(50)] \n    return top_aids\n\n# (2) Choosing Interaction Features\nWe now have 50 candidates per user from our public notebook above. Next we need to make features for our reranker model. The strongest and easiest way to make features is extract our co-visit counts by changing the last two lines of my public notebook to the following:\n\n    top_counts = [ct for aid, ct in aids_counter.most_common(50)] \n    return top_counts\n\nWhen we merge these counts to our candidates, we now have an interaction feature for each user item pair. To make more interaction features, we can extract the counts for each co-visit matrix individually. For example, imagine that we have 3 co-visit matrices named covisit2, covisit3, and covist4. Then one by one, we extract each covisit's counts:\n\n    EXTRACT = ['covisit2']\n    aids_counter = Counter()\n    if 'covisit2' in EXTRACT:\n        aids = list(itertools.chain(*[covisit2[aid] for aid in unique_aids if aid in covisit2]))\n        for a in aids: aids_counter[a] += 1\n    if 'covisit3' in EXTRACT:\n        aids = list(itertools.chain(*[covisit3[aid] for aid in unique_aids if aid in covisit3]))\n        for a in aids: aids_counter[a] += 1\n    if 'covisit4' in EXTRACT:\n        aids = list(itertools.chain(*[covisit4[aid] for aid in unique_aids if aid in covisit4]))\n        for a in aids: aids_counter[a] += 1\n    top_counts = [ct for aid, ct in aids_counter.most_common(50)] \n    return top_counts\n\n# Reranker Boost CV and LB +0.011\nFirst we use the technique above to generate candidates and the technique above to extract covisit counts. Next we add some simple item and user features like counting the number of times an item is click cart or order. When we apply the XGB reranker described [here][2], our CV and LB will boost by `+0.011`. For example, the public notebook will boost to LB 0.586.\n\n# Using Rules Only (without reranker) Scores LB 0.590\nTo score over LB 0.600, we create more co-visit matrices to boost the original notebook's LB score. My public notebook uses 3 covisit matrices and achieves LB 0.575. If we make 17 more covisit matrices, we can boost my public \"rules only\" notebook to LB 0.590 (new notebook published [here][4]). Then when we extract the covisit counts explained above, the XGB reranker will boost +0.011 and achieve LB 0.601\n\n# (3) Twenty Covisit Matrices\nBelow are a description of my 20 covisit matrices. These covisit matrices are the secret sauce enabling my single XGB ranker model to achieve LB 0.601. The following variable names are from my new LB 0.590 notebook posted [here][4]. (Example code showing how to compute covisit matrices on GPU is [here][3])\n* **top_20** - this covisit matrix is in my original notebook\n* **top_20b** - all covisit pair counts are consecutive items. See code below.\n    `df['k'] = np.arange(len(df))`\n    `df = df.merge(df, on=['session'])`\n    `df = df.loc[ (df.k_y - df.k_x).abs()==1 ]`\n* **top_20c** - all covisit pair counts are `(df.k_y - df.k_x).abs()<=2`\n* **top_20d** - all covisit pairs are carts/orders and forward at most 3 consecutive\n    `df = df.loc[df['type'].isin(['carts','orders'])]`\n    `df = df.merge(df, on=['session'])`\n    `df = df.loc[ (df.k_y - df.k_x > 0) & (df.k_y - df.k_x <= 3) ]`\n* **top_20e** - all covisit pairs are `(df.k_y - df.k_x).abs()<=3` and have time decay with\n    `df['wgt'] = (1/2)**( (df.ts_x - df.ts_y).abs() /60/60)`\n* **top_20f** - same as above but `(df.k_y - df.k_x).abs()<=6`\n* **top_20_orders** - this covisit matrix is in my original notebook\n* **top_20_buy2buy** - this covisit matrix is in my original notebook\n* **top_20_buy2buy2** - use most recent 3 weeks data and only carts/orders. Apply time decay shown above.\n* **top_20_test** - use most recent 3 weeks data. Only forward in time pairs. Use clicks/carts/orders to carts/orders. Add time decay\n    `df = df.loc[df.ts >= LAST_3_WEEKS ]`\n    `df2 = df.loc[df['type'].isin(['carts','orders'])]`\n    `df = df.merge(df2, on=['session'])`\n    `df = df.loc[ df.ts_y - df.ts_x > 0 ]`\n    `df['wgt'] = (1/2)**( (df.ts_x - df.ts_y).abs() /60/60)`\n* **top_20_test2** - use most recent 2 weeks data with time decay.\n* **top_20_buy** - Limit to forward 2 hours. Use clicks/carts/orders to carts/orders. Apply time decay.\n* **top_20_new** - Find cold start users in train. Pairs using only their first history item. Use clicks/carts/orders to carts/orders.\n    `df['x'] = df.groupby('session').ts.transform('min')`\n    `df = df.loc[df.x > train.ts.min() + TWO_WEEKS ]`\n    `df['n'] = df.groupby('session').cumcount()`\n    `df2 = df.loc[df['n']==0]`\n    `df3 = df.loc[df['type'].isin(['carts','orders'])]`\n    `df = df2.merge(df3, on='session')`\n* **top_20_new2** - Find cold start users in train. Pairs using only their first history item. Use clicks/carts/orders to clicks/carts/orders. Apply time decay.\n* **top_40_day** - Use only last week data. Forward in time. Clicks/carts/orders to carts/orders. Time decay\n* **top_40_day2** - Use only last week data. Time decay\n* **top_40_less** - Train users with less than 6 history and test users with less than 3\n    `df = df.loc[df[COUNT]<THRESHOLD]`\n    `df = df.merge(df, on='session')`\n* **top_40_more** - Train users with more than 6 history and test users with more than 3\n* **top_40_less2** - Use item pairs with first item before 2pm. Clicks/carts/orders to carts/orders. Time decay\n    `df2 = df.loc[df[HOUR]<14]`\n    `df = df2.merge(df, on='session')`\n* **top_40_more2** - Use item pairs with first item after 2pm. Clicks/carts/orders to carts/orders. Time decay\n\n# Fast Covisit Experiments With RAPIDS cuDF\nTo find the above 20 covisit matrices, i computed hundreds of covisit matrices and then computed local CV score. To make covisit matrices quickly, I used RAPIDS cuDF to make each covisit matrix on GPU in under 1 minute. Code to make covisit matrix is shown [here][3]. Matrices were made using Nvidia 4xV100 32GB GPUs.\n\n# UPDATE: GitHub Code!\nI published all 261 jupyter notebooks in my GitHub [here][6]. Specially we can review all the code used to generate co-visititation matices. And we can see the pipeline for building, training, inferring a GBT reranker model. Our team's final Kaggle inference submit notebook is [here][7]. My notebook to generate 100 candidates for reranker is [here][4]. By itself it scores 49th place LB 0.590!\n\n[1]: https://www.kaggle.com/competitions/otto-recommender-system/discussion/364721\n[2]: https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\n[3]: https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\n[4]: https://www.kaggle.com/cdeotte/rules-only-model-achieves-lb-590\n[5]: https://www.kaggle.com/competitions/otto-recommender-system/discussion/382975\n[6]: https://github.com/cdeotte/Kaggle-OTTO-Comp\n[7]: https://www.kaggle.com/code/cdeotte/3rd-place-team-g-b-d-t-0-604\n[8]: https://www.kaggle.com/competitions/otto-recommender-system/discussion/386497",
      "votes": 151
    },
    {
      "id": 2144158,
      "postDate": "2023-02-14T19:15:12.750Z",
      "content": "<p>UPDATE: I published all 261 jupyter notebooks to run my full single model LB 0.601 solution at GitHub here: <a href=\"https://github.com/cdeotte/Kaggle-OTTO-Comp\" target=\"_blank\">https://github.com/cdeotte/Kaggle-OTTO-Comp</a></p>",
      "rawMarkdown": "UPDATE: I published all 261 jupyter notebooks to run my full single model LB 0.601 solution at GitHub here: https://github.com/cdeotte/Kaggle-OTTO-Comp",
      "votes": 7
    },
    {
      "id": 2127112,
      "postDate": "2023-02-02T17:23:28.827Z",
      "content": "<p>Everything looks so easy when reading the describtion of your solution. I've even thought for a moment \"how could it happen that I didn't try it myself?\" <br>\nWith just kaggle notebooks running all the possible experiments is more tricky. And anyway, I didn't even think about some of your matrices, like before/after 2PM, only users with short history, only last week. I did make a matrice for exact next aid, but only used it for clicks and didn't even try to apply it to carts/orders.</p>\n<p>And again, thank you for you clear and insightfull posts, both during and after the competition.</p>",
      "rawMarkdown": "Everything looks so easy when reading the describtion of your solution. I've even thought for a moment \"how could it happen that I didn't try it myself?\" \nWith just kaggle notebooks running all the possible experiments is more tricky. And anyway, I didn't even think about some of your matrices, like before/after 2PM, only users with short history, only last week. I did make a matrice for exact next aid, but only used it for clicks and didn't even try to apply it to carts/orders.\n\nAnd again, thank you for you clear and insightfull posts, both during and after the competition.",
      "votes": 3
    },
    {
      "id": 2127417,
      "postDate": "2023-02-02T21:45:54.857Z",
      "content": "<p>Great job <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> and the rest of the team! 🥳 Amazing performance!</p>\n<p>This write up reads like a good detective story, the plot is so clearly explained! So cool to understand what you did to achieve this phenomenal result. Love the progression from the public kernel with the co-visitation matrices there to the full solution using the reranker!</p>\n<p>Congrats again and thank you for this great write-up! </p>",
      "rawMarkdown": "Great job @cdeotte and the rest of the team! 🥳 Amazing performance!\n\nThis write up reads like a good detective story, the plot is so clearly explained! So cool to understand what you did to achieve this phenomenal result. Love the progression from the public kernel with the co-visitation matrices there to the full solution using the reranker!\n\nCongrats again and thank you for this great write-up! ",
      "votes": 4,
      "replies": [
        {
          "id": 2128306,
          "postDate": "2023-02-03T15:59:16.260Z",
          "content": "<p>Thanks Radek. Thanks for all your sharing during the competition!</p>",
          "rawMarkdown": "Thanks Radek. Thanks for all your sharing during the competition!"
        }
      ]
    },
    {
      "id": 2186719,
      "postDate": "2023-03-18T03:42:24.003Z",
      "content": "<p>thx for sharing, really learn a lot from that</p>",
      "rawMarkdown": "thx for sharing, really learn a lot from that",
      "votes": 1
    },
    {
      "id": 2146750,
      "postDate": "2023-02-16T05:38:22.827Z",
      "content": "<p>Congratulations <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> excellent work.</p>",
      "rawMarkdown": "Congratulations @cdeotte excellent work.",
      "votes": 1
    },
    {
      "id": 2141778,
      "postDate": "2023-02-13T05:00:00.417Z",
      "content": "<p>Wow, congratulations on taking 3rd place in the competition! Your solution is impressive OAO</p>\n<p>I learnt your approach to using RAPID cuDF to quickly compute hundreds of covisit matrices and then compute the local CV score is clever. I can imagine that this saved a lot of time and allowed me to experiment more efficiently in the future!</p>\n<p>Thank for sharing!</p>",
      "rawMarkdown": "Wow, congratulations on taking 3rd place in the competition! Your solution is impressive OAO\n\nI learnt your approach to using RAPID cuDF to quickly compute hundreds of covisit matrices and then compute the local CV score is clever. I can imagine that this saved a lot of time and allowed me to experiment more efficiently in the future!\n\nThank for sharing!",
      "votes": 1
    },
    {
      "id": 2139626,
      "postDate": "2023-02-10T23:35:14.827Z",
      "content": "<p>Congratulations! Great read!</p>",
      "rawMarkdown": "Congratulations! Great read!",
      "votes": 1
    },
    {
      "id": 2138097,
      "postDate": "2023-02-10T14:55:52.430Z",
      "content": "<p>I saw that in your open source code, the saved file name of the feature is gpu-116<br>\n;gpu-220 and so on, why are they named so?</p>",
      "rawMarkdown": "I saw that in your open source code, the saved file name of the feature is gpu-116\n;gpu-220 and so on, why are they named so?",
      "votes": 1,
      "replies": [
        {
          "id": 2139629,
          "postDate": "2023-02-10T23:39:28.810Z",
          "content": "<p>This was experiment 116 and experiment 220. I made hundreds of different co-visit matrices and computed validation score to see which were the best.</p>",
          "rawMarkdown": "This was experiment 116 and experiment 220. I made hundreds of different co-visit matrices and computed validation score to see which were the best.",
          "votes": 1
        }
      ]
    },
    {
      "id": 2131421,
      "postDate": "2023-02-06T05:14:31.107Z",
      "content": "<p>Hello Chris,<br>\nGreat work and Congratulations.<br>\nI try to implement your idea but feel a little confused in some covisit items.<br>\nCould you slightly talk about if you don't mind: </p>\n<ol>\n<li>What's the difference between top_20_new and top_20_new2?</li>\n<li>What's the definition of 'cold start'? is the user's first action time - start time &gt; 2days? or 1week? </li>\n<li>In top_40_less2 / top_40_more2, we'll filter the specific users by actions more/less than 6(3), and filter by first item time before/after 2pm, am I right?<br>\nThanks for sharing the idea/notebook, really fantastic.</li>\n</ol>",
      "rawMarkdown": "Hello Chris,\nGreat work and Congratulations.\nI try to implement your idea but feel a little confused in some covisit items.\nCould you slightly talk about if you don't mind: \n1. What's the difference between top_20_new and top_20_new2?\n2. What's the definition of 'cold start'? is the user's first action time - start time > 2days? or 1week? \n3. In top_40_less2 / top_40_more2, we'll filter the specific users by actions more/less than 6(3), and filter by first item time before/after 2pm, am I right?\nThanks for sharing the idea/notebook, really fantastic.",
      "votes": 1,
      "replies": [
        {
          "id": 2132156,
          "postDate": "2023-02-06T16:23:48.880Z",
          "content": "<p>Thanks ChickenBoy,</p>\n<ol>\n<li><p>top_20_new is clicks/carts/orders to carts/orders without time decay. And top_20_new2 is clicks/carts/orders to clicks/carts/orders with time decay.</p></li>\n<li><p>Cold start is <code>user_first_action - dataset_start_time &gt; 2 weeks</code></p>\n<p>df['x'] = df.groupby('session').ts.transform('min')<br>\n df = df.loc[df.x &gt; train.ts.min() + TWO_WEEKS ]<br>\n df['n'] = df.groupby('session').cumcount()<br>\n df2 = df.loc[df['n']==0]<br>\n df3 = df.loc[df['type'].isin(['carts','orders'])]<br>\n df = df2.merge(df3, on='session')</p></li>\n<li><p>In top_40_more/less, we filter users</p>\n<p>df = df.loc[df[COUNT]&lt;THRESHOLD] <br>\n df = df.merge(df, on='session')</p></li>\n</ol>\n<p>And in top_40_more2/less2, we filter first item. </p>\n<pre><code>df2 = df.loc[df[HOUR]&lt;14]\ndf = df2.merge(df, on='session')\n</code></pre>",
          "rawMarkdown": "Thanks ChickenBoy,\n\n1. top_20_new is clicks/carts/orders to carts/orders without time decay. And top_20_new2 is clicks/carts/orders to clicks/carts/orders with time decay.\n\n2. Cold start is `user_first_action - dataset_start_time > 2 weeks `\n\n     df['x'] = df.groupby('session').ts.transform('min')\n     df = df.loc[df.x > train.ts.min() + TWO_WEEKS ]\n     df['n'] = df.groupby('session').cumcount()\n     df2 = df.loc[df['n']==0]\n     df3 = df.loc[df['type'].isin(['carts','orders'])]\n     df = df2.merge(df3, on='session')\n\n3. In top_40_more/less, we filter users\n  \n     df = df.loc[df[COUNT]<THRESHOLD] \n     df = df.merge(df, on='session')\n  \nAnd in top_40_more2/less2, we filter first item. \n\n    df2 = df.loc[df[HOUR]<14]\n    df = df2.merge(df, on='session')",
          "votes": 2,
          "replies": [
            {
              "id": 2132225,
              "postDate": "2023-02-06T17:12:18.810Z",
              "content": "<p>Thanks! Really helpful👍👍👍</p>",
              "rawMarkdown": "Thanks! Really helpful👍👍👍",
              "votes": 2
            }
          ]
        }
      ]
    },
    {
      "id": 2129831,
      "postDate": "2023-02-04T22:50:36.573Z",
      "content": "<p>A useful share. Thanks I will use this in my project</p>",
      "rawMarkdown": "A useful share. Thanks I will use this in my project",
      "votes": 1
    },
    {
      "id": 2129759,
      "postDate": "2023-02-04T20:51:34.087Z",
      "content": "<p>Nice write down</p>",
      "rawMarkdown": "Nice write down",
      "votes": 1
    },
    {
      "id": 2128550,
      "postDate": "2023-02-03T19:47:20.930Z",
      "content": "<p>Great breakdown</p>",
      "rawMarkdown": "Great breakdown",
      "votes": 1
    },
    {
      "id": 2127381,
      "postDate": "2023-02-02T21:03:21.687Z",
      "content": "<p>Congratulations! <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> <br>\nAnd Thanks it helped me to understand  about Competition ranking in Kaggle.</p>",
      "rawMarkdown": "Congratulations! @cdeotte \nAnd Thanks it helped me to understand  about Competition ranking in Kaggle.",
      "votes": 1
    },
    {
      "id": 2126362,
      "postDate": "2023-02-02T07:34:08.147Z",
      "content": "<p>Thank you for sharing. It helped me a lot.</p>\n<p>Could you share the code for building a reank model using your CV notebook and LB notebook?</p>\n<p>I had a hard time making a reank model using candidates.</p>\n<p>Thank you.</p>",
      "rawMarkdown": "Thank you for sharing. It helped me a lot.\n\nCould you share the code for building a reank model using your CV notebook and LB notebook?\n\nI had a hard time making a reank model using candidates.\n\nThank you.",
      "votes": 1
    },
    {
      "id": 2125980,
      "postDate": "2023-02-02T03:27:05.887Z",
      "content": "<p>Congratulations on your gold medal, and thanks for your great help - your code and suggestions were very influential (and have helped me get my first medal!)<br>\nYour work actually introduced me to <code>cuDF</code>, which I'm still new with and have a question I hope you could help. Beside reducing <code>dtype</code>, to preserve GPU memory I also remove unused stuffs, but from my experience <code>del</code> and <code>gc.collect()</code> do not always help with lowering GPU memory. Take the  example code snippet below - the memory usage doubles after the <code>merge</code>, and does not reduce after <code>del</code> and <code>gc.collect()</code>. Is it because of some caching property of <code>cuDF</code>?</p>\n<pre><code>\ndf1 = cudf.from_pandas(pd.load_parquet(path_1)) \ndf2 = cudf.from_pandas(pd.load_parquet(path_2)) \ndf1 = df1.merge(df2, on=, how=) \n df1, df2 \n_ = gc.collect() \n</code></pre>\n<p>Thank you!</p>",
      "rawMarkdown": "Congratulations on your gold medal, and thanks for your great help - your code and suggestions were very influential (and have helped me get my first medal!)\nYour work actually introduced me to `cuDF`, which I'm still new with and have a question I hope you could help. Beside reducing `dtype`, to preserve GPU memory I also remove unused stuffs, but from my experience `del` and `gc.collect()` do not always help with lowering GPU memory. Take the  example code snippet below - the memory usage doubles after the `merge`, and does not reduce after `del` and `gc.collect()`. Is it because of some caching property of `cuDF`?\n```python\n# GPU memory < 0.1 GBs\ndf1 = cudf.from_pandas(pd.load_parquet(path_1)) # GPU memory ~ 3.5 GBs\ndf2 = cudf.from_pandas(pd.load_parquet(path_2)) # GPU memory ~ 3.6 GBs\ndf1 = df1.merge(df2, on='session', how='left') # GPU memory ~ 7.0 GBs\ndel df1, df2 # GPU memory ~ 7.0 GBs\n_ = gc.collect() # GPU memory ~ 7.0 GBs\n```\nThank you!",
      "votes": 1,
      "replies": [
        {
          "id": 2126051,
          "postDate": "2023-02-02T04:22:58.530Z",
          "content": "<p>yes, sometimes memory usage does not decrease. In this situation, i save dataframe to disk as parquet. Then i shut down notebook and start a new notebook and read in the parquet. That will clear memory.</p>",
          "rawMarkdown": "yes, sometimes memory usage does not decrease. In this situation, i save dataframe to disk as parquet. Then i shut down notebook and start a new notebook and read in the parquet. That will clear memory.",
          "votes": 1,
          "replies": [
            {
              "id": 2126144,
              "postDate": "2023-02-02T05:42:19.227Z",
              "content": "<p>That's what I had to do to too! Also I google-ed around for an option to release unused GPU memory and found nothing related to cuDF but a few options for PyTorch (<a href=\"https://pytorch.org/docs/stable/generated/torch.cuda.empty_cache.html#torch-cuda-empty-cache\" target=\"_blank\">torch.cuda.empty_cache</a>, if I'm correct?). Would be nice if cuDF has something similar.<br>\nThanks Chris! </p>",
              "rawMarkdown": "That's what I had to do to too! Also I google-ed around for an option to release unused GPU memory and found nothing related to cuDF but a few options for PyTorch ([torch.cuda.empty_cache](https://pytorch.org/docs/stable/generated/torch.cuda.empty_cache.html#torch-cuda-empty-cache), if I'm correct?). Would be nice if cuDF has something similar.\nThanks Chris! ",
              "votes": 1
            },
            {
              "id": 2126164,
              "postDate": "2023-02-02T05:47:43.680Z",
              "rawMarkdown": "",
              "isDeleted": true
            },
            {
              "id": 2126168,
              "postDate": "2023-02-02T05:48:38.680Z",
              "content": "<p>I think this can help:<br>\n<code>#Free The GPU Memory</code><br>\n<code>from numba import cuda</code><br>\n<code>cuda.select_device(0)</code><br>\n<code>cuda.close()</code><br>\n<code>cuda.select_device(0)</code></p>",
              "rawMarkdown": "I think this can help:\n`#Free The GPU Memory`\n`from numba import cuda`\n`cuda.select_device(0)`\n`cuda.close()`\n`cuda.select_device(0)`",
              "votes": 3
            },
            {
              "id": 2126636,
              "postDate": "2023-02-02T10:56:16.127Z",
              "content": "<p>Thanks Mohamed! I have not tried this, but based on numba documentation this seems equivalent to restarting the kernel. Have you tried it?</p>",
              "rawMarkdown": "Thanks Mohamed! I have not tried this, but based on numba documentation this seems equivalent to restarting the kernel. Have you tried it?",
              "votes": 1
            },
            {
              "id": 2126678,
              "postDate": "2023-02-02T11:44:11.280Z",
              "content": "<p>I used it several times in \"American Express Competition\". Sometimes I encounter a permission issue (Not sure honestly why it appears sometimes), but other than that, it works perfectly.</p>",
              "rawMarkdown": "I used it several times in \"American Express Competition\". Sometimes I encounter a permission issue (Not sure honestly why it appears sometimes), but other than that, it works perfectly.",
              "votes": 1
            },
            {
              "id": 2126917,
              "postDate": "2023-02-02T15:04:20.790Z",
              "content": "<p>Sounds like what I'm looking for - will make sure to try it next time. Thanks again!</p>",
              "rawMarkdown": "Sounds like what I'm looking for - will make sure to try it next time. Thanks again!",
              "votes": 1
            }
          ]
        },
        {
          "id": 2129883,
          "postDate": "2023-02-05T01:20:17.170Z",
          "content": "<p>Put your cudf operations inside a function.  Then python releases GPU memory used inside the function after the return.</p>",
          "rawMarkdown": "Put your cudf operations inside a function.  Then python releases GPU memory used inside the function after the return.",
          "votes": 4
        }
      ]
    },
    {
      "id": 2125898,
      "postDate": "2023-02-02T01:24:28.653Z",
      "content": "<p>super cool!</p>",
      "rawMarkdown": "super cool!",
      "votes": 1,
      "replies": [
        {
          "id": 2125916,
          "postDate": "2023-02-02T01:50:43.040Z",
          "content": "<p>Thanks Adam</p>",
          "rawMarkdown": "Thanks Adam"
        }
      ]
    },
    {
      "id": 2125886,
      "postDate": "2023-02-02T00:58:10.020Z",
      "content": "<p>Thank you Chris, I won't get current ranking wihtout your public notebook。</p>\n<p>I have some doubts in the your gbdt public notebook  ：<br>\nI would like to know why there is no need to specify a group in Inference?<br>\nHow does the model judge whether the data is in the same group during inference?<br>\nDoes this mean that the inference group must be the same as the training group?<br>\nI looked at the docs but didn't find what I want to know, am I missing something?</p>\n<p>Please forgive me for asking the question here again 😂because I really want to know the answer</p>",
      "rawMarkdown": "Thank you Chris, I won't get current ranking wihtout your public notebook。\n\nI have some doubts in the your gbdt public notebook  ：\nI would like to know why there is no need to specify a group in Inference?\nHow does the model judge whether the data is in the same group during inference?\nDoes this mean that the inference group must be the same as the training group?\nI looked at the docs but didn't find what I want to know, am I missing something?\n\nPlease forgive me for asking the question here again 😂because I really want to know the answer\n",
      "votes": 1,
      "replies": [
        {
          "id": 2125888,
          "postDate": "2023-02-02T01:08:33.187Z",
          "content": "<p>Group is not needed during inference. The GBT will rank all rows during inference. So when we just look at each user during inference, the ranking will be correct.</p>\n<p>(Group is only needed during training)</p>",
          "rawMarkdown": "Group is not needed during inference. The GBT will rank all rows during inference. So when we just look at each user during inference, the ranking will be correct.\n\n(Group is only needed during training)",
          "votes": 1,
          "replies": [
            {
              "id": 2126217,
              "postDate": "2023-02-02T06:10:49.377Z",
              "content": "<p>Thanks Chris!</p>",
              "rawMarkdown": "Thanks Chris!",
              "votes": 1
            }
          ]
        }
      ]
    },
    {
      "id": 2130617,
      "postDate": "2023-02-05T15:20:20.370Z",
      "content": "<p>Nice work, it was very interesting to read! </p>",
      "rawMarkdown": "Nice work, it was very interesting to read! ",
      "votes": 2,
      "replies": [
        {
          "id": 2136039,
          "postDate": "2023-02-09T04:09:49.487Z",
          "content": "<p>Thanks Andrew!</p>",
          "rawMarkdown": "Thanks Andrew!",
          "votes": 1
        }
      ]
    },
    {
      "id": 2129630,
      "postDate": "2023-02-04T19:01:51.847Z",
      "content": "<p>The information you share is very valuable. Thanks for sharing. I will use it in my next rule based project</p>",
      "rawMarkdown": "The information you share is very valuable. Thanks for sharing. I will use it in my next rule based project",
      "votes": 2
    },
    {
      "id": 2128312,
      "postDate": "2023-02-03T16:05:20.163Z",
      "content": "<p>Congratulations, <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> on your outstanding results! Your exceptional problem-solving skills and strong intuition have truly inspired me. I have gained so much valuable knowledge from you. I am grateful for all the lessons and experiences you have shared with us. Thank you!</p>",
      "rawMarkdown": "Congratulations, @cdeotte on your outstanding results! Your exceptional problem-solving skills and strong intuition have truly inspired me. I have gained so much valuable knowledge from you. I am grateful for all the lessons and experiences you have shared with us. Thank you!",
      "votes": 2
    },
    {
      "id": 2127634,
      "postDate": "2023-02-03T02:24:13.223Z",
      "content": "<p>Congrats <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> and team on great results. Thanks for sharing throughout the competition, again learn alot from you!</p>",
      "rawMarkdown": "Congrats @cdeotte and team on great results. Thanks for sharing throughout the competition, again learn alot from you!",
      "votes": 2
    },
    {
      "id": 2126779,
      "postDate": "2023-02-02T13:01:10.733Z",
      "content": "<p>Congratulations! It's incredible how the rule based models could be pushed. My limit was 0.581 LB with rule based.<br>\nNext time I'll try out some of the ideas you presented.</p>\n<p>Again congratulations!</p>",
      "rawMarkdown": "Congratulations! It's incredible how the rule based models could be pushed. My limit was 0.581 LB with rule based.\nNext time I'll try out some of the ideas you presented.\n\nAgain congratulations!",
      "votes": 2
    },
    {
      "id": 2126498,
      "postDate": "2023-02-02T09:08:12.020Z",
      "content": "<p>I love your way to explain solution starting from baseline notebook. <br>\nI really learned a lot from your notebook and discusssions.<br>\nCongrats!</p>",
      "rawMarkdown": "I love your way to explain solution starting from baseline notebook. \nI really learned a lot from your notebook and discusssions.\nCongrats!",
      "votes": 2
    },
    {
      "id": 2126035,
      "postDate": "2023-02-02T04:10:10.003Z",
      "content": "<p>This is epic! Thanks for sharing <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a>!<br>\nOut of curiosity, what makes you stick with rule-based and creating various different covisit matrix while there's other techniques such as CF, MF and word2vec?</p>\n<p>and given all the count features, did you tune the ranker?</p>",
      "rawMarkdown": "This is epic! Thanks for sharing @cdeotte!\nOut of curiosity, what makes you stick with rule-based and creating various different covisit matrix while there's other techniques such as CF, MF and word2vec?\n\nand given all the count features, did you tune the ranker?",
      "votes": 2,
      "replies": [
        {
          "id": 2126053,
          "postDate": "2023-02-02T04:24:06.760Z",
          "content": "<p>I did everything. I pushed rule-based as far as it would go. Afterward, i used word2vec and matrix factorization to create features for my GBT reranker. Both helped.</p>",
          "rawMarkdown": "I did everything. I pushed rule-based as far as it would go. Afterward, i used word2vec and matrix factorization to create features for my GBT reranker. Both helped.",
          "votes": 1,
          "replies": [
            {
              "id": 2126080,
              "postDate": "2023-02-02T04:52:08.560Z",
              "content": "<p>Do you think LSTM Embeddings would help more than Word2Vec given that we have aids sorted by time? Just want to know if you made a similar experiment? </p>",
              "rawMarkdown": "Do you think LSTM Embeddings would help more than Word2Vec given that we have aids sorted by time? Just want to know if you made a similar experiment? ",
              "votes": 1
            },
            {
              "id": 2126096,
              "postDate": "2023-02-02T05:08:53.167Z",
              "content": "<p>I think all item embeddings would help. The trick was to first train some NN such as LSTM, Word2Vec, Matrix Factorization etc.</p>\n<p>Then we take the item embeddings and for each row in our candidate dataframe, we compute the cosine similarity between user history last item and candidate. Then user history 2nd to last, 3rd, 4th 5th. Then user history first item, 2nd, 3rd, 4th, 5th. Then user history last buy, 2nd to last buy, 3rd, 4th, 5th. Then finally we take aggregate means and standard deviations of groups of these values. These features were very helpful.</p>",
              "rawMarkdown": "I think all item embeddings would help. The trick was to first train some NN such as LSTM, Word2Vec, Matrix Factorization etc.\n\nThen we take the item embeddings and for each row in our candidate dataframe, we compute the cosine similarity between user history last item and candidate. Then user history 2nd to last, 3rd, 4th 5th. Then user history first item, 2nd, 3rd, 4th, 5th. Then user history last buy, 2nd to last buy, 3rd, 4th, 5th. Then finally we take aggregate means and standard deviations of groups of these values. These features were very helpful.",
              "votes": 3
            },
            {
              "id": 2126106,
              "postDate": "2023-02-02T05:15:13.997Z",
              "content": "<p>Nice! I tried a similar idea. I used Word2Vec, but calculated the cosine similarity between last, 2nd to last and 3rd to last interacted items and the last, 2nd to last and 3rd to last clicked/carted/ordered items. Honestly, I wanted to try the similarity between last clicked/carted/ordered and candidates but couldn't find enough time for that as that it was already the last day of the competition. Kudos to <a href=\"https://www.kaggle.com/tezdhar\" target=\"_blank\">@tezdhar</a> for our great ideas!</p>",
              "rawMarkdown": "Nice! I tried a similar idea. I used Word2Vec, but calculated the cosine similarity between last, 2nd to last and 3rd to last interacted items and the last, 2nd to last and 3rd to last clicked/carted/ordered items. Honestly, I wanted to try the similarity between last clicked/carted/ordered and candidates but couldn't find enough time for that as that it was already the last day of the competition. Kudos to @tezdhar for our great ideas!",
              "votes": 1
            },
            {
              "id": 2126108,
              "postDate": "2023-02-02T05:17:55.547Z",
              "content": "<p>as always thanks for sharing clear and details tricks</p>\n<p>I am curious about how do you compute multiple item comparisons in fast way?<br>\nI am stuck with for loop iteration with following steps</p>\n<ol>\n<li>in each iteration, i take vectors of item1 &amp; item2 and append it to list items1, items2</li>\n<li>at the end of iterations, convert items1 and items2 to numpy array</li>\n<li>compute the similarity feature with vectorized cosine similarity function</li>\n</ol>\n<p>it's functional but it takes a lot of time to complete</p>",
              "rawMarkdown": "as always thanks for sharing clear and details tricks\n\nI am curious about how do you compute multiple item comparisons in fast way?\nI am stuck with for loop iteration with following steps\n1. in each iteration, i take vectors of item1 & item2 and append it to list items1, items2\n2. at the end of iterations, convert items1 and items2 to numpy array\n3. compute the similarity feature with vectorized cosine similarity function\n\nit's functional but it takes a lot of time to complete",
              "votes": 1
            },
            {
              "id": 2126193,
              "postDate": "2023-02-02T05:59:29.677Z",
              "content": "<p>I'm not sure what you're asking. I use <code>cupy</code> and GPU to perform the vector multiplication of user history item with candidate item embedding. It takes a few seconds to create a new column of cosine similarity. I create dozens of features then train XGB reranker. I do not worry about making too many features. My pipeline can handle 1000+ features. (Because for XGB reranker i remove all users where no candidate has a positive target).</p>",
              "rawMarkdown": "I'm not sure what you're asking. I use `cupy` and GPU to perform the vector multiplication of user history item with candidate item embedding. It takes a few seconds to create a new column of cosine similarity. I create dozens of features then train XGB reranker. I do not worry about making too many features. My pipeline can handle 1000+ features. (Because for XGB reranker i remove all users where no candidate has a positive target).",
              "votes": 2
            },
            {
              "id": 2127101,
              "postDate": "2023-02-02T17:12:44.323Z",
              "content": "<blockquote>\n  <p>I do not worry about making too many features. My pipeline can handle 1000+ features. (Because for XGB reranker i remove all users where no candidate has a positive target).</p>\n</blockquote>\n<p>For us working with kaggle notebooks this is not an option. As for clicks, most sessions do have a positive target, and I struggled to fit 18 features for click model into available memory. Downsampled negatives, converted all the float features into float16 after loading from parquet, and felt I was close to maximum available features.<br>\nFor carts/orders kaggle notebook with GPU support could probably handle about 100-150 features, but again no chance for 1000+.</p>\n<p>P.S. congratulations and thank you for your usefull posts!</p>",
              "rawMarkdown": ">I do not worry about making too many features. My pipeline can handle 1000+ features. (Because for XGB reranker i remove all users where no candidate has a positive target).\n\nFor us working with kaggle notebooks this is not an option. As for clicks, most sessions do have a positive target, and I struggled to fit 18 features for click model into available memory. Downsampled negatives, converted all the float features into float16 after loading from parquet, and felt I was close to maximum available features.\nFor carts/orders kaggle notebook with GPU support could probably handle about 100-150 features, but again no chance for 1000+.\n\nP.S. congratulations and thank you for your usefull posts!",
              "votes": 1
            }
          ]
        }
      ]
    },
    {
      "id": 2125893,
      "postDate": "2023-02-02T01:19:20.587Z",
      "content": "<p>Amazing ！0.590 without reranker.  Thanks so much for your all tutorial otherwise I didn't know how to play a recommend game.</p>",
      "rawMarkdown": "Amazing ！0.590 without reranker.  Thanks so much for your all tutorial otherwise I didn't know how to play a recommend game.",
      "votes": 2,
      "replies": [
        {
          "id": 2125903,
          "postDate": "2023-02-02T01:35:32.117Z",
          "content": "<p>Thanks EeyoreLee. Congratulations on your solo Bronze medal finish. Your LB 0.593 was very close to Silver 0.594. You did great !</p>",
          "rawMarkdown": "Thanks EeyoreLee. Congratulations on your solo Bronze medal finish. Your LB 0.593 was very close to Silver 0.594. You did great !",
          "votes": 2
        }
      ]
    },
    {
      "id": 3001255,
      "postDate": "2024-09-28T16:12:23.177Z",
      "content": "<p>Hi，thanks for your contribution！I have a question：Why not directly read train.jsonl line by line and then determine whether each line should be added to the training set or validation set? What is the purpose of constructing session_chunks?Sincerely hope for your answer！</p>",
      "rawMarkdown": "Hi，thanks for your contribution！I have a question：Why not directly read train.jsonl line by line and then determine whether each line should be added to the training set or validation set? What is the purpose of constructing session_chunks?Sincerely hope for your answer！"
    },
    {
      "id": 2165553,
      "postDate": "2023-03-02T09:16:21.490Z",
      "content": "<p>Congratulations !!! </p>",
      "rawMarkdown": "Congratulations !!! "
    },
    {
      "id": 2129389,
      "postDate": "2023-02-04T15:39:46.547Z",
      "rawMarkdown": "",
      "isDeleted": true
    },
    {
      "id": 2129119,
      "postDate": "2023-02-04T10:47:07.627Z",
      "rawMarkdown": "",
      "votes": 1,
      "isDeleted": true
    },
    {
      "id": 2131517,
      "postDate": "2023-02-06T07:13:13.363Z",
      "content": "<p>Thanks for your sharing.</p>",
      "rawMarkdown": "Thanks for your sharing.",
      "votes": 1
    },
    {
      "id": 3235131,
      "postDate": "2025-06-28T18:26:54.350Z",
      "content": "<p>Thank you for the detail writeup!</p>",
      "rawMarkdown": "Thank you for the detail writeup!"
    }
  ],
  "comments": [
    {
      "id": 2144158,
      "author_name": "Chris Deotte",
      "author_url": "",
      "post_date": "2023-02-14T19:15:12.750000",
      "content": "<p>UPDATE: I published all 261 jupyter notebooks to run my full single model LB 0.601 solution at GitHub here: <a href=\"https://github.com/cdeotte/Kaggle-OTTO-Comp\" target=\"_blank\">https://github.com/cdeotte/Kaggle-OTTO-Comp</a></p>",
      "votes": 7,
      "replies": []
    },
    {
      "id": 2127112,
      "author_name": "Artem Fedorov",
      "author_url": "",
      "post_date": "2023-02-02T17:23:28.827000",
      "content": "<p>Everything looks so easy when reading the describtion of your solution. I've even thought for a moment \"how could it happen that I didn't try it myself?\" <br>\nWith just kaggle notebooks running all the possible experiments is more tricky. And anyway, I didn't even think about some of your matrices, like before/after 2PM, only users with short history, only last week. I did make a matrice for exact next aid, but only used it for clicks and didn't even try to apply it to carts/orders.</p>\n<p>And again, thank you for you clear and insightfull posts, both during and after the competition.</p>",
      "votes": 3,
      "replies": []
    },
    {
      "id": 2127417,
      "author_name": "Radek Osmulski",
      "author_url": "",
      "post_date": "2023-02-02T21:45:54.857000",
      "content": "<p>Great job <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> and the rest of the team! 🥳 Amazing performance!</p>\n<p>This write up reads like a good detective story, the plot is so clearly explained! So cool to understand what you did to achieve this phenomenal result. Love the progression from the public kernel with the co-visitation matrices there to the full solution using the reranker!</p>\n<p>Congrats again and thank you for this great write-up! </p>",
      "votes": 4,
      "replies": [
        {
          "id": 2128306,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2023-02-03T15:59:16.260000",
          "content": "<p>Thanks Radek. Thanks for all your sharing during the competition!</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 2186719,
      "author_name": "马甲线来来来",
      "author_url": "",
      "post_date": "2023-03-18T03:42:24.003000",
      "content": "<p>thx for sharing, really learn a lot from that</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2146750,
      "author_name": "Girijesh",
      "author_url": "",
      "post_date": "2023-02-16T05:38:22.827000",
      "content": "<p>Congratulations <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> excellent work.</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2141778,
      "author_name": "Ryan",
      "author_url": "",
      "post_date": "2023-02-13T05:00:00.417000",
      "content": "<p>Wow, congratulations on taking 3rd place in the competition! Your solution is impressive OAO</p>\n<p>I learnt your approach to using RAPID cuDF to quickly compute hundreds of covisit matrices and then compute the local CV score is clever. I can imagine that this saved a lot of time and allowed me to experiment more efficiently in the future!</p>\n<p>Thank for sharing!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2139626,
      "author_name": "Mayuri Deshpande",
      "author_url": "",
      "post_date": "2023-02-10T23:35:14.827000",
      "content": "<p>Congratulations! Great read!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2138097,
      "author_name": "Apa",
      "author_url": "",
      "post_date": "2023-02-10T14:55:52.430000",
      "content": "<p>I saw that in your open source code, the saved file name of the feature is gpu-116<br>\n;gpu-220 and so on, why are they named so?</p>",
      "votes": 1,
      "replies": [
        {
          "id": 2139629,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2023-02-10T23:39:28.810000",
          "content": "<p>This was experiment 116 and experiment 220. I made hundreds of different co-visit matrices and computed validation score to see which were the best.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 2131421,
      "author_name": "Nick Liu",
      "author_url": "",
      "post_date": "2023-02-06T05:14:31.107000",
      "content": "<p>Hello Chris,<br>\nGreat work and Congratulations.<br>\nI try to implement your idea but feel a little confused in some covisit items.<br>\nCould you slightly talk about if you don't mind: </p>\n<ol>\n<li>What's the difference between top_20_new and top_20_new2?</li>\n<li>What's the definition of 'cold start'? is the user's first action time - start time &gt; 2days? or 1week? </li>\n<li>In top_40_less2 / top_40_more2, we'll filter the specific users by actions more/less than 6(3), and filter by first item time before/after 2pm, am I right?<br>\nThanks for sharing the idea/notebook, really fantastic.</li>\n</ol>",
      "votes": 1,
      "replies": [
        {
          "id": 2132156,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2023-02-06T16:23:48.880000",
          "content": "<p>Thanks ChickenBoy,</p>\n<ol>\n<li><p>top_20_new is clicks/carts/orders to carts/orders without time decay. And top_20_new2 is clicks/carts/orders to clicks/carts/orders with time decay.</p></li>\n<li><p>Cold start is <code>user_first_action - dataset_start_time &gt; 2 weeks</code></p>\n<p>df['x'] = df.groupby('session').ts.transform('min')<br>\n df = df.loc[df.x &gt; train.ts.min() + TWO_WEEKS ]<br>\n df['n'] = df.groupby('session').cumcount()<br>\n df2 = df.loc[df['n']==0]<br>\n df3 = df.loc[df['type'].isin(['carts','orders'])]<br>\n df = df2.merge(df3, on='session')</p></li>\n<li><p>In top_40_more/less, we filter users</p>\n<p>df = df.loc[df[COUNT]&lt;THRESHOLD] <br>\n df = df.merge(df, on='session')</p></li>\n</ol>\n<p>And in top_40_more2/less2, we filter first item. </p>\n<pre><code>df2 = df.loc[df[HOUR]&lt;14]\ndf = df2.merge(df, on='session')\n</code></pre>",
          "votes": 2,
          "replies": [
            {
              "id": 2132225,
              "author_name": "Nick Liu",
              "author_url": "",
              "post_date": "2023-02-06T17:12:18.810000",
              "content": "<p>Thanks! Really helpful👍👍👍</p>",
              "votes": 2,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2129831,
      "author_name": "ibrahim karatas",
      "author_url": "",
      "post_date": "2023-02-04T22:50:36.573000",
      "content": "<p>A useful share. Thanks I will use this in my project</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2129759,
      "author_name": "ToriGlori",
      "author_url": "",
      "post_date": "2023-02-04T20:51:34.087000",
      "content": "<p>Nice write down</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2128550,
      "author_name": "andrey bobrik",
      "author_url": "",
      "post_date": "2023-02-03T19:47:20.930000",
      "content": "<p>Great breakdown</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2127381,
      "author_name": "S Victor Kumar",
      "author_url": "",
      "post_date": "2023-02-02T21:03:21.687000",
      "content": "<p>Congratulations! <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> <br>\nAnd Thanks it helped me to understand  about Competition ranking in Kaggle.</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2126362,
      "author_name": "Donghoon Jang",
      "author_url": "",
      "post_date": "2023-02-02T07:34:08.147000",
      "content": "<p>Thank you for sharing. It helped me a lot.</p>\n<p>Could you share the code for building a reank model using your CV notebook and LB notebook?</p>\n<p>I had a hard time making a reank model using candidates.</p>\n<p>Thank you.</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2125980,
      "author_name": "Hoang Nguyen",
      "author_url": "",
      "post_date": "2023-02-02T03:27:05.887000",
      "content": "<p>Congratulations on your gold medal, and thanks for your great help - your code and suggestions were very influential (and have helped me get my first medal!)<br>\nYour work actually introduced me to <code>cuDF</code>, which I'm still new with and have a question I hope you could help. Beside reducing <code>dtype</code>, to preserve GPU memory I also remove unused stuffs, but from my experience <code>del</code> and <code>gc.collect()</code> do not always help with lowering GPU memory. Take the  example code snippet below - the memory usage doubles after the <code>merge</code>, and does not reduce after <code>del</code> and <code>gc.collect()</code>. Is it because of some caching property of <code>cuDF</code>?</p>\n<pre><code>\ndf1 = cudf.from_pandas(pd.load_parquet(path_1)) \ndf2 = cudf.from_pandas(pd.load_parquet(path_2)) \ndf1 = df1.merge(df2, on=, how=) \n df1, df2 \n_ = gc.collect() \n</code></pre>\n<p>Thank you!</p>",
      "votes": 1,
      "replies": [
        {
          "id": 2126051,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2023-02-02T04:22:58.530000",
          "content": "<p>yes, sometimes memory usage does not decrease. In this situation, i save dataframe to disk as parquet. Then i shut down notebook and start a new notebook and read in the parquet. That will clear memory.</p>",
          "votes": 1,
          "replies": [
            {
              "id": 2126144,
              "author_name": "Hoang Nguyen",
              "author_url": "",
              "post_date": "2023-02-02T05:42:19.227000",
              "content": "<p>That's what I had to do to too! Also I google-ed around for an option to release unused GPU memory and found nothing related to cuDF but a few options for PyTorch (<a href=\"https://pytorch.org/docs/stable/generated/torch.cuda.empty_cache.html#torch-cuda-empty-cache\" target=\"_blank\">torch.cuda.empty_cache</a>, if I'm correct?). Would be nice if cuDF has something similar.<br>\nThanks Chris! </p>",
              "votes": 1,
              "replies": []
            },
            {
              "id": 2126164,
              "author_name": "",
              "author_url": "",
              "post_date": "2023-02-02T05:47:43.680000",
              "content": "",
              "votes": 0,
              "replies": []
            },
            {
              "id": 2126168,
              "author_name": "Mohamed Eltayeb",
              "author_url": "",
              "post_date": "2023-02-02T05:48:38.680000",
              "content": "<p>I think this can help:<br>\n<code>#Free The GPU Memory</code><br>\n<code>from numba import cuda</code><br>\n<code>cuda.select_device(0)</code><br>\n<code>cuda.close()</code><br>\n<code>cuda.select_device(0)</code></p>",
              "votes": 3,
              "replies": []
            },
            {
              "id": 2126636,
              "author_name": "Hoang Nguyen",
              "author_url": "",
              "post_date": "2023-02-02T10:56:16.127000",
              "content": "<p>Thanks Mohamed! I have not tried this, but based on numba documentation this seems equivalent to restarting the kernel. Have you tried it?</p>",
              "votes": 1,
              "replies": []
            },
            {
              "id": 2126678,
              "author_name": "Mohamed Eltayeb",
              "author_url": "",
              "post_date": "2023-02-02T11:44:11.280000",
              "content": "<p>I used it several times in \"American Express Competition\". Sometimes I encounter a permission issue (Not sure honestly why it appears sometimes), but other than that, it works perfectly.</p>",
              "votes": 1,
              "replies": []
            },
            {
              "id": 2126917,
              "author_name": "Hoang Nguyen",
              "author_url": "",
              "post_date": "2023-02-02T15:04:20.790000",
              "content": "<p>Sounds like what I'm looking for - will make sure to try it next time. Thanks again!</p>",
              "votes": 1,
              "replies": []
            }
          ]
        },
        {
          "id": 2129883,
          "author_name": "Giba",
          "author_url": "",
          "post_date": "2023-02-05T01:20:17.170000",
          "content": "<p>Put your cudf operations inside a function.  Then python releases GPU memory used inside the function after the return.</p>",
          "votes": 4,
          "replies": []
        }
      ]
    },
    {
      "id": 2125898,
      "author_name": "ADAM.",
      "author_url": "",
      "post_date": "2023-02-02T01:24:28.653000",
      "content": "<p>super cool!</p>",
      "votes": 1,
      "replies": [
        {
          "id": 2125916,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2023-02-02T01:50:43.040000",
          "content": "<p>Thanks Adam</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 2125886,
      "author_name": "cooperation",
      "author_url": "",
      "post_date": "2023-02-02T00:58:10.020000",
      "content": "<p>Thank you Chris, I won't get current ranking wihtout your public notebook。</p>\n<p>I have some doubts in the your gbdt public notebook  ：<br>\nI would like to know why there is no need to specify a group in Inference?<br>\nHow does the model judge whether the data is in the same group during inference?<br>\nDoes this mean that the inference group must be the same as the training group?<br>\nI looked at the docs but didn't find what I want to know, am I missing something?</p>\n<p>Please forgive me for asking the question here again 😂because I really want to know the answer</p>",
      "votes": 1,
      "replies": [
        {
          "id": 2125888,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2023-02-02T01:08:33.187000",
          "content": "<p>Group is not needed during inference. The GBT will rank all rows during inference. So when we just look at each user during inference, the ranking will be correct.</p>\n<p>(Group is only needed during training)</p>",
          "votes": 1,
          "replies": [
            {
              "id": 2126217,
              "author_name": "cooperation",
              "author_url": "",
              "post_date": "2023-02-02T06:10:49.377000",
              "content": "<p>Thanks Chris!</p>",
              "votes": 1,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2130617,
      "author_name": "Andrei Kavalenka",
      "author_url": "",
      "post_date": "2023-02-05T15:20:20.370000",
      "content": "<p>Nice work, it was very interesting to read! </p>",
      "votes": 2,
      "replies": [
        {
          "id": 2136039,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2023-02-09T04:09:49.487000",
          "content": "<p>Thanks Andrew!</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 2129630,
      "author_name": "ibrahim karatas",
      "author_url": "",
      "post_date": "2023-02-04T19:01:51.847000",
      "content": "<p>The information you share is very valuable. Thanks for sharing. I will use it in my next rule based project</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 2128312,
      "author_name": "Taha Muhammad Haider",
      "author_url": "",
      "post_date": "2023-02-03T16:05:20.163000",
      "content": "<p>Congratulations, <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> on your outstanding results! Your exceptional problem-solving skills and strong intuition have truly inspired me. I have gained so much valuable knowledge from you. I am grateful for all the lessons and experiences you have shared with us. Thank you!</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 2127634,
      "author_name": "KhanhVD",
      "author_url": "",
      "post_date": "2023-02-03T02:24:13.223000",
      "content": "<p>Congrats <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> and team on great results. Thanks for sharing throughout the competition, again learn alot from you!</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 2126779,
      "author_name": "Pietro Maldini",
      "author_url": "",
      "post_date": "2023-02-02T13:01:10.733000",
      "content": "<p>Congratulations! It's incredible how the rule based models could be pushed. My limit was 0.581 LB with rule based.<br>\nNext time I'll try out some of the ideas you presented.</p>\n<p>Again congratulations!</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 2126498,
      "author_name": "Wonho Song",
      "author_url": "",
      "post_date": "2023-02-02T09:08:12.020000",
      "content": "<p>I love your way to explain solution starting from baseline notebook. <br>\nI really learned a lot from your notebook and discusssions.<br>\nCongrats!</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 2126035,
      "author_name": "Aji Samudra",
      "author_url": "",
      "post_date": "2023-02-02T04:10:10.003000",
      "content": "<p>This is epic! Thanks for sharing <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a>!<br>\nOut of curiosity, what makes you stick with rule-based and creating various different covisit matrix while there's other techniques such as CF, MF and word2vec?</p>\n<p>and given all the count features, did you tune the ranker?</p>",
      "votes": 2,
      "replies": [
        {
          "id": 2126053,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2023-02-02T04:24:06.760000",
          "content": "<p>I did everything. I pushed rule-based as far as it would go. Afterward, i used word2vec and matrix factorization to create features for my GBT reranker. Both helped.</p>",
          "votes": 1,
          "replies": [
            {
              "id": 2126080,
              "author_name": "Mohamed Eltayeb",
              "author_url": "",
              "post_date": "2023-02-02T04:52:08.560000",
              "content": "<p>Do you think LSTM Embeddings would help more than Word2Vec given that we have aids sorted by time? Just want to know if you made a similar experiment? </p>",
              "votes": 1,
              "replies": []
            },
            {
              "id": 2126096,
              "author_name": "Chris Deotte",
              "author_url": "",
              "post_date": "2023-02-02T05:08:53.167000",
              "content": "<p>I think all item embeddings would help. The trick was to first train some NN such as LSTM, Word2Vec, Matrix Factorization etc.</p>\n<p>Then we take the item embeddings and for each row in our candidate dataframe, we compute the cosine similarity between user history last item and candidate. Then user history 2nd to last, 3rd, 4th 5th. Then user history first item, 2nd, 3rd, 4th, 5th. Then user history last buy, 2nd to last buy, 3rd, 4th, 5th. Then finally we take aggregate means and standard deviations of groups of these values. These features were very helpful.</p>",
              "votes": 3,
              "replies": []
            },
            {
              "id": 2126106,
              "author_name": "Mohamed Eltayeb",
              "author_url": "",
              "post_date": "2023-02-02T05:15:13.997000",
              "content": "<p>Nice! I tried a similar idea. I used Word2Vec, but calculated the cosine similarity between last, 2nd to last and 3rd to last interacted items and the last, 2nd to last and 3rd to last clicked/carted/ordered items. Honestly, I wanted to try the similarity between last clicked/carted/ordered and candidates but couldn't find enough time for that as that it was already the last day of the competition. Kudos to <a href=\"https://www.kaggle.com/tezdhar\" target=\"_blank\">@tezdhar</a> for our great ideas!</p>",
              "votes": 1,
              "replies": []
            },
            {
              "id": 2126108,
              "author_name": "Aji Samudra",
              "author_url": "",
              "post_date": "2023-02-02T05:17:55.547000",
              "content": "<p>as always thanks for sharing clear and details tricks</p>\n<p>I am curious about how do you compute multiple item comparisons in fast way?<br>\nI am stuck with for loop iteration with following steps</p>\n<ol>\n<li>in each iteration, i take vectors of item1 &amp; item2 and append it to list items1, items2</li>\n<li>at the end of iterations, convert items1 and items2 to numpy array</li>\n<li>compute the similarity feature with vectorized cosine similarity function</li>\n</ol>\n<p>it's functional but it takes a lot of time to complete</p>",
              "votes": 1,
              "replies": []
            },
            {
              "id": 2126193,
              "author_name": "Chris Deotte",
              "author_url": "",
              "post_date": "2023-02-02T05:59:29.677000",
              "content": "<p>I'm not sure what you're asking. I use <code>cupy</code> and GPU to perform the vector multiplication of user history item with candidate item embedding. It takes a few seconds to create a new column of cosine similarity. I create dozens of features then train XGB reranker. I do not worry about making too many features. My pipeline can handle 1000+ features. (Because for XGB reranker i remove all users where no candidate has a positive target).</p>",
              "votes": 2,
              "replies": []
            },
            {
              "id": 2127101,
              "author_name": "Artem Fedorov",
              "author_url": "",
              "post_date": "2023-02-02T17:12:44.323000",
              "content": "<blockquote>\n  <p>I do not worry about making too many features. My pipeline can handle 1000+ features. (Because for XGB reranker i remove all users where no candidate has a positive target).</p>\n</blockquote>\n<p>For us working with kaggle notebooks this is not an option. As for clicks, most sessions do have a positive target, and I struggled to fit 18 features for click model into available memory. Downsampled negatives, converted all the float features into float16 after loading from parquet, and felt I was close to maximum available features.<br>\nFor carts/orders kaggle notebook with GPU support could probably handle about 100-150 features, but again no chance for 1000+.</p>\n<p>P.S. congratulations and thank you for your usefull posts!</p>",
              "votes": 1,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2125893,
      "author_name": "EeyoreLee",
      "author_url": "",
      "post_date": "2023-02-02T01:19:20.587000",
      "content": "<p>Amazing ！0.590 without reranker.  Thanks so much for your all tutorial otherwise I didn't know how to play a recommend game.</p>",
      "votes": 2,
      "replies": [
        {
          "id": 2125903,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2023-02-02T01:35:32.117000",
          "content": "<p>Thanks EeyoreLee. Congratulations on your solo Bronze medal finish. Your LB 0.593 was very close to Silver 0.594. You did great !</p>",
          "votes": 2,
          "replies": []
        }
      ]
    },
    {
      "id": 3001255,
      "author_name": "YuhaoWu123",
      "author_url": "",
      "post_date": "2024-09-28T16:12:23.177000",
      "content": "<p>Hi，thanks for your contribution！I have a question：Why not directly read train.jsonl line by line and then determine whether each line should be added to the training set or validation set? What is the purpose of constructing session_chunks?Sincerely hope for your answer！</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 2165553,
      "author_name": "Siliva1799",
      "author_url": "",
      "post_date": "2023-03-02T09:16:21.490000",
      "content": "<p>Congratulations !!! </p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 2129389,
      "author_name": "",
      "author_url": "",
      "post_date": "2023-02-04T15:39:46.547000",
      "content": "",
      "votes": 0,
      "replies": []
    },
    {
      "id": 2129119,
      "author_name": "",
      "author_url": "",
      "post_date": "2023-02-04T10:47:07.627000",
      "content": "",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2131517,
      "author_name": "",
      "author_url": "",
      "post_date": "2023-02-06T07:13:13.363000",
      "content": "",
      "votes": 1,
      "replies": []
    },
    {
      "id": 3235131,
      "author_name": "",
      "author_url": "",
      "post_date": "2025-06-28T18:26:54.350000",
      "content": "",
      "votes": 0,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "2125843": "# Team G & B & D & T\nIt was a pleasure to work with @titericz @benediktschifferer @theoviel . We each made individual models and then ensembled all our work together by adding the ranks of each of our predictions per user target type. Below I describe my individual single model. My teammates will describe their work in their own discussion posts. You can read about Theo's LB 0.6029 model [here][5]! You can read about Benny's LB 0.601 model [here][8]!\n\nMost of my solution was made public in my notebook [here][3] and discussion [here][2] during the competition. There were only 3 significant ideas missing from my public work. Let's discuss how to boost my public work to LB 0.601 single model. (UPDATE: All code published to GitHub [here][6])\n\n# How To Score LB 0.601 Single Model\nIt was explained [here][1] and [here][2] that the best approach was \"candidate rerank\" model. My public notebook [here][3] shows how to achieve LB 0.575. And my discussion post [here][2] explains how to improve my public notebook by adding a GBT ranker model. Below are the three missing pieces labeled (1), (2), and (3) to achieve LB 0.601\n\n# (1) Choosing Candidates\nTo build a \"candidate rerank\", we need candidates. Where do we get candidates? The easiest way is to get them from my public notebook. In the `def suggest_buys(df)` and `def suggest_clicks(df)` function, the last lines are\n\n    top_aids = [aid for aid, ct in aids_counter.most_common(20)] \n    return top_aids\n\nTo generate 50 candidates, we change 20 to 50 as in\n\n    top_aids = [aid for aid, ct in aids_counter.most_common(50)] \n    return top_aids\n\n# (2) Choosing Interaction Features\nWe now have 50 candidates per user from our public notebook above. Next we need to make features for our reranker model. The strongest and easiest way to make features is extract our co-visit counts by changing the last two lines of my public notebook to the following:\n\n    top_counts = [ct for aid, ct in aids_counter.most_common(50)] \n    return top_counts\n\nWhen we merge these counts to our candidates, we now have an interaction feature for each user item pair. To make more interaction features, we can extract the counts for each co-visit matrix individually. For example, imagine that we have 3 co-visit matrices named covisit2, covisit3, and covist4. Then one by one, we extract each covisit's counts:\n\n    EXTRACT = ['covisit2']\n    aids_counter = Counter()\n    if 'covisit2' in EXTRACT:\n        aids = list(itertools.chain(*[covisit2[aid] for aid in unique_aids if aid in covisit2]))\n        for a in aids: aids_counter[a] += 1\n    if 'covisit3' in EXTRACT:\n        aids = list(itertools.chain(*[covisit3[aid] for aid in unique_aids if aid in covisit3]))\n        for a in aids: aids_counter[a] += 1\n    if 'covisit4' in EXTRACT:\n        aids = list(itertools.chain(*[covisit4[aid] for aid in unique_aids if aid in covisit4]))\n        for a in aids: aids_counter[a] += 1\n    top_counts = [ct for aid, ct in aids_counter.most_common(50)] \n    return top_counts\n\n# Reranker Boost CV and LB +0.011\nFirst we use the technique above to generate candidates and the technique above to extract covisit counts. Next we add some simple item and user features like counting the number of times an item is click cart or order. When we apply the XGB reranker described [here][2], our CV and LB will boost by `+0.011`. For example, the public notebook will boost to LB 0.586.\n\n# Using Rules Only (without reranker) Scores LB 0.590\nTo score over LB 0.600, we create more co-visit matrices to boost the original notebook's LB score. My public notebook uses 3 covisit matrices and achieves LB 0.575. If we make 17 more covisit matrices, we can boost my public \"rules only\" notebook to LB 0.590 (new notebook published [here][4]). Then when we extract the covisit counts explained above, the XGB reranker will boost +0.011 and achieve LB 0.601\n\n# (3) Twenty Covisit Matrices\nBelow are a description of my 20 covisit matrices. These covisit matrices are the secret sauce enabling my single XGB ranker model to achieve LB 0.601. The following variable names are from my new LB 0.590 notebook posted [here][4]. (Example code showing how to compute covisit matrices on GPU is [here][3])\n* **top_20** - this covisit matrix is in my original notebook\n* **top_20b** - all covisit pair counts are consecutive items. See code below.\n    `df['k'] = np.arange(len(df))`\n    `df = df.merge(df, on=['session'])`\n    `df = df.loc[ (df.k_y - df.k_x).abs()==1 ]`\n* **top_20c** - all covisit pair counts are `(df.k_y - df.k_x).abs()<=2`\n* **top_20d** - all covisit pairs are carts/orders and forward at most 3 consecutive\n    `df = df.loc[df['type'].isin(['carts','orders'])]`\n    `df = df.merge(df, on=['session'])`\n    `df = df.loc[ (df.k_y - df.k_x > 0) & (df.k_y - df.k_x <= 3) ]`\n* **top_20e** - all covisit pairs are `(df.k_y - df.k_x).abs()<=3` and have time decay with\n    `df['wgt'] = (1/2)**( (df.ts_x - df.ts_y).abs() /60/60)`\n* **top_20f** - same as above but `(df.k_y - df.k_x).abs()<=6`\n* **top_20_orders** - this covisit matrix is in my original notebook\n* **top_20_buy2buy** - this covisit matrix is in my original notebook\n* **top_20_buy2buy2** - use most recent 3 weeks data and only carts/orders. Apply time decay shown above.\n* **top_20_test** - use most recent 3 weeks data. Only forward in time pairs. Use clicks/carts/orders to carts/orders. Add time decay\n    `df = df.loc[df.ts >= LAST_3_WEEKS ]`\n    `df2 = df.loc[df['type'].isin(['carts','orders'])]`\n    `df = df.merge(df2, on=['session'])`\n    `df = df.loc[ df.ts_y - df.ts_x > 0 ]`\n    `df['wgt'] = (1/2)**( (df.ts_x - df.ts_y).abs() /60/60)`\n* **top_20_test2** - use most recent 2 weeks data with time decay.\n* **top_20_buy** - Limit to forward 2 hours. Use clicks/carts/orders to carts/orders. Apply time decay.\n* **top_20_new** - Find cold start users in train. Pairs using only their first history item. Use clicks/carts/orders to carts/orders.\n    `df['x'] = df.groupby('session').ts.transform('min')`\n    `df = df.loc[df.x > train.ts.min() + TWO_WEEKS ]`\n    `df['n'] = df.groupby('session').cumcount()`\n    `df2 = df.loc[df['n']==0]`\n    `df3 = df.loc[df['type'].isin(['carts','orders'])]`\n    `df = df2.merge(df3, on='session')`\n* **top_20_new2** - Find cold start users in train. Pairs using only their first history item. Use clicks/carts/orders to clicks/carts/orders. Apply time decay.\n* **top_40_day** - Use only last week data. Forward in time. Clicks/carts/orders to carts/orders. Time decay\n* **top_40_day2** - Use only last week data. Time decay\n* **top_40_less** - Train users with less than 6 history and test users with less than 3\n    `df = df.loc[df[COUNT]<THRESHOLD]`\n    `df = df.merge(df, on='session')`\n* **top_40_more** - Train users with more than 6 history and test users with more than 3\n* **top_40_less2** - Use item pairs with first item before 2pm. Clicks/carts/orders to carts/orders. Time decay\n    `df2 = df.loc[df[HOUR]<14]`\n    `df = df2.merge(df, on='session')`\n* **top_40_more2** - Use item pairs with first item after 2pm. Clicks/carts/orders to carts/orders. Time decay\n\n# Fast Covisit Experiments With RAPIDS cuDF\nTo find the above 20 covisit matrices, i computed hundreds of covisit matrices and then computed local CV score. To make covisit matrices quickly, I used RAPIDS cuDF to make each covisit matrix on GPU in under 1 minute. Code to make covisit matrix is shown [here][3]. Matrices were made using Nvidia 4xV100 32GB GPUs.\n\n# UPDATE: GitHub Code!\nI published all 261 jupyter notebooks in my GitHub [here][6]. Specially we can review all the code used to generate co-visititation matices. And we can see the pipeline for building, training, inferring a GBT reranker model. Our team's final Kaggle inference submit notebook is [here][7]. My notebook to generate 100 candidates for reranker is [here][4]. By itself it scores 49th place LB 0.590!\n\n[1]: https://www.kaggle.com/competitions/otto-recommender-system/discussion/364721\n[2]: https://www.kaggle.com/competitions/otto-recommender-system/discussion/370210\n[3]: https://www.kaggle.com/code/cdeotte/candidate-rerank-model-lb-0-575\n[4]: https://www.kaggle.com/cdeotte/rules-only-model-achieves-lb-590\n[5]: https://www.kaggle.com/competitions/otto-recommender-system/discussion/382975\n[6]: https://github.com/cdeotte/Kaggle-OTTO-Comp\n[7]: https://www.kaggle.com/code/cdeotte/3rd-place-team-g-b-d-t-0-604\n[8]: https://www.kaggle.com/competitions/otto-recommender-system/discussion/386497",
    "2144158": "UPDATE: I published all 261 jupyter notebooks to run my full single model LB 0.601 solution at GitHub here: https://github.com/cdeotte/Kaggle-OTTO-Comp",
    "2127112": "Everything looks so easy when reading the describtion of your solution. I've even thought for a moment \"how could it happen that I didn't try it myself?\" \nWith just kaggle notebooks running all the possible experiments is more tricky. And anyway, I didn't even think about some of your matrices, like before/after 2PM, only users with short history, only last week. I did make a matrice for exact next aid, but only used it for clicks and didn't even try to apply it to carts/orders.\n\nAnd again, thank you for you clear and insightfull posts, both during and after the competition.",
    "2127417": "Great job @cdeotte and the rest of the team! 🥳 Amazing performance!\n\nThis write up reads like a good detective story, the plot is so clearly explained! So cool to understand what you did to achieve this phenomenal result. Love the progression from the public kernel with the co-visitation matrices there to the full solution using the reranker!\n\nCongrats again and thank you for this great write-up! ",
    "2186719": "thx for sharing, really learn a lot from that",
    "2146750": "Congratulations @cdeotte excellent work.",
    "2141778": "Wow, congratulations on taking 3rd place in the competition! Your solution is impressive OAO\n\nI learnt your approach to using RAPID cuDF to quickly compute hundreds of covisit matrices and then compute the local CV score is clever. I can imagine that this saved a lot of time and allowed me to experiment more efficiently in the future!\n\nThank for sharing!",
    "2139626": "Congratulations! Great read!",
    "2138097": "I saw that in your open source code, the saved file name of the feature is gpu-116\n;gpu-220 and so on, why are they named so?",
    "2131421": "Hello Chris,\nGreat work and Congratulations.\nI try to implement your idea but feel a little confused in some covisit items.\nCould you slightly talk about if you don't mind: \n1. What's the difference between top_20_new and top_20_new2?\n2. What's the definition of 'cold start'? is the user's first action time - start time > 2days? or 1week? \n3. In top_40_less2 / top_40_more2, we'll filter the specific users by actions more/less than 6(3), and filter by first item time before/after 2pm, am I right?\nThanks for sharing the idea/notebook, really fantastic.",
    "2129831": "A useful share. Thanks I will use this in my project",
    "2129759": "Nice write down",
    "2128550": "Great breakdown",
    "2127381": "Congratulations! @cdeotte \nAnd Thanks it helped me to understand  about Competition ranking in Kaggle.",
    "2126362": "Thank you for sharing. It helped me a lot.\n\nCould you share the code for building a reank model using your CV notebook and LB notebook?\n\nI had a hard time making a reank model using candidates.\n\nThank you.",
    "2125980": "Congratulations on your gold medal, and thanks for your great help - your code and suggestions were very influential (and have helped me get my first medal!)\nYour work actually introduced me to `cuDF`, which I'm still new with and have a question I hope you could help. Beside reducing `dtype`, to preserve GPU memory I also remove unused stuffs, but from my experience `del` and `gc.collect()` do not always help with lowering GPU memory. Take the  example code snippet below - the memory usage doubles after the `merge`, and does not reduce after `del` and `gc.collect()`. Is it because of some caching property of `cuDF`?\n```python\n# GPU memory < 0.1 GBs\ndf1 = cudf.from_pandas(pd.load_parquet(path_1)) # GPU memory ~ 3.5 GBs\ndf2 = cudf.from_pandas(pd.load_parquet(path_2)) # GPU memory ~ 3.6 GBs\ndf1 = df1.merge(df2, on='session', how='left') # GPU memory ~ 7.0 GBs\ndel df1, df2 # GPU memory ~ 7.0 GBs\n_ = gc.collect() # GPU memory ~ 7.0 GBs\n```\nThank you!",
    "2125898": "super cool!",
    "2125886": "Thank you Chris, I won't get current ranking wihtout your public notebook。\n\nI have some doubts in the your gbdt public notebook  ：\nI would like to know why there is no need to specify a group in Inference?\nHow does the model judge whether the data is in the same group during inference?\nDoes this mean that the inference group must be the same as the training group?\nI looked at the docs but didn't find what I want to know, am I missing something?\n\nPlease forgive me for asking the question here again 😂because I really want to know the answer\n",
    "2130617": "Nice work, it was very interesting to read! ",
    "2129630": "The information you share is very valuable. Thanks for sharing. I will use it in my next rule based project",
    "2128312": "Congratulations, @cdeotte on your outstanding results! Your exceptional problem-solving skills and strong intuition have truly inspired me. I have gained so much valuable knowledge from you. I am grateful for all the lessons and experiences you have shared with us. Thank you!",
    "2127634": "Congrats @cdeotte and team on great results. Thanks for sharing throughout the competition, again learn alot from you!",
    "2126779": "Congratulations! It's incredible how the rule based models could be pushed. My limit was 0.581 LB with rule based.\nNext time I'll try out some of the ideas you presented.\n\nAgain congratulations!",
    "2126498": "I love your way to explain solution starting from baseline notebook. \nI really learned a lot from your notebook and discusssions.\nCongrats!",
    "2126035": "This is epic! Thanks for sharing @cdeotte!\nOut of curiosity, what makes you stick with rule-based and creating various different covisit matrix while there's other techniques such as CF, MF and word2vec?\n\nand given all the count features, did you tune the ranker?",
    "2125893": "Amazing ！0.590 without reranker.  Thanks so much for your all tutorial otherwise I didn't know how to play a recommend game.",
    "3001255": "Hi，thanks for your contribution！I have a question：Why not directly read train.jsonl line by line and then determine whether each line should be added to the training set or validation set? What is the purpose of constructing session_chunks?Sincerely hope for your answer！",
    "2165553": "Congratulations !!! ",
    "2129389": "",
    "2129119": "",
    "2131517": "Thanks for your sharing.",
    "3235131": "Thank you for the detail writeup!"
  }
}