{
  "id": 313833,
  "title": "12th place solution - Stretching short 'predictionstring's",
  "content": "<p>First of all, I would like to thank Kaggle and the organizers for hosting this competition, and everyone who shared useful methods and information.</p>\n<p>I've refered to a lot of shared ideas in this competition.</p>\n<h2>Solution</h2>\n<p>As the published method, I've handled  the task as NER.<br>\nMy solution consists of below two parts.</p>\n<ol>\n<li>Weighted ensemble of 5 models</li>\n<li>Several postprocess (including stretching short 'predictionstring's)  </li>\n</ol>\n<h3>1. Weighted ensemble of 5 models</h3>\n<p>My models are based on <a href=\"https://www.kaggle.com/Abhishek\" target=\"_blank\">@Abhishek</a>'s code.</p>\n<p>I took a weighted average of below 5 models.<br>\nEach model is trained on 5 folds and chosen some folds in submission.</p>\n<table>\n<thead>\n<tr>\n<th>model</th>\n<th>weight</th>\n<th>the amount of used folds</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>longformer-large</td>\n<td>0.175</td>\n<td>3</td>\n</tr>\n<tr>\n<td>funnel-large</td>\n<td>0.175</td>\n<td>3</td>\n</tr>\n<tr>\n<td>deberta-large(seed:77)</td>\n<td>0.15</td>\n<td>3</td>\n</tr>\n<tr>\n<td>deberta-large(seed:456)</td>\n<td>0.15</td>\n<td>2</td>\n</tr>\n<tr>\n<td>deberta-xlarge</td>\n<td>0.35</td>\n<td>5</td>\n</tr>\n</tbody>\n</table>\n<h3>2. Several postprocesses</h3>\n<p>Mainly, I used below 3 postprocesses.<br>\n① <br>\nI stretched short 'predictionstring's slightly.<br>\n The thresholds are as follows:</p>\n<table>\n<thead>\n<tr>\n<th>discourse_type</th>\n<th>threshold1<br>(length/degree)</th>\n<th>threshold2<br>(length/degree)</th>\n<th>threshold3<br>(length/degree)</th>\n<th>threshold4<br>(length/degree)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Lead</td>\n<td>7~13 / +6</td>\n<td>14~19 / +12</td>\n<td>20~30 / +14</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Position</td>\n<td>5~15 / +3</td>\n<td>16~20 / +2</td>\n<td>-</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Claim</td>\n<td>1~5 / +1</td>\n<td>6~10 / +2</td>\n<td>11~20 / +4</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Counterclaim</td>\n<td>5~24 / +4</td>\n<td>25~37 / +5</td>\n<td>-</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Rebuttal</td>\n<td>2~4 / +1</td>\n<td>5~13 / +5</td>\n<td>14~21 / +7</td>\n<td>22~27 / +8</td>\n</tr>\n<tr>\n<td>Evidence</td>\n<td>17~20 / +11</td>\n<td>21~23 / +14</td>\n<td>24~29 / +17</td>\n<td>30~36 / +20</td>\n</tr>\n<tr>\n<td>Concluding Statement</td>\n<td>-</td>\n<td>-</td>\n<td>-</td>\n<td>-</td>\n</tr>\n</tbody>\n</table>\n<p>Basically, I increased the length to be stretched in proportion to the length of the 'predictionstring'.<br>\nThis process increased TP while decreasing FP, finally improving the public/private by 0.007/0.005.</p>\n<p>② <br>\nThe points are following.</p>\n<p>・Modifying 'jn'<br>\n'link_evidence' used '-1' to distinguish between each 'predictionstring', <br>\nso the result of 'link_evidence' contained '-1' while ground truth don't include '-1'.</p>\n<p>Therefore I modified 'jn' which is used to concatenate several 'predictionstring's in 'link_evidence' so that the result of 'link_evidence' don't contain '-1'.</p>\n<pre><code>#before\ndef jn(pst, start, end):\n    return \" \".join([str(x) for x in pst[start:end]])\n\n#after\ndef jn(pst, start, end):\n    return \" \".join([str(x) for x in pst[start:end] if x !=-1])\n</code></pre>\n<p>・Applying it on other discourse types<br>\nI applied this method on other discourse types excluding 'Claim'.</p>\n<p>・Optimizing thresholds<br>\n＝＝＝＝<br>\nThe improvement increased public/private by +0.003 /+0.003.(excluding the effect of the default 'link_evidence')</p>\n<p>③</p>\n<p>Looking at the predictions, <br>\nI found that the end of prediction is sometimes a capital letter(e.g. 'This'). <br>\nSo, if the capital letter in the end of prediction is not a proper noun, I removed it.</p>\n<h2>What didn't worked well for me</h2>\n<p>・multi-task training using 15 topics<br>\n・concatenating last N layers of output of BERT<br>\n・several losses(Focal Loss, Dice Loss)<br>\n・large batch size</p>\n<h2>Resourse</h2>\n<p>Colab pro+ （Mainly, V100)<br>\nGCE preemptive instance(A100)</p>\n<h2>Inference code</h2>\n<p>The original code is <a href=\"https://www.kaggle.com/kurokurob/12th-place-solution-original\" target=\"_blank\">here</a>.<br>\nAfter the end of competition, I found some errors in the original code, so I fixed them.<br>\nThe modified code is <a href=\"https://www.kaggle.com/code/kurokurob/12th-place-solution-error-fix\" target=\"_blank\">here</a>.<br>\n<br><br>\nThanks for reading!</p>",
  "comments": [
    {
      "id": 1729272,
      "author_name": "chumajin",
      "author_url": "",
      "post_date": "2022-03-19T21:46:05.513000",
      "content": "<p>Congratulations on solo-gold ! You are great and thank you for sharing.<br>\nPost-processing is simple and easy to understand.</p>\n<p>I have one question. Have you tried deberta xlarge at google colab? In my case, I couldn't run because of insufficient memory at even batch size 1 (without gradient checkpointing etc in my case.)</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1729403,
          "author_name": "kuro_B",
          "author_url": "",
          "post_date": "2022-03-20T03:14:24.077000",
          "content": "<p>Thanks for the comment!<br>\nI  tried to train deberta xlarge at google colab with batch size 1, freezing a few layers at the beginning of the encoder, but couldn't trained it.</p>\n<p>Therefore, I borrowed a preemptive instance of A100 at GCE for training deberta xlarge.</p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1729524,
          "author_name": "chumajin",
          "author_url": "",
          "post_date": "2022-03-20T07:03:23.117000",
          "content": "<p>Thank you for your reply! I also tried freezing, but I couldn't improve the accuracy (probably lack of skill). I see.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1728946,
      "author_name": "AK",
      "author_url": "",
      "post_date": "2022-03-19T13:21:40.137000",
      "content": "<p>Hey <br>\nthanks for the write up . can you please ellabrate the first part of the postprocessing through some pseudo code it will be helpful . TIA</p>",
      "votes": 2,
      "replies": [
        {
          "id": 1728971,
          "author_name": "kuro_B",
          "author_url": "",
          "post_date": "2022-03-19T13:58:29.503000",
          "content": "<p><a href=\"https://www.kaggle.com/aman1391\" target=\"_blank\">@aman1391</a> <br>\nHi, thanks for the comment.<br>\nYou can do  the first part of the postprocessing by the following steps.</p>\n<p>①Define thresholds(only the threshold of 'Claim' is defined here)</p>\n<pre><code>claim_thresh_list=[\n                {\n    'start':1,\n    'end':5,\n    'add_num':1\n},\n             {\n    'start':6,\n    'end':10,\n    'add_num':2\n},\n\n{\n    'start':11,\n    'end': 20,\n    'add_num':4\n\n},\n]\n</code></pre>\n<p>②Define a function</p>\n<pre><code>def add_token_v4(row, discourse_type, thresh_list: list):\n    #sort in ascending order\n    thresh_list=sorted(thresh_list, key=lambda x: x['start'])\n\n    #check if the spans are overlapping\n    count_array=np.zeros(10000)\n    for d in thresh_list:\n        count_array[d['start']: d['end']+1]+=1\n    if (count_array&gt;1).sum()&gt;=1:\n        raise Exception(\"spans are overlapping\")\n\n    pred_len=len(row['predictionstring'].split())\n    for d in thresh_list:\n        if (row['class']==discourse_type) and (pred_len&gt;=d['start']) and (pred_len&lt;=d['end']):\n            max_idx=int(row['predictionstring'].split()[-1])\n            min_idx=int(row['predictionstring'].split()[0])\n            fix_pred=' '.join([str(i) for i in range(min_idx, max_idx+d['add_num']+1)])\n            return fix_pred\n\n    #If the predictionstring is not contained in any span, return the original predictionstring\n    return row['predictionstring']\n</code></pre>\n<p>③Perform the postprocess<br>\nYou can postprocess by applying the above function to the df for submission.</p>\n<pre><code>submission['predictionstring']=submission.apply(lambda x: add_token_v4(x, 'Claim', claim_thresh_list), axis=1)\n</code></pre>",
          "votes": 3,
          "replies": []
        },
        {
          "id": 1728975,
          "author_name": "AK",
          "author_url": "",
          "post_date": "2022-03-19T14:07:14.517000",
          "content": "<p>Thanks for the prompt reply..</p>",
          "votes": 1,
          "replies": []
        }
      ]
    }
  ],
  "comment_count": 6,
  "messages": [
    {
      "id": 1728680,
      "postDate": "2022-03-19T06:39:56.533Z",
      "content": "<p>First of all, I would like to thank Kaggle and the organizers for hosting this competition, and everyone who shared useful methods and information.</p>\n<p>I've refered to a lot of shared ideas in this competition.</p>\n<h2>Solution</h2>\n<p>As the published method, I've handled  the task as NER.<br>\nMy solution consists of below two parts.</p>\n<ol>\n<li>Weighted ensemble of 5 models</li>\n<li>Several postprocess (including stretching short 'predictionstring's)  </li>\n</ol>\n<h3>1. Weighted ensemble of 5 models</h3>\n<p>My models are based on <a href=\"https://www.kaggle.com/Abhishek\" target=\"_blank\">@Abhishek</a>'s code.</p>\n<p>I took a weighted average of below 5 models.<br>\nEach model is trained on 5 folds and chosen some folds in submission.</p>\n<table>\n<thead>\n<tr>\n<th>model</th>\n<th>weight</th>\n<th>the amount of used folds</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>longformer-large</td>\n<td>0.175</td>\n<td>3</td>\n</tr>\n<tr>\n<td>funnel-large</td>\n<td>0.175</td>\n<td>3</td>\n</tr>\n<tr>\n<td>deberta-large(seed:77)</td>\n<td>0.15</td>\n<td>3</td>\n</tr>\n<tr>\n<td>deberta-large(seed:456)</td>\n<td>0.15</td>\n<td>2</td>\n</tr>\n<tr>\n<td>deberta-xlarge</td>\n<td>0.35</td>\n<td>5</td>\n</tr>\n</tbody>\n</table>\n<h3>2. Several postprocesses</h3>\n<p>Mainly, I used below 3 postprocesses.<br>\n① <br>\nI stretched short 'predictionstring's slightly.<br>\n The thresholds are as follows:</p>\n<table>\n<thead>\n<tr>\n<th>discourse_type</th>\n<th>threshold1<br>(length/degree)</th>\n<th>threshold2<br>(length/degree)</th>\n<th>threshold3<br>(length/degree)</th>\n<th>threshold4<br>(length/degree)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Lead</td>\n<td>7~13 / +6</td>\n<td>14~19 / +12</td>\n<td>20~30 / +14</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Position</td>\n<td>5~15 / +3</td>\n<td>16~20 / +2</td>\n<td>-</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Claim</td>\n<td>1~5 / +1</td>\n<td>6~10 / +2</td>\n<td>11~20 / +4</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Counterclaim</td>\n<td>5~24 / +4</td>\n<td>25~37 / +5</td>\n<td>-</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Rebuttal</td>\n<td>2~4 / +1</td>\n<td>5~13 / +5</td>\n<td>14~21 / +7</td>\n<td>22~27 / +8</td>\n</tr>\n<tr>\n<td>Evidence</td>\n<td>17~20 / +11</td>\n<td>21~23 / +14</td>\n<td>24~29 / +17</td>\n<td>30~36 / +20</td>\n</tr>\n<tr>\n<td>Concluding Statement</td>\n<td>-</td>\n<td>-</td>\n<td>-</td>\n<td>-</td>\n</tr>\n</tbody>\n</table>\n<p>Basically, I increased the length to be stretched in proportion to the length of the 'predictionstring'.<br>\nThis process increased TP while decreasing FP, finally improving the public/private by 0.007/0.005.</p>\n<p>② <br>\nThe points are following.</p>\n<p>・Modifying 'jn'<br>\n'link_evidence' used '-1' to distinguish between each 'predictionstring', <br>\nso the result of 'link_evidence' contained '-1' while ground truth don't include '-1'.</p>\n<p>Therefore I modified 'jn' which is used to concatenate several 'predictionstring's in 'link_evidence' so that the result of 'link_evidence' don't contain '-1'.</p>\n<pre><code>#before\ndef jn(pst, start, end):\n    return \" \".join([str(x) for x in pst[start:end]])\n\n#after\ndef jn(pst, start, end):\n    return \" \".join([str(x) for x in pst[start:end] if x !=-1])\n</code></pre>\n<p>・Applying it on other discourse types<br>\nI applied this method on other discourse types excluding 'Claim'.</p>\n<p>・Optimizing thresholds<br>\n＝＝＝＝<br>\nThe improvement increased public/private by +0.003 /+0.003.(excluding the effect of the default 'link_evidence')</p>\n<p>③</p>\n<p>Looking at the predictions, <br>\nI found that the end of prediction is sometimes a capital letter(e.g. 'This'). <br>\nSo, if the capital letter in the end of prediction is not a proper noun, I removed it.</p>\n<h2>What didn't worked well for me</h2>\n<p>・multi-task training using 15 topics<br>\n・concatenating last N layers of output of BERT<br>\n・several losses(Focal Loss, Dice Loss)<br>\n・large batch size</p>\n<h2>Resourse</h2>\n<p>Colab pro+ （Mainly, V100)<br>\nGCE preemptive instance(A100)</p>\n<h2>Inference code</h2>\n<p>The original code is <a href=\"https://www.kaggle.com/kurokurob/12th-place-solution-original\" target=\"_blank\">here</a>.<br>\nAfter the end of competition, I found some errors in the original code, so I fixed them.<br>\nThe modified code is <a href=\"https://www.kaggle.com/code/kurokurob/12th-place-solution-error-fix\" target=\"_blank\">here</a>.<br>\n<br><br>\nThanks for reading!</p>",
      "rawMarkdown": "First of all, I would like to thank Kaggle and the organizers for hosting this competition, and everyone who shared useful methods and information.\n\nI've refered to a lot of shared ideas in this competition.\n\n## Solution\n\nAs the published method, I've handled  the task as NER.\nMy solution consists of below two parts.\n\n1. Weighted ensemble of 5 models\n2. Several postprocess (including stretching short 'predictionstring's)  \n\n### 1. Weighted ensemble of 5 models\nMy models are based on @Abhishek's code.\n\nI took a weighted average of below 5 models.\nEach model is trained on 5 folds and chosen some folds in submission.\n|model|weight|the amount of used folds|\n| :---: | :---: | :---: |\n|  longformer-large |  0.175  |  3  |\n|  funnel-large |  0.175  |  3  |\n|  deberta-large(seed:77)  |  0.15  | 3 |\n|  deberta-large(seed:456) |  0.15  | 2 |\n|  deberta-xlarge  |  0.35  |  5  |\n\n### 2. Several postprocesses\nMainly, I used below 3 postprocesses.\n① <u>Stretching short 'predictionstring's（public+0.007/private+0.005)</u>\nI stretched short 'predictionstring's slightly.\n The thresholds are as follows:\n\n|discourse_type|threshold1<br>(length/degree)|threshold2<br>(length/degree)|threshold3<br>(length/degree)|threshold4<br>(length/degree)|\n|:----:|:----:|:----:|:----:|:----:|\n| Lead | 7~13 / +6  |  14~19 / +12 | 20~30 / +14| -  |\n| Position | 5~15 / +3  |  16~20 / +2 | -| -  |\n|  Claim | 1~5 / +1  |  6~10 / +2 | 11~20 / +4  |  - |\n|  Counterclaim | 5~24 / +4  |  25~37 / +5 | - | -  |\n|  Rebuttal | 2~4 / +1  |  5~13 / +5 | 14~21 / +7  | 22~27 / +8 |\n|  Evidence | 17~20 / +11  |  21~23 / +14 | 24~29 / +17  | 30~36 / +20 |\n|  Concluding Statement | -  |  - | -  | - |\n\nBasically, I increased the length to be stretched in proportion to the length of the 'predictionstring'.\nThis process increased TP while decreasing FP, finally improving the public/private by 0.007/0.005.\n\n② <u>Improvement of [link_evedence](tensorflow-longformer-ner-postprocessing/notebook)（public+0.003/private+0.003)</u>\nThe points are following.\n\n・Modifying 'jn'\n'link_evidence' used '-1' to distinguish between each 'predictionstring', \nso the result of 'link_evidence' contained '-1' while ground truth don't include '-1'.\n\nTherefore I modified 'jn' which is used to concatenate several 'predictionstring's in 'link_evidence' so that the result of 'link_evidence' don't contain '-1'.\n```\n#before\ndef jn(pst, start, end):\n    return \" \".join([str(x) for x in pst[start:end]])\n\n#after\ndef jn(pst, start, end):\n    return \" \".join([str(x) for x in pst[start:end] if x !=-1])\n```\n\n・Applying it on other discourse types\nI applied this method on other discourse types excluding 'Claim'.\n\n・Optimizing thresholds\n＝＝＝＝\nThe improvement increased public/private by +0.003 /+0.003.(excluding the effect of the default 'link_evidence')\n\n③<u>Removing a capital letter on the end of the 'predictionstring'（The effect is small)</u>\n\nLooking at the predictions, \nI found that the end of prediction is sometimes a capital letter(e.g. 'This'). \nSo, if the capital letter in the end of prediction is not a proper noun, I removed it.\n\n## What didn't worked well for me\n・multi-task training using 15 topics\n・concatenating last N layers of output of BERT\n・several losses(Focal Loss, Dice Loss)\n・large batch size\n\n## Resourse\n\nColab pro+ （Mainly, V100)\nGCE preemptive instance(A100)\n\n## Inference code\nThe original code is [here](https://www.kaggle.com/kurokurob/12th-place-solution-original).\nAfter the end of competition, I found some errors in the original code, so I fixed them.\nThe modified code is [here](https://www.kaggle.com/code/kurokurob/12th-place-solution-error-fix).\n<br>\nThanks for reading!\n\n",
      "votes": 22
    },
    {
      "id": 1729272,
      "postDate": "2022-03-19T21:46:05.513Z",
      "content": "<p>Congratulations on solo-gold ! You are great and thank you for sharing.<br>\nPost-processing is simple and easy to understand.</p>\n<p>I have one question. Have you tried deberta xlarge at google colab? In my case, I couldn't run because of insufficient memory at even batch size 1 (without gradient checkpointing etc in my case.)</p>",
      "rawMarkdown": "Congratulations on solo-gold ! You are great and thank you for sharing.\nPost-processing is simple and easy to understand.\n\nI have one question. Have you tried deberta xlarge at google colab? In my case, I couldn't run because of insufficient memory at even batch size 1 (without gradient checkpointing etc in my case.)",
      "votes": 1,
      "replies": [
        {
          "id": 1729403,
          "postDate": "2022-03-20T03:14:24.077Z",
          "content": "<p>Thanks for the comment!<br>\nI  tried to train deberta xlarge at google colab with batch size 1, freezing a few layers at the beginning of the encoder, but couldn't trained it.</p>\n<p>Therefore, I borrowed a preemptive instance of A100 at GCE for training deberta xlarge.</p>",
          "rawMarkdown": "Thanks for the comment!\nI  tried to train deberta xlarge at google colab with batch size 1, freezing a few layers at the beginning of the encoder, but couldn't trained it.\n\nTherefore, I borrowed a preemptive instance of A100 at GCE for training deberta xlarge.",
          "votes": 1
        },
        {
          "id": 1729524,
          "postDate": "2022-03-20T07:03:23.117Z",
          "content": "<p>Thank you for your reply! I also tried freezing, but I couldn't improve the accuracy (probably lack of skill). I see.</p>",
          "rawMarkdown": "Thank you for your reply! I also tried freezing, but I couldn't improve the accuracy (probably lack of skill). I see.",
          "votes": 1
        }
      ]
    },
    {
      "id": 1728946,
      "postDate": "2022-03-19T13:21:40.137Z",
      "content": "<p>Hey <br>\nthanks for the write up . can you please ellabrate the first part of the postprocessing through some pseudo code it will be helpful . TIA</p>",
      "rawMarkdown": "Hey \nthanks for the write up . can you please ellabrate the first part of the postprocessing through some pseudo code it will be helpful . TIA",
      "votes": 2,
      "replies": [
        {
          "id": 1728971,
          "postDate": "2022-03-19T13:58:29.503Z",
          "content": "<p><a href=\"https://www.kaggle.com/aman1391\" target=\"_blank\">@aman1391</a> <br>\nHi, thanks for the comment.<br>\nYou can do  the first part of the postprocessing by the following steps.</p>\n<p>①Define thresholds(only the threshold of 'Claim' is defined here)</p>\n<pre><code>claim_thresh_list=[\n                {\n    'start':1,\n    'end':5,\n    'add_num':1\n},\n             {\n    'start':6,\n    'end':10,\n    'add_num':2\n},\n\n{\n    'start':11,\n    'end': 20,\n    'add_num':4\n\n},\n]\n</code></pre>\n<p>②Define a function</p>\n<pre><code>def add_token_v4(row, discourse_type, thresh_list: list):\n    #sort in ascending order\n    thresh_list=sorted(thresh_list, key=lambda x: x['start'])\n\n    #check if the spans are overlapping\n    count_array=np.zeros(10000)\n    for d in thresh_list:\n        count_array[d['start']: d['end']+1]+=1\n    if (count_array&gt;1).sum()&gt;=1:\n        raise Exception(\"spans are overlapping\")\n\n    pred_len=len(row['predictionstring'].split())\n    for d in thresh_list:\n        if (row['class']==discourse_type) and (pred_len&gt;=d['start']) and (pred_len&lt;=d['end']):\n            max_idx=int(row['predictionstring'].split()[-1])\n            min_idx=int(row['predictionstring'].split()[0])\n            fix_pred=' '.join([str(i) for i in range(min_idx, max_idx+d['add_num']+1)])\n            return fix_pred\n\n    #If the predictionstring is not contained in any span, return the original predictionstring\n    return row['predictionstring']\n</code></pre>\n<p>③Perform the postprocess<br>\nYou can postprocess by applying the above function to the df for submission.</p>\n<pre><code>submission['predictionstring']=submission.apply(lambda x: add_token_v4(x, 'Claim', claim_thresh_list), axis=1)\n</code></pre>",
          "rawMarkdown": "@aman1391 \nHi, thanks for the comment.\nYou can do  the first part of the postprocessing by the following steps.\n\n①Define thresholds(only the threshold of 'Claim' is defined here)\n\n```\nclaim_thresh_list=[\n                {\n    'start':1,\n    'end':5,\n    'add_num':1\n},\n             {\n    'start':6,\n    'end':10,\n    'add_num':2\n},\n\n{\n    'start':11,\n    'end': 20,\n    'add_num':4\n    \n},\n]\n```\n\n②Define a function\n\n```\ndef add_token_v4(row, discourse_type, thresh_list: list):\n    #sort in ascending order\n    thresh_list=sorted(thresh_list, key=lambda x: x['start'])\n\n    #check if the spans are overlapping\n    count_array=np.zeros(10000)\n    for d in thresh_list:\n        count_array[d['start']: d['end']+1]+=1\n    if (count_array>1).sum()>=1:\n        raise Exception(\"spans are overlapping\")\n    \n    pred_len=len(row['predictionstring'].split())\n    for d in thresh_list:\n        if (row['class']==discourse_type) and (pred_len>=d['start']) and (pred_len<=d['end']):\n            max_idx=int(row['predictionstring'].split()[-1])\n            min_idx=int(row['predictionstring'].split()[0])\n            fix_pred=' '.join([str(i) for i in range(min_idx, max_idx+d['add_num']+1)])\n            return fix_pred\n\n    #If the predictionstring is not contained in any span, return the original predictionstring\n    return row['predictionstring']\n```\n\n\n\n③Perform the postprocess\nYou can postprocess by applying the above function to the df for submission.\n```\nsubmission['predictionstring']=submission.apply(lambda x: add_token_v4(x, 'Claim', claim_thresh_list), axis=1)\n\n```\n",
          "votes": 3
        },
        {
          "id": 1728975,
          "postDate": "2022-03-19T14:07:14.517Z",
          "content": "<p>Thanks for the prompt reply..</p>",
          "rawMarkdown": "Thanks for the prompt reply..",
          "votes": 1
        }
      ]
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-19T12:36:55Z",
  "competition_id": 31779,
  "competition_slug": "feedback-prize-2021",
  "team_id": 7955896,
  "solution_url": "/competitions/feedback-prize-2021/writeups/kuro-b-12th-place-solution-stretching-short-predic"
}