{
  "id": 362691,
  "title": "📌 Advanced Feature Engineering 1 - Goal Angle",
  "url": "/competitions/tabular-playground-series-oct-2022/discussion/362691",
  "author_name": "",
  "post_date": "2022-10-28T14:59:53.654540300Z",
  "votes": 15,
  "comment_count": 7,
  "views": 0,
  "content": "<p>Hi all,</p>\n<p>I created four new features which are goal angle, ball touch positions, car number inside the triangle, and goal direction. The goal angle represents the angle between the two goalposts.</p>\n<p>Feature 1 is the goal angle.<br>\nFeature 2, ball touch positions <a href=\"https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362692\" target=\"_blank\">link</a>.<br>\nFeature 3, the car number in the triangle <a href=\"https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362839\" target=\"_blank\">link</a>.<br>\nFeature 4, goal direction <a href=\"https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362852\" target=\"_blank\">link</a>.</p>\n<h2>Goal Angle</h2>\n<pre><code>def add_angle_features(df):\n    # Goal Line Angle\n    df['A_goal_angle'] = -1\n    df['B_goal_angle'] = -1    \n    ball_point_tpls = [tuple(x) for x in df[['ball_pos_x', 'ball_pos_y']].to_numpy()]\n\n    ## Team A\n    a_angle, b_angle = [], []\n    for ball_pos in ball_point_tpls:\n        # A\n        vec1 = (-16.37 - ball_pos[0], 100 - ball_pos[1])\n        vec2 = (16.47 - ball_pos[0], 100 - ball_pos[1])\n\n        dot_value = vec1[0]*vec2[0]+vec1[1]*vec2[1]\n        cos_angle = dot_value / (np.sqrt(vec1[0]**2+vec1[1]**2)*np.sqrt(vec2[0]**2+vec2[1]**2))\n        angle = math.acos(cos_angle) * (180.0 / math.pi)\n        a_angle.append(angle)\n\n        # B\n        vec1 = (-16.37 - ball_pos[0], -100 - ball_pos[1])\n        vec2 = (16.47 - ball_pos[0], -100 - ball_pos[1])\n\n        dot_value = vec1[0]*vec2[0]+vec1[1]*vec2[1]\n        cos_angle = dot_value / (np.sqrt(vec1[0]**2+vec1[1]**2)*np.sqrt(vec2[0]**2+vec2[1]**2))\n        angle = math.acos(cos_angle) * (180.0 / math.pi)\n        b_angle.append(angle)\n\n    df['A_goal_angle'] = a_angle\n    df['B_goal_angle'] = b_angle\n</code></pre>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3381067%2F8c600e2817f047e25bc136323350eb94%2Fgoal_angle_1.png?generation=1666968821896499&amp;alt=media\" alt=\"\"></p>\n<p>Thank you for the great visualization <a href=\"https://www.kaggle.com/sergiosaharovskiy\" target=\"_blank\">@sergiosaharovskiy</a> ✔️</p>",
  "messages": [
    {
      "id": "2007874",
      "postDate": "10/28/2022 14:59:53",
      "content": "<p>Hi all,</p>\n<p>I created four new features which are goal angle, ball touch positions, car number inside the triangle, and goal direction. The goal angle represents the angle between the two goalposts.</p>\n<p>Feature 1 is the goal angle.<br>\nFeature 2, ball touch positions <a href=\"https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362692\" target=\"_blank\">link</a>.<br>\nFeature 3, the car number in the triangle <a href=\"https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362839\" target=\"_blank\">link</a>.<br>\nFeature 4, goal direction <a href=\"https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362852\" target=\"_blank\">link</a>.</p>\n<h2>Goal Angle</h2>\n<pre><code>def add_angle_features(df):\n    # Goal Line Angle\n    df['A_goal_angle'] = -1\n    df['B_goal_angle'] = -1    \n    ball_point_tpls = [tuple(x) for x in df[['ball_pos_x', 'ball_pos_y']].to_numpy()]\n\n    ## Team A\n    a_angle, b_angle = [], []\n    for ball_pos in ball_point_tpls:\n        # A\n        vec1 = (-16.37 - ball_pos[0], 100 - ball_pos[1])\n        vec2 = (16.47 - ball_pos[0], 100 - ball_pos[1])\n\n        dot_value = vec1[0]*vec2[0]+vec1[1]*vec2[1]\n        cos_angle = dot_value / (np.sqrt(vec1[0]**2+vec1[1]**2)*np.sqrt(vec2[0]**2+vec2[1]**2))\n        angle = math.acos(cos_angle) * (180.0 / math.pi)\n        a_angle.append(angle)\n\n        # B\n        vec1 = (-16.37 - ball_pos[0], -100 - ball_pos[1])\n        vec2 = (16.47 - ball_pos[0], -100 - ball_pos[1])\n\n        dot_value = vec1[0]*vec2[0]+vec1[1]*vec2[1]\n        cos_angle = dot_value / (np.sqrt(vec1[0]**2+vec1[1]**2)*np.sqrt(vec2[0]**2+vec2[1]**2))\n        angle = math.acos(cos_angle) * (180.0 / math.pi)\n        b_angle.append(angle)\n\n    df['A_goal_angle'] = a_angle\n    df['B_goal_angle'] = b_angle\n</code></pre>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3381067%2F8c600e2817f047e25bc136323350eb94%2Fgoal_angle_1.png?generation=1666968821896499&amp;alt=media\" alt=\"\"></p>\n<p>Thank you for the great visualization <a href=\"https://www.kaggle.com/sergiosaharovskiy\" target=\"_blank\">@sergiosaharovskiy</a> ✔️</p>",
      "rawMarkdown": "Hi all,\n\nI created four new features which are goal angle, ball touch positions, car number inside the triangle, and goal direction. The goal angle represents the angle between the two goalposts.\n\nFeature 1 is the goal angle.\nFeature 2, ball touch positions [link](https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362692).\nFeature 3, the car number in the triangle [link](https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362839).\nFeature 4, goal direction [link](https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362852).\n\n## Goal Angle\n```\ndef add_angle_features(df):\n    # Goal Line Angle\n    df['A_goal_angle'] = -1\n    df['B_goal_angle'] = -1    \n    ball_point_tpls = [tuple(x) for x in df[['ball_pos_x', 'ball_pos_y']].to_numpy()]\n\n    ## Team A\n    a_angle, b_angle = [], []\n    for ball_pos in ball_point_tpls:\n        # A\n        vec1 = (-16.37 - ball_pos[0], 100 - ball_pos[1])\n        vec2 = (16.47 - ball_pos[0], 100 - ball_pos[1])\n\n        dot_value = vec1[0]*vec2[0]+vec1[1]*vec2[1]\n        cos_angle = dot_value / (np.sqrt(vec1[0]**2+vec1[1]**2)*np.sqrt(vec2[0]**2+vec2[1]**2))\n        angle = math.acos(cos_angle) * (180.0 / math.pi)\n        a_angle.append(angle)\n\n        # B\n        vec1 = (-16.37 - ball_pos[0], -100 - ball_pos[1])\n        vec2 = (16.47 - ball_pos[0], -100 - ball_pos[1])\n\n        dot_value = vec1[0]*vec2[0]+vec1[1]*vec2[1]\n        cos_angle = dot_value / (np.sqrt(vec1[0]**2+vec1[1]**2)*np.sqrt(vec2[0]**2+vec2[1]**2))\n        angle = math.acos(cos_angle) * (180.0 / math.pi)\n        b_angle.append(angle)\n    \n    df['A_goal_angle'] = a_angle\n    df['B_goal_angle'] = b_angle\n```\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3381067%2F8c600e2817f047e25bc136323350eb94%2Fgoal_angle_1.png?generation=1666968821896499&alt=media)\n\nThank you for the great visualization @sergiosaharovskiy ✔️",
      "votes": null
    },
    {
      "id": "2007913",
      "postDate": "10/28/2022 15:14:20",
      "content": "<p>Cool feature, thanks for sharing !<br>\nDid you benchmark it to tell how well it improves the score ?</p>",
      "rawMarkdown": "Cool feature, thanks for sharing !\nDid you benchmark it to tell how well it improves the score ?",
      "votes": null
    },
    {
      "id": "2008124",
      "postDate": "10/28/2022 19:04:49",
      "content": "<p>Thank you. It is the most important feature of my lgbm model</p>",
      "rawMarkdown": "Thank you. It is the most important feature of my lgbm model",
      "votes": null
    },
    {
      "id": "2008161",
      "postDate": "10/28/2022 19:38:43",
      "content": "<p>Great, I never though about that feature! I took the liberty of vectorizing</p>\n<pre><code>def add_angle_features(df):\n\n    ## Team A Goal\n    v1 = np.array([-16.37, 100]) - df[['ball_pos_x', 'ball_pos_y']]\n    v2 = np.array([16.47, 100]) - df[['ball_pos_x', 'ball_pos_y']]\n    n1 = np.linalg.norm(v1, axis=1)\n    n2 = np.linalg.norm(v2, axis=1)\n    dot = (v1*v2).sum(axis=1)\n    cos_angle = (dot)/(n1*n2)\n    a_angle = np.arccos(cos_angle) * (180.0 / math.pi)\n\n    ## Team B Goal\n    v1 = np.array([-16.37, -100]) - df[['ball_pos_x', 'ball_pos_y']]\n    v2 = np.array([16.47, -100]) - df[['ball_pos_x', 'ball_pos_y']]\n    n1 = np.linalg.norm(v1, axis=1)\n    n2 = np.linalg.norm(v2, axis=1)\n    dot = (v1*v2).sum(axis=1)\n    cos_angle = (dot)/(n1*n2)\n    b_angle = np.arccos(cos_angle) * (180.0 / math.pi)\n\n    df['A_goal_angle'] = a_angle\n    df['B_goal_angle'] = b_angle\n\n    df.A_goal_angle = df.A_goal_angle.astype(np.float32)\n    df.B_goal_angle = df.A_goal_angle.astype(np.float32)\n</code></pre>",
      "rawMarkdown": "Great, I never though about that feature! I took the liberty of vectorizing\n\n```\ndef add_angle_features(df):\n\n    ## Team A Goal\n    v1 = np.array([-16.37, 100]) - df[['ball_pos_x', 'ball_pos_y']]\n    v2 = np.array([16.47, 100]) - df[['ball_pos_x', 'ball_pos_y']]\n    n1 = np.linalg.norm(v1, axis=1)\n    n2 = np.linalg.norm(v2, axis=1)\n    dot = (v1*v2).sum(axis=1)\n    cos_angle = (dot)/(n1*n2)\n    a_angle = np.arccos(cos_angle) * (180.0 / math.pi)\n\n    ## Team B Goal\n    v1 = np.array([-16.37, -100]) - df[['ball_pos_x', 'ball_pos_y']]\n    v2 = np.array([16.47, -100]) - df[['ball_pos_x', 'ball_pos_y']]\n    n1 = np.linalg.norm(v1, axis=1)\n    n2 = np.linalg.norm(v2, axis=1)\n    dot = (v1*v2).sum(axis=1)\n    cos_angle = (dot)/(n1*n2)\n    b_angle = np.arccos(cos_angle) * (180.0 / math.pi)\n\n    df['A_goal_angle'] = a_angle\n    df['B_goal_angle'] = b_angle\n    \n    df.A_goal_angle = df.A_goal_angle.astype(np.float32)\n    df.B_goal_angle = df.A_goal_angle.astype(np.float32)\n```",
      "votes": null
    },
    {
      "id": "2008210",
      "postDate": "10/28/2022 20:31:45",
      "content": "<p>That's cool. I'm not entirely sure if this is exactly the same but I used a similar feature. For me, it didn't work very well but maybe that's because I didn't have the right coordinates for the poles. </p>\n<p>By the way, are angles also scaled using StandardScaler?</p>\n<p>`</p>\n<pre><code>X=df[['ball_pos_x', 'ball_pos_y']].values\ndef view_on_goal(X,goal):\n\n    A=goal-np.array([-10,0])-X\n\n    B=goal+np.array([10,0])-X\n\n    return np.arctan2(A[:, 0]*B[:, 1]- B[:, 0]*A[:, 1],A[:, 0]*A[:, 1]+B[:, 1]*B[:, 1])`\n</code></pre>",
      "rawMarkdown": "That's cool. I'm not entirely sure if this is exactly the same but I used a similar feature. For me, it didn't work very well but maybe that's because I didn't have the right coordinates for the poles. \n\nBy the way, are angles also scaled using StandardScaler?\n\n`\n\n    X=df[['ball_pos_x', 'ball_pos_y']].values\n    def view_on_goal(X,goal):\n\n        A=goal-np.array([-10,0])-X\n\n        B=goal+np.array([10,0])-X\n\n        return np.arctan2(A[:, 0]*B[:, 1]- B[:, 0]*A[:, 1],A[:, 0]*A[:, 1]+B[:, 1]*B[:, 1])`",
      "votes": null
    },
    {
      "id": "2009082",
      "postDate": "10/29/2022 16:11:35",
      "content": "<p>The angle feature is between 0 and 180. You can scale it by dividing 180</p>",
      "rawMarkdown": "The angle feature is between 0 and 180. You can scale it by dividing 180",
      "votes": null
    },
    {
      "id": "2009363",
      "postDate": "10/29/2022 23:06:58",
      "content": "<p>Thank you for putting this together and sharing it.  It was something I had thought about and did not get a chance to put together.  I am interested in what you observed for the feature importance of the new features.  Happy to help with this, if it has not been tackled already.</p>",
      "rawMarkdown": "Thank you for putting this together and sharing it.  It was something I had thought about and did not get a chance to put together.  I am interested in what you observed for the feature importance of the new features.  Happy to help with this, if it has not been tackled already.",
      "votes": null
    },
    {
      "id": "2010637",
      "postDate": "10/31/2022 00:56:01",
      "content": "<p>This is turning out to be an awesome feature. Thanks for sharing <a href=\"https://www.kaggle.com/hasanbasriakcay\" target=\"_blank\">@hasanbasriakcay</a>!</p>",
      "rawMarkdown": "This is turning out to be an awesome feature. Thanks for sharing @hasanbasriakcay!",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 2007913,
      "author_name": "pluplu76",
      "author_url": "",
      "post_date": "10/28/2022 15:14:20",
      "content": "<p>Cool feature, thanks for sharing !<br>\nDid you benchmark it to tell how well it improves the score ?</p>",
      "votes": null,
      "replies": [
        {
          "id": 2008124,
          "author_name": "hasanbasriakcay",
          "author_url": "",
          "post_date": "10/28/2022 19:04:49",
          "content": "<p>Thank you. It is the most important feature of my lgbm model</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2008161,
      "author_name": "jcaliz",
      "author_url": "",
      "post_date": "10/28/2022 19:38:43",
      "content": "<p>Great, I never though about that feature! I took the liberty of vectorizing</p>\n<pre><code>def add_angle_features(df):\n\n    ## Team A Goal\n    v1 = np.array([-16.37, 100]) - df[['ball_pos_x', 'ball_pos_y']]\n    v2 = np.array([16.47, 100]) - df[['ball_pos_x', 'ball_pos_y']]\n    n1 = np.linalg.norm(v1, axis=1)\n    n2 = np.linalg.norm(v2, axis=1)\n    dot = (v1*v2).sum(axis=1)\n    cos_angle = (dot)/(n1*n2)\n    a_angle = np.arccos(cos_angle) * (180.0 / math.pi)\n\n    ## Team B Goal\n    v1 = np.array([-16.37, -100]) - df[['ball_pos_x', 'ball_pos_y']]\n    v2 = np.array([16.47, -100]) - df[['ball_pos_x', 'ball_pos_y']]\n    n1 = np.linalg.norm(v1, axis=1)\n    n2 = np.linalg.norm(v2, axis=1)\n    dot = (v1*v2).sum(axis=1)\n    cos_angle = (dot)/(n1*n2)\n    b_angle = np.arccos(cos_angle) * (180.0 / math.pi)\n\n    df['A_goal_angle'] = a_angle\n    df['B_goal_angle'] = b_angle\n\n    df.A_goal_angle = df.A_goal_angle.astype(np.float32)\n    df.B_goal_angle = df.A_goal_angle.astype(np.float32)\n</code></pre>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2008210,
      "author_name": "robinbarbarino",
      "author_url": "",
      "post_date": "10/28/2022 20:31:45",
      "content": "<p>That's cool. I'm not entirely sure if this is exactly the same but I used a similar feature. For me, it didn't work very well but maybe that's because I didn't have the right coordinates for the poles. </p>\n<p>By the way, are angles also scaled using StandardScaler?</p>\n<p>`</p>\n<pre><code>X=df[['ball_pos_x', 'ball_pos_y']].values\ndef view_on_goal(X,goal):\n\n    A=goal-np.array([-10,0])-X\n\n    B=goal+np.array([10,0])-X\n\n    return np.arctan2(A[:, 0]*B[:, 1]- B[:, 0]*A[:, 1],A[:, 0]*A[:, 1]+B[:, 1]*B[:, 1])`\n</code></pre>",
      "votes": null,
      "replies": [
        {
          "id": 2009082,
          "author_name": "hasanbasriakcay",
          "author_url": "",
          "post_date": "10/29/2022 16:11:35",
          "content": "<p>The angle feature is between 0 and 180. You can scale it by dividing 180</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2009363,
      "author_name": "michaeljf",
      "author_url": "",
      "post_date": "10/29/2022 23:06:58",
      "content": "<p>Thank you for putting this together and sharing it.  It was something I had thought about and did not get a chance to put together.  I am interested in what you observed for the feature importance of the new features.  Happy to help with this, if it has not been tackled already.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2010637,
      "author_name": "tobetek",
      "author_url": "",
      "post_date": "10/31/2022 00:56:01",
      "content": "<p>This is turning out to be an awesome feature. Thanks for sharing <a href=\"https://www.kaggle.com/hasanbasriakcay\" target=\"_blank\">@hasanbasriakcay</a>!</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "2007874": "Hi all,\n\nI created four new features which are goal angle, ball touch positions, car number inside the triangle, and goal direction. The goal angle represents the angle between the two goalposts.\n\nFeature 1 is the goal angle.\nFeature 2, ball touch positions [link](https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362692).\nFeature 3, the car number in the triangle [link](https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362839).\nFeature 4, goal direction [link](https://www.kaggle.com/competitions/tabular-playground-series-oct-2022/discussion/362852).\n\n## Goal Angle\n```\ndef add_angle_features(df):\n    # Goal Line Angle\n    df['A_goal_angle'] = -1\n    df['B_goal_angle'] = -1    \n    ball_point_tpls = [tuple(x) for x in df[['ball_pos_x', 'ball_pos_y']].to_numpy()]\n\n    ## Team A\n    a_angle, b_angle = [], []\n    for ball_pos in ball_point_tpls:\n        # A\n        vec1 = (-16.37 - ball_pos[0], 100 - ball_pos[1])\n        vec2 = (16.47 - ball_pos[0], 100 - ball_pos[1])\n\n        dot_value = vec1[0]*vec2[0]+vec1[1]*vec2[1]\n        cos_angle = dot_value / (np.sqrt(vec1[0]**2+vec1[1]**2)*np.sqrt(vec2[0]**2+vec2[1]**2))\n        angle = math.acos(cos_angle) * (180.0 / math.pi)\n        a_angle.append(angle)\n\n        # B\n        vec1 = (-16.37 - ball_pos[0], -100 - ball_pos[1])\n        vec2 = (16.47 - ball_pos[0], -100 - ball_pos[1])\n\n        dot_value = vec1[0]*vec2[0]+vec1[1]*vec2[1]\n        cos_angle = dot_value / (np.sqrt(vec1[0]**2+vec1[1]**2)*np.sqrt(vec2[0]**2+vec2[1]**2))\n        angle = math.acos(cos_angle) * (180.0 / math.pi)\n        b_angle.append(angle)\n    \n    df['A_goal_angle'] = a_angle\n    df['B_goal_angle'] = b_angle\n```\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3381067%2F8c600e2817f047e25bc136323350eb94%2Fgoal_angle_1.png?generation=1666968821896499&alt=media)\n\nThank you for the great visualization @sergiosaharovskiy ✔️",
    "2007913": "Cool feature, thanks for sharing !\nDid you benchmark it to tell how well it improves the score ?",
    "2008124": "Thank you. It is the most important feature of my lgbm model",
    "2008161": "Great, I never though about that feature! I took the liberty of vectorizing\n\n```\ndef add_angle_features(df):\n\n    ## Team A Goal\n    v1 = np.array([-16.37, 100]) - df[['ball_pos_x', 'ball_pos_y']]\n    v2 = np.array([16.47, 100]) - df[['ball_pos_x', 'ball_pos_y']]\n    n1 = np.linalg.norm(v1, axis=1)\n    n2 = np.linalg.norm(v2, axis=1)\n    dot = (v1*v2).sum(axis=1)\n    cos_angle = (dot)/(n1*n2)\n    a_angle = np.arccos(cos_angle) * (180.0 / math.pi)\n\n    ## Team B Goal\n    v1 = np.array([-16.37, -100]) - df[['ball_pos_x', 'ball_pos_y']]\n    v2 = np.array([16.47, -100]) - df[['ball_pos_x', 'ball_pos_y']]\n    n1 = np.linalg.norm(v1, axis=1)\n    n2 = np.linalg.norm(v2, axis=1)\n    dot = (v1*v2).sum(axis=1)\n    cos_angle = (dot)/(n1*n2)\n    b_angle = np.arccos(cos_angle) * (180.0 / math.pi)\n\n    df['A_goal_angle'] = a_angle\n    df['B_goal_angle'] = b_angle\n    \n    df.A_goal_angle = df.A_goal_angle.astype(np.float32)\n    df.B_goal_angle = df.A_goal_angle.astype(np.float32)\n```",
    "2008210": "That's cool. I'm not entirely sure if this is exactly the same but I used a similar feature. For me, it didn't work very well but maybe that's because I didn't have the right coordinates for the poles. \n\nBy the way, are angles also scaled using StandardScaler?\n\n`\n\n    X=df[['ball_pos_x', 'ball_pos_y']].values\n    def view_on_goal(X,goal):\n\n        A=goal-np.array([-10,0])-X\n\n        B=goal+np.array([10,0])-X\n\n        return np.arctan2(A[:, 0]*B[:, 1]- B[:, 0]*A[:, 1],A[:, 0]*A[:, 1]+B[:, 1]*B[:, 1])`",
    "2009082": "The angle feature is between 0 and 180. You can scale it by dividing 180",
    "2009363": "Thank you for putting this together and sharing it.  It was something I had thought about and did not get a chance to put together.  I am interested in what you observed for the feature importance of the new features.  Happy to help with this, if it has not been tackled already.",
    "2010637": "This is turning out to be an awesome feature. Thanks for sharing @hasanbasriakcay!"
  },
  "source": "meta"
}