{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"sourceType":"competition"},{"sourceId":12668552,"sourceType":"datasetVersion","datasetId":8005743},{"sourceId":12670716,"sourceType":"datasetVersion","datasetId":8007146},{"sourceId":12670806,"sourceType":"datasetVersion","datasetId":8007201},{"sourceId":12770395,"sourceType":"datasetVersion","datasetId":8073088},{"sourceId":12771122,"sourceType":"datasetVersion","datasetId":8073596},{"sourceId":12771235,"sourceType":"datasetVersion","datasetId":8073682}],"dockerImageVersionId":31089,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-08-20T05:20:58.893354Z","iopub.execute_input":"2025-08-20T05:20:58.893705Z","iopub.status.idle":"2025-08-20T05:20:59.267098Z","shell.execute_reply.started":"2025-08-20T05:20:58.893661Z","shell.execute_reply":"2025-08-20T05:20:59.266397Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import polars as pl\nimport pandas as pd\nimport os\nimport re\nimport matplotlib.pyplot as plt\nimport polars as pl\nimport pandas as pd\nimport numpy as np\nimport catboost as cb\nfrom sklearn.model_selection import StratifiedGroupKFold\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.metrics import f1_score\nimport joblib\nimport warnings\nimport pickle\nimport json\nimport kaggle_evaluation.cmi_inference_server\nwarnings.simplefilter(\"ignore\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-20T05:20:59.268226Z","iopub.execute_input":"2025-08-20T05:20:59.268549Z","iopub.status.idle":"2025-08-20T05:21:01.734278Z","shell.execute_reply.started":"2025-08-20T05:20:59.268525Z","shell.execute_reply":"2025-08-20T05:21:01.733436Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from scipy.spatial.transform import Rotation as R\nimport pandas as pd\nimport numpy as np\nimport os\ndef remove_gravity_from_acc(acc_data, rot_data):\n\n    if isinstance(acc_data, pd.DataFrame):\n        acc_values = acc_data[['acc_x', 'acc_y', 'acc_z']].values\n    else:\n        acc_values = acc_data\n\n    if isinstance(rot_data, pd.DataFrame):\n        quat_values = rot_data[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    else:\n        quat_values = rot_data\n\n    num_samples = acc_values.shape[0]\n    linear_accel = np.zeros_like(acc_values)\n    \n    gravity_world = np.array([0, 0, 9.81])\n\n    for i in range(num_samples):\n        if np.all(np.isnan(quat_values[i])) or np.all(np.isclose(quat_values[i], 0)):\n            linear_accel[i, :] = acc_values[i, :] \n            continue\n\n        try:\n            rotation = R.from_quat(quat_values[i])\n            gravity_sensor_frame = rotation.apply(gravity_world, inverse=True)\n            linear_accel[i, :] = acc_values[i, :] - gravity_sensor_frame\n        except ValueError:\n             linear_accel[i, :] = acc_values[i, :]\n             \n    return linear_accel\n\n\ndef calculate_angular_velocity_from_quat(rot_data, time_delta=1/200): # Assuming 200Hz sampling rate\n    if isinstance(rot_data, pd.DataFrame):\n        quat_values = rot_data[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    else:\n        quat_values = rot_data\n\n    num_samples = quat_values.shape[0]\n    angular_vel = np.zeros((num_samples, 3))\n\n    for i in range(num_samples - 1):\n        q_t = quat_values[i]\n        q_t_plus_dt = quat_values[i+1]\n\n        if np.all(np.isnan(q_t)) or np.all(np.isclose(q_t, 0)) or \\\n           np.all(np.isnan(q_t_plus_dt)) or np.all(np.isclose(q_t_plus_dt, 0)):\n            continue\n\n        try:\n            rot_t = R.from_quat(q_t)\n            rot_t_plus_dt = R.from_quat(q_t_plus_dt)\n\n            # Calculate the relative rotation\n            delta_rot = rot_t.inv() * rot_t_plus_dt\n            \n            # Convert delta rotation to angular velocity vector\n            # The rotation vector (Euler axis * angle) scaled by 1/dt\n            # is a good approximation for small delta_rot\n            angular_vel[i, :] = delta_rot.as_rotvec() / time_delta\n        except ValueError:\n            # If quaternion is invalid, angular velocity remains zero\n            pass\n            \n    return angular_vel\n\ndef calculate_angular_distance(rot_data):\n    if isinstance(rot_data, pd.DataFrame):\n        quat_values = rot_data[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    else:\n        quat_values = rot_data\n\n    num_samples = quat_values.shape[0]\n    angular_dist = np.zeros(num_samples)\n\n    for i in range(num_samples - 1):\n        q1 = quat_values[i]\n        q2 = quat_values[i+1]\n\n        if np.all(np.isnan(q1)) or np.all(np.isclose(q1, 0)) or \\\n           np.all(np.isnan(q2)) or np.all(np.isclose(q2, 0)):\n            angular_dist[i] = 0 # Или np.nan, в зависимости от желаемого поведения\n            continue\n        try:\n            # Преобразование кватернионов в объекты Rotation\n            r1 = R.from_quat(q1)\n            r2 = R.from_quat(q2)\n\n            # Вычисление углового расстояния: 2 * arccos(|real(p * q*)|)\n            # где p* - сопряженный кватернион q\n            # В scipy.spatial.transform.Rotation, r1.inv() * r2 дает относительное вращение.\n            # Угол этого относительного вращения - это и есть угловое расстояние.\n            relative_rotation = r1.inv() * r2\n            \n            # Угол rotation vector соответствует угловому расстоянию\n            # Норма rotation vector - это угол в радианах\n            angle = np.linalg.norm(relative_rotation.as_rotvec())\n            angular_dist[i] = angle\n        except ValueError:\n            angular_dist[i] = 0 # В случае недействительных кватернионов\n            pass\n            \n    return angular_dist\n\nimport polars as pl\nimport numpy as np\nfrom scipy.spatial.transform import Rotation as R\n\ndef remove_gravity_polars(df: pl.DataFrame) -> pl.DataFrame:\n    \"\"\"Remove gravity component from acceleration using quaternion orientation\"\"\"\n    # Convert to pandas for this complex operation\n    pdf = df.select([\"acc_x\", \"acc_y\", \"acc_z\", \"rot_x\", \"rot_y\", \"rot_z\", \"rot_w\"]).to_pandas()\n    linear_accel = remove_gravity_from_acc(pdf[['acc_x', 'acc_y', 'acc_z']], \n                                         pdf[['rot_x', 'rot_y', 'rot_z', 'rot_w']])\n    return df.with_columns([\n        pl.Series(\"linear_acc_x\", linear_accel[:, 0]),\n        pl.Series(\"linear_acc_y\", linear_accel[:, 1]),\n        pl.Series(\"linear_acc_z\", linear_accel[:, 2])\n    ])\n\ndef angular_velocity_polars(df: pl.DataFrame) -> pl.DataFrame:\n    \"\"\"Calculate angular velocity from quaternions\"\"\"\n    pdf = df.select([\"rot_x\", \"rot_y\", \"rot_z\", \"rot_w\"]).to_pandas()\n    ang_vel = calculate_angular_velocity_from_quat(pdf)\n    return df.with_columns([\n        pl.Series(\"angular_vel_x\", ang_vel[:, 0]),\n        pl.Series(\"angular_vel_y\", ang_vel[:, 1]),\n        pl.Series(\"angular_vel_z\", ang_vel[:, 2])\n    ])\n\ndef angular_distance_polars(df: pl.DataFrame) -> pl.DataFrame:\n    \"\"\"Calculate angular distance between quaternions\"\"\"\n    pdf = df.select([\"rot_x\", \"rot_y\", \"rot_z\", \"rot_w\"]).to_pandas()\n    ang_dist = calculate_angular_distance(pdf)\n    return df.with_columns(pl.Series(\"angular_distance\", ang_dist))\n\ndef add_motion_intensity(df: pl.DataFrame) -> pl.DataFrame:\n    \"\"\"Add motion intensity features\"\"\"\n    return df.with_columns([\n        # Linear motion intensity\n        ((pl.col(\"linear_acc_x\")**2 + pl.col(\"linear_acc_y\")**2 + pl.col(\"linear_acc_z\")**2)**0.5)\n        .alias(\"linear_acc_magnitude\"),\n        \n        # Rotational motion intensity\n        ((pl.col(\"angular_vel_x\")**2 + pl.col(\"angular_vel_y\")**2 + pl.col(\"angular_vel_z\")**2)**0.5)\n        .alias(\"angular_vel_magnitude\"),\n        \n        # Combined motion intensity\n        ((pl.col(\"linear_acc_magnitude\")**2 + pl.col(\"angular_vel_magnitude\")**2)**0.5)\n        .alias(\"combined_motion_intensity\")\n    ])\n\ndef add_jerk_features(df: pl.DataFrame, sampling_rate: float = 200) -> pl.DataFrame:\n    \"\"\"Calculate jerk (derivative of acceleration)\"\"\"\n    dt = 1/sampling_rate\n    return df.with_columns([\n        # Linear jerk components\n        pl.col(\"linear_acc_x\").diff().fill_null(0)/dt,\n        pl.col(\"linear_acc_y\").diff().fill_null(0)/dt,\n        pl.col(\"linear_acc_z\").diff().fill_null(0)/dt,\n        \n        # Angular jerk (derivative of angular velocity)\n        pl.col(\"angular_vel_x\").diff().fill_null(0)/dt,\n        pl.col(\"angular_vel_y\").diff().fill_null(0)/dt,\n        pl.col(\"angular_vel_z\").diff().fill_null(0)/dt\n    ]).rename({\n        \"linear_acc_x_diff\": \"jerk_x\",\n        \"linear_acc_y_diff\": \"jerk_y\",\n        \"linear_acc_z_diff\": \"jerk_z\",\n        \"angular_vel_x_diff\": \"angular_jerk_x\",\n        \"angular_vel_y_diff\": \"angular_jerk_y\",\n        \"angular_vel_z_diff\": \"angular_jerk_z\"\n    })\n\ndef add_smoothness_metrics(df: pl.DataFrame, window_size: int = 5) -> pl.DataFrame:\n    \"\"\"Add metrics that quantify movement smoothness\"\"\"\n    return df.with_columns([\n        # Signal magnitude area (SMA)\n        (pl.col(\"linear_acc_x\").abs() + pl.col(\"linear_acc_y\").abs() + pl.col(\"linear_acc_z\").abs())\n        .alias(\"sma_linear_acc\"),\n        \n        # Rolling standard deviation (movement variability)\n        pl.col(\"linear_acc_magnitude\").rolling_std(window_size).alias(\"acc_variability\"),\n        pl.col(\"angular_vel_magnitude\").rolling_std(window_size).alias(\"ang_vel_variability\"),\n        \n        # Zero-crossing rate (movement frequency)\n        (pl.col(\"linear_acc_x\").sign().diff().abs() > 1).rolling_sum(window_size).alias(\"zero_crossing_rate\")\n    ])\n\ndef add_statistical_features(df: pl.DataFrame, window_size: int = 10) -> pl.DataFrame:\n    \"\"\"Add rolling statistical features\"\"\"\n    return df.with_columns([\n        # Rolling mean features\n        pl.col(\"linear_acc_magnitude\").rolling_mean(window_size).alias(\"rolling_mean_acc\"),\n        pl.col(\"angular_vel_magnitude\").rolling_mean(window_size).alias(\"rolling_mean_ang_vel\"),\n        \n        # Rolling max features\n        pl.col(\"linear_acc_magnitude\").rolling_max(window_size).alias(\"rolling_max_acc\"),\n        pl.col(\"angular_vel_magnitude\").rolling_max(window_size).alias(\"rolling_max_ang_vel\"),\n        \n        # Energy (sum of squares)\n        (pl.col(\"linear_acc_x\")**2 + pl.col(\"linear_acc_y\")**2 + pl.col(\"linear_acc_z\")**2)\n        .rolling_mean(window_size).alias(\"energy_linear_acc\")\n    ])    \n\ndef feature_engineering_polars(df: pl.DataFrame) -> pl.DataFrame:\n    \"\"\"Complete feature engineering pipeline with proper FFT handling\"\"\"\n    # Calculate all non-FFT features first\n    base_features = (\n        df\n        .with_columns([\n            (pl.col(\"acc_x\")**2 + pl.col(\"acc_y\")**2 + pl.col(\"acc_z\")**2).sqrt().alias(\"acc_mag\"),\n            (pl.col(\"rot_x\")**2 + pl.col(\"rot_y\")**2 + pl.col(\"rot_z\")**2).sqrt().alias(\"rot_angle\"),\n            (2 * pl.col(\"rot_w\").clip(-1, 1).arccos()).alias(\"rot_angle_quat\"),\n        ])\n\n        # .pipe(remove_gravity_polars)\n        # .pipe(angular_velocity_polars)\n        # .pipe(angular_distance_polars)\n        \n        # --- Jerk Features ---\n        .with_columns([\n            pl.col(\"acc_x\").diff().over(\"sequence_id\").alias(\"acc_x_jerk\"),\n            pl.col(\"acc_y\").diff().over(\"sequence_id\").alias(\"acc_y_jerk\"),\n            pl.col(\"acc_z\").diff().over(\"sequence_id\").alias(\"acc_z_jerk\"),\n            pl.col(\"acc_mag\").diff().over(\"sequence_id\").alias(\"acc_mag_jerk_alt\"),\n        ])\n\n        # --- acc features added\n        .with_columns([\n            (pl.col(\"acc_x\") + pl.col(\"acc_y\") - pl.col(\"acc_z\")).alias(\"acc_xy_z_net\"),\n            (pl.col(\"acc_y\") + pl.col(\"acc_z\") - pl.col(\"acc_x\")).alias(\"acc_yz_x_net\"),\n            (pl.col(\"acc_x\") + pl.col(\"acc_z\") - pl.col(\"acc_y\")).alias(\"acc_xz_y_net\"),\n            \n            (pl.col(\"acc_x\") - pl.col(\"acc_y\") - pl.col(\"acc_z\")).alias(\"acc_x_minus_yz\"),\n            (pl.col(\"acc_y\") - pl.col(\"acc_x\") - pl.col(\"acc_z\")).alias(\"acc_y_minus_xz\"),\n            (pl.col(\"acc_z\") - pl.col(\"acc_x\") - pl.col(\"acc_y\")).alias(\"acc_z_minus_xy\"),\n\n            (pl.col(\"acc_x\") * pl.col(\"acc_y\")).alias(\"acc_xy_product\"),\n            (pl.col(\"acc_x\") * pl.col(\"acc_z\")).alias(\"acc_xz_product\"),\n            (pl.col(\"acc_y\") * pl.col(\"acc_z\")).alias(\"acc_yz_product\"),\n            \n            (pl.col(\"acc_x\") * pl.col(\"acc_y\") * pl.col(\"acc_z\")).alias(\"acc_xyz_product\"),\n            \n            (pl.col(\"acc_x\") * pl.col(\"acc_y\") - pl.col(\"acc_z\")).alias(\"acc_xy_z_net_ms\"),\n            (pl.col(\"acc_y\") * pl.col(\"acc_z\") - pl.col(\"acc_x\")).alias(\"acc_yz_x_net_ms\"),\n            (pl.col(\"acc_x\") * pl.col(\"acc_z\") - pl.col(\"acc_y\")).alias(\"acc_xz_y_net_ms\"), \n\n            (pl.col(\"acc_x\") / (pl.col(\"acc_y\").abs() + 1e-6)).alias(\"acc_x_over_y\"),\n            (pl.col(\"acc_x\") / (pl.col(\"acc_z\").abs() + 1e-6)).alias(\"acc_x_over_z\"),\n            (pl.col(\"acc_y\") / (pl.col(\"acc_x\").abs() + 1e-6)).alias(\"acc_y_over_x\"),\n            (pl.col(\"acc_y\") / (pl.col(\"acc_z\").abs() + 1e-6)).alias(\"acc_y_over_z\"),\n            (pl.col(\"acc_z\") / (pl.col(\"acc_x\").abs() + 1e-6)).alias(\"acc_z_over_x\"),\n            (pl.col(\"acc_z\") / (pl.col(\"acc_y\").abs() + 1e-6)).alias(\"acc_z_over_y\"),\n            \n            ((pl.col(\"acc_x\") + pl.col(\"acc_y\")) / (pl.col(\"acc_z\").abs() + 1e-6)).alias(\"acc_xy_over_z\"),\n            ((pl.col(\"acc_x\") + pl.col(\"acc_z\")) / (pl.col(\"acc_y\").abs() + 1e-6)).alias(\"acc_xz_over_y\"),\n            ((pl.col(\"acc_y\") + pl.col(\"acc_z\")) / (pl.col(\"acc_x\").abs() + 1e-6)).alias(\"acc_yz_over_x\"),  \n\n            # (pl.col(\"acc_x\")**2 + pl.col(\"acc_y\")**2 + pl.col(\"acc_z\")**2).sqrt().alias(\"acc_magnitude\"),\n            (pl.col(\"acc_x\")**2 + pl.col(\"acc_y\")**2).sqrt().alias(\"acc_xy_magnitude\"),\n            (pl.col(\"acc_x\")**2 + pl.col(\"acc_z\")**2).sqrt().alias(\"acc_xz_magnitude\"),\n            (pl.col(\"acc_y\")**2 + pl.col(\"acc_z\")**2).sqrt().alias(\"acc_yz_magnitude\"),  \n\n            ((pl.col(\"acc_x\")**2 + pl.col(\"acc_y\")**2).sqrt() / (pl.col(\"acc_z\").abs() + 1e-6)).alias(\"acc_horizontal_vertical_ratio\"),\n            \n            # Direction cosines\n            # (pl.col(\"acc_x\") / (pl.col(\"acc_magnitude\") + 1e-6)).alias(\"acc_x_direction_cosine\"),\n            # (pl.col(\"acc_y\") / (pl.col(\"acc_magnitude\") + 1e-6)).alias(\"acc_y_direction_cosine\"),\n            # (pl.col(\"acc_z\") / (pl.col(\"acc_magnitude\") + 1e-6)).alias(\"acc_z_direction_cosine\"),\n\n            (pl.col(\"acc_x\").abs().log1p() * pl.col(\"acc_x\").sign()).alias(\"acc_x_log_scaled\"),\n            (pl.col(\"acc_y\").abs().log1p() * pl.col(\"acc_y\").sign()).alias(\"acc_y_log_scaled\"),\n            (pl.col(\"acc_z\").abs().log1p() * pl.col(\"acc_z\").sign()).alias(\"acc_z_log_scaled\"),\n            \n            # Exponential features\n            (pl.col(\"acc_x\").exp()).alias(\"acc_x_exp\"),\n            (pl.col(\"acc_y\").exp()).alias(\"acc_y_exp\"),\n            (pl.col(\"acc_z\").exp()).alias(\"acc_z_exp\")            \n        ])\n        # --- Energy Features (using raw acc) ---\n        .with_columns(\n            (pl.col(\"acc_x\")**2 + pl.col(\"acc_y\")**2 + pl.col(\"acc_z\")**2).alias(\"acc_energy\")\n        )\n        \n        # --- Linear Acceleration Features (must come before linear energy) ---\n        .with_columns([\n            (pl.col(\"acc_x\") - pl.col(\"acc_x\").mean()).alias(\"linear_acc_x\"),\n            (pl.col(\"acc_y\") - pl.col(\"acc_y\").mean()).alias(\"linear_acc_y\"),\n            (pl.col(\"acc_z\") - pl.col(\"acc_z\").mean()).alias(\"linear_acc_z\"),\n        ])\n        .with_columns([\n            (pl.col(\"linear_acc_x\")**2 + pl.col(\"linear_acc_y\")**2 + pl.col(\"linear_acc_z\")**2).sqrt().alias(\"linear_acc_mag\"),\n            (pl.col(\"linear_acc_x\")**2 + pl.col(\"linear_acc_y\")**2 + pl.col(\"linear_acc_z\")**2).alias(\"linear_acc_energy\"),\n        ])\n        \n        # --- Complete Jerk magnitude calculation ---\n        .with_columns(\n            (pl.col(\"acc_x_jerk\")**2 + pl.col(\"acc_y_jerk\")**2 + pl.col(\"acc_z_jerk\")**2).sqrt().alias(\"acc_mag_jerk\")\n        )\n        \n        # --- Angular Velocity Features ---\n        .with_columns([\n            pl.col(\"rot_w\").diff().over(\"sequence_id\").alias(\"rot_w_vel\"),\n            pl.col(\"rot_x\").diff().over(\"sequence_id\").alias(\"rot_x_vel\"),\n            pl.col(\"rot_y\").diff().over(\"sequence_id\").alias(\"rot_y_vel\"),\n            pl.col(\"rot_z\").diff().over(\"sequence_id\").alias(\"rot_z_vel\"),\n        ])\n        .with_columns(\n            (pl.col(\"rot_x_vel\")**2 + pl.col(\"rot_y_vel\")**2 + pl.col(\"rot_z_vel\")**2).sqrt().alias(\"rot_angle_vel\")\n        )\n        \n        # --- Orientation Features ---\n        .with_columns([\n            (2 * (pl.col(\"rot_w\") * pl.col(\"rot_y\") - pl.col(\"rot_z\") * pl.col(\"rot_x\"))).alias(\"pitch_sin\"),\n            (1 - 2 * (pl.col(\"rot_y\")**2 + pl.col(\"rot_z\")**2)).alias(\"pitch_cos\"),\n            (pl.col(\"rot_w\")**2 + pl.col(\"rot_x\")**2 + pl.col(\"rot_y\")**2 + pl.col(\"rot_z\")**2).sqrt().alias(\"quat_norm\"),\n        ])\n        .with_columns(\n            (pl.col(\"pitch_sin\") / (pl.col(\"pitch_cos\") + 1e-7)).arctan().alias(\"pitch_approx\")\n        )\n        \n        # --- Advanced Physics-based Features ---\n        .pipe(remove_gravity_polars)\n        .pipe(angular_velocity_polars)\n        .pipe(angular_distance_polars)\n        # .pipe(add_motion_intensity)\n        # .pipe(add_jerk_features)\n        # .pipe(add_statistical_features)\n        # --- Higher-order derivatives --- removed\n        .with_columns([\n            pl.col(\"angular_vel_x\").diff().over(\"sequence_id\").alias(\"angular_jerk_x\"),\n            pl.col(\"angular_vel_y\").diff().over(\"sequence_id\").alias(\"angular_jerk_y\"),\n            pl.col(\"angular_vel_z\").diff().over(\"sequence_id\").alias(\"angular_jerk_z\"),\n        ])\n        \n        # --- Signal Processing Features ---\n        #************************************************************************** uuuu\n        .with_columns([\n            pl.col(\"acc_mag\").rolling_mean(5, min_periods=1).over(\"sequence_id\").alias(\"acc_mag_smooth\"),\n            pl.col(\"linear_acc_mag\").rolling_std(5, min_periods=1).over(\"sequence_id\").alias(\"linear_acc_std\"),\n        #     #######################################rolling mean newly added features#################################\n        #     # pl.col(\"acc_mag\").rolling_mean(3, min_periods=1).over(\"sequence_id\").alias(\"acc_mag_smooth3\"),\n        #     # pl.col(\"linear_acc_mag\").rolling_std(3, min_periods=1).over(\"sequence_id\").alias(\"linear_acc_std3\"),\n        #     # pl.col(\"acc_mag\").rolling_mean(7, min_periods=1).over(\"sequence_id\").alias(\"acc_mag_smooth7\"),\n        #     # pl.col(\"linear_acc_mag\").rolling_std(7, min_periods=1).over(\"sequence_id\").alias(\"linear_acc_std7\"), \n        #     ################################################################################################################\n            pl.col(\"acc_mag\").diff().var().over(\"sequence_id\").alias(\"acc_entropy\"),\n            ((pl.col(\"acc_mag\") > pl.col(\"acc_mag\").shift(1)) & \n             (pl.col(\"acc_mag\") > pl.col(\"acc_mag\").shift(-1))).cast(pl.Int8).sum().over(\"sequence_id\").alias(\"peak_count\"),\n        ])\n        .with_columns(pl.all().fill_null(0)) \n        #**************************************************************************\n        .with_columns([\n            # Forward/backward vs lateral movement interaction\n            (pl.col(\"acc_x\") * pl.col(\"acc_y\")).alias(\"acc_xy_interaction\"),\n            (pl.col(\"acc_x\") * pl.col(\"acc_z\")).alias(\"acc_xz_interaction\"),\n            \n            # Vertical vs horizontal dominance\n            (pl.col(\"acc_z\") / (pl.col(\"acc_x\").abs() + pl.col(\"acc_y\").abs() + 1e-7)).alias(\"vertical_dominance\"),\n            \n            # Directional balance\n            (pl.col(\"acc_x\") - pl.col(\"acc_y\")).abs().alias(\"lateral_imbalance\"),\n        ])\n        .with_columns([\n            # Kinetic energy ratios (x/y/z contribution to total)\n            (pl.col(\"acc_x\")**2 / (pl.col(\"acc_energy\") + 1e-7)).alias(\"energy_ratio_x\"),\n            (pl.col(\"acc_y\")**2 / (pl.col(\"acc_energy\") + 1e-7)).alias(\"energy_ratio_y\"),\n            (pl.col(\"acc_z\")**2 / (pl.col(\"acc_energy\") + 1e-7)).alias(\"energy_ratio_z\"),\n            \n            # Rotational vs translational energy\n            (pl.col(\"rot_angle_vel\") / (pl.col(\"acc_mag\") + 1e-7)).alias(\"rotational_to_linear_ratio\"),\n        ])\n        .with_columns([\n            # Directional jerk consistency\n            (pl.col(\"acc_x_jerk\").sign() * pl.col(\"acc_y_jerk\").sign()).alias(\"jerk_direction_agreement_xy\"),\n            \n            # Jerk magnitude ratios\n            (pl.col(\"acc_x_jerk\").abs() / (pl.col(\"acc_mag_jerk\") + 1e-7)).alias(\"jerk_ratio_x\"),\n        ])        \n        # --- Physics-inspired simple features ---\n        .with_columns([\n            # Directional interaction features\n            (pl.col(\"acc_x\") * pl.col(\"acc_y\")).alias(\"acc_xy_interaction\"),\n            (pl.col(\"acc_x\") * pl.col(\"acc_z\")).alias(\"acc_xz_interaction\"),\n            \n            # Vertical vs horizontal dominance\n            (pl.col(\"acc_z\") / (pl.col(\"acc_x\").abs() + pl.col(\"acc_y\").abs() + 1e-7)).alias(\"vertical_dominance\"),\n            \n            # Directional balance\n            (pl.col(\"acc_x\") - pl.col(\"acc_y\")).abs().alias(\"lateral_imbalance\"),\n            \n            # Energy ratios\n            (pl.col(\"acc_x\")**2 / (pl.col(\"acc_energy\") + 1e-7)).alias(\"energy_ratio_x\"),\n            (pl.col(\"acc_y\")**2 / (pl.col(\"acc_energy\") + 1e-7)).alias(\"energy_ratio_y\"),\n            (pl.col(\"acc_z\")**2 / (pl.col(\"acc_energy\") + 1e-7)).alias(\"energy_ratio_z\"),\n            \n            # Rotational vs translational energy\n            (pl.col(\"rot_angle_vel\") / (pl.col(\"acc_mag\") + 1e-7)).alias(\"rotational_to_linear_ratio\"),\n            \n            # Jerk features\n            (pl.col(\"acc_x_jerk\").sign() * pl.col(\"acc_y_jerk\").sign()).alias(\"jerk_direction_agreement_xy\"),\n            (pl.col(\"acc_x_jerk\").abs() / (pl.col(\"acc_mag_jerk\") + 1e-7)).alias(\"jerk_ratio_x\"),\n            \n            # Motion dynamics\n            (pl.col(\"acc_mag\") / (pl.col(\"acc_mag_jerk\").abs() + 1e-7)).alias(\"motion_smoothness\"),\n        ])     \n        .with_columns([\n            # Additive combinations\n            (pl.col(\"acc_x\") + pl.col(\"acc_y\")).alias(\"acc_xy_sum\"),\n            (pl.col(\"acc_y\") + pl.col(\"acc_z\")).alias(\"acc_yz_sum\"), \n            (pl.col(\"acc_x\") + pl.col(\"acc_z\")).alias(\"acc_xz_sum\"),\n            \n            # Subtractive combinations\n            (pl.col(\"acc_x\") - pl.col(\"acc_y\")).alias(\"acc_xy_diff\"),\n            (pl.col(\"acc_y\") - pl.col(\"acc_z\")).alias(\"acc_yz_diff\"),\n            (pl.col(\"acc_x\") - pl.col(\"acc_z\")).alias(\"acc_xz_diff\"),\n            \n            # Triple-axis interactions\n            (pl.col(\"acc_x\") + pl.col(\"acc_y\") - pl.col(\"acc_z\")).alias(\"acc_xy_z_net\"),\n            (pl.col(\"acc_y\") + pl.col(\"acc_z\") - pl.col(\"acc_x\")).alias(\"acc_yz_x_net\"),\n            (pl.col(\"acc_x\") + pl.col(\"acc_z\") - pl.col(\"acc_y\")).alias(\"acc_xz_y_net\"),\n\n            ############################\n            (pl.col(\"rot_x\") + pl.col(\"rot_y\")).alias(\"rot_xy_sum\"),\n            (pl.col(\"rot_y\") + pl.col(\"rot_z\")).alias(\"rot_yz_sum\"), \n            (pl.col(\"rot_x\") + pl.col(\"rot_z\")).alias(\"rot_xz_sum\"),\n            (pl.col(\"rot_x\") + pl.col(\"rot_w\")).alias(\"rot_xw_sum\"),\n\t\t\t(pl.col(\"rot_y\") + pl.col(\"rot_w\")).alias(\"rot_yw_sum\"),\n\t\t\t(pl.col(\"rot_z\") + pl.col(\"rot_w\")).alias(\"rot_zw_sum\"),\n            # Subtractive combinations\n            (pl.col(\"rot_x\") - pl.col(\"rot_y\")).alias(\"rot_xy_diff\"),\n            (pl.col(\"rot_y\") - pl.col(\"rot_z\")).alias(\"rot_yz_diff\"),\n            (pl.col(\"rot_x\") - pl.col(\"rot_z\")).alias(\"rot_xz_diff\"),\n\t\t\t\n            (pl.col(\"rot_x\") - pl.col(\"rot_w\")).alias(\"rot_xw_diff\"),\n            (pl.col(\"rot_y\") - pl.col(\"rot_w\")).alias(\"rot_yw_diff\"),\n            (pl.col(\"rot_z\") - pl.col(\"rot_w\")).alias(\"rot_zw_diff\"),\t\t\t\n\n            #########################NEW FEATURES########################################################\n            # Triple-axis interactions\n            (pl.col(\"rot_x\") + pl.col(\"rot_y\") - pl.col(\"rot_z\")).alias(\"rot_xy_z_net\"),\n            (pl.col(\"rot_y\") + pl.col(\"rot_z\") - pl.col(\"rot_x\")).alias(\"rot_yz_x_net\"),\n            (pl.col(\"rot_x\") + pl.col(\"rot_z\") - pl.col(\"rot_y\")).alias(\"rot_xz_y_net\"), \n\t\t\t\n            (pl.col(\"rot_x\") + pl.col(\"rot_w\") - pl.col(\"rot_z\")).alias(\"rot_xw_z_net\"),\n            (pl.col(\"rot_y\") + pl.col(\"rot_w\") - pl.col(\"rot_x\")).alias(\"rot_yw_x_net\"),\n            (pl.col(\"rot_x\") + pl.col(\"rot_w\") - pl.col(\"rot_y\")).alias(\"rot_xw_y_net\"),      \n\n            (pl.col(\"rot_x\") * pl.col(\"rot_w\") - pl.col(\"rot_z\")).alias(\"rot_xw_z_net_ms\"),\n            (pl.col(\"rot_y\") * pl.col(\"rot_w\") - pl.col(\"rot_x\")).alias(\"rot_yw_x_net_ms\"),\n            (pl.col(\"rot_x\") * pl.col(\"rot_w\") - pl.col(\"rot_y\")).alias(\"rot_xw_y_net_ms\"), \n\n            (pl.col(\"rot_x\") * pl.col(\"rot_y\") - pl.col(\"rot_z\")).alias(\"rot_xy_z_net_ms\"),\n            (pl.col(\"rot_y\") * pl.col(\"rot_z\") - pl.col(\"rot_x\")).alias(\"rot_yz_x_net_ms\"),\n            (pl.col(\"rot_z\") * pl.col(\"rot_w\") - pl.col(\"rot_y\")).alias(\"rot_zw_y_net_ms\"),   \n\n            (pl.col(\"rot_x\") / pl.col(\"rot_w\") - pl.col(\"rot_z\")).alias(\"rot_xw_z_net_md\"),\n            (pl.col(\"rot_y\") / pl.col(\"rot_w\") - pl.col(\"rot_x\")).alias(\"rot_yw_x_net_md\"),\n            (pl.col(\"rot_x\") / pl.col(\"rot_w\") - pl.col(\"rot_y\")).alias(\"rot_xw_y_net_md\"), \n\n            (pl.col(\"rot_x\") / pl.col(\"rot_y\") - pl.col(\"rot_z\")).alias(\"rot_xy_z_net_md\"),\n            (pl.col(\"rot_y\") / pl.col(\"rot_z\") - pl.col(\"rot_x\")).alias(\"rot_yz_x_net_md\"),\n            (pl.col(\"rot_z\") / pl.col(\"rot_w\") - pl.col(\"rot_y\")).alias(\"rot_zw_y_net_md\"), \n\n            (pl.col(\"rot_x\") * pl.col(\"rot_y\") + pl.col(\"rot_z\") * pl.col(\"rot_w\")).alias(\"rot_xy_plus_zw\"),\n            (pl.col(\"rot_x\") * pl.col(\"rot_z\") + pl.col(\"rot_y\") * pl.col(\"rot_w\")).alias(\"rot_xz_plus_yw\"),\n            (pl.col(\"rot_x\") * pl.col(\"rot_w\") + pl.col(\"rot_y\") * pl.col(\"rot_z\")).alias(\"rot_xw_plus_yz\"),\n            ((pl.col(\"rot_x\") + pl.col(\"rot_y\")) / (pl.col(\"rot_z\") + pl.col(\"rot_w\") + 1e-6)).alias(\"rot_xy_over_zw\"),\n            ((pl.col(\"rot_x\") + pl.col(\"rot_z\")) / (pl.col(\"rot_y\") + pl.col(\"rot_w\") + 1e-6)).alias(\"rot_xz_over_yw\"),\n            ((pl.col(\"rot_x\") + pl.col(\"rot_w\")) / (pl.col(\"rot_y\") + pl.col(\"rot_z\") + 1e-6)).alias(\"rot_xw_over_yz\"),\n\n            (pl.col(\"rot_x\")**2 + pl.col(\"rot_y\")**2 + pl.col(\"rot_z\")**2).sqrt().alias(\"rot_xyz_magnitude\"),\n            (pl.col(\"rot_x\")**2 + pl.col(\"rot_y\")**2 + pl.col(\"rot_w\")**2).sqrt().alias(\"rot_xyw_magnitude\"),\n            (pl.col(\"rot_x\")**2 + pl.col(\"rot_z\")**2 + pl.col(\"rot_w\")**2).sqrt().alias(\"rot_xzw_magnitude\"),\n            (pl.col(\"rot_y\")**2 + pl.col(\"rot_z\")**2 + pl.col(\"rot_w\")**2).sqrt().alias(\"rot_yzw_magnitude\"),\n            \n            (pl.col(\"rot_x\")**2 + pl.col(\"rot_y\")**2 + pl.col(\"rot_z\")**2 + pl.col(\"rot_w\")**2).sqrt().alias(\"rot_full_magnitude\"),\n\n            (pl.col(\"rot_x\")*pl.col(\"rot_y\") + pl.col(\"rot_y\")*pl.col(\"rot_z\") + pl.col(\"rot_z\")*pl.col(\"rot_x\")).alias(\"rot_vec_dot_products\"),\n            \n            # Scalar-vector interactions\n            (pl.col(\"rot_w\") * (pl.col(\"rot_x\") + pl.col(\"rot_y\") + pl.col(\"rot_z\"))).alias(\"rot_w_times_vec_sum\"),\n            (pl.col(\"rot_w\") * (pl.col(\"rot_x\")**2 + pl.col(\"rot_y\")**2 + pl.col(\"rot_z\")**2)).alias(\"rot_w_times_vec_mag_sq\"),  \n\n            (pl.col(\"rot_w\")**2 - (pl.col(\"rot_x\")**2 + pl.col(\"rot_y\")**2 + pl.col(\"rot_z\")**2)).alias(\"rot_scalar_minus_vector\"),\n            \n            # Normalization check\n            (pl.col(\"rot_x\")**2 + pl.col(\"rot_y\")**2 + pl.col(\"rot_z\")**2 + pl.col(\"rot_w\")**2 - 1).abs().alias(\"rot_normalization_error\"),  \n\n            (pl.col(\"rot_x\").abs().log1p() * pl.col(\"rot_x\").sign()).alias(\"rot_x_log_scaled\"),\n            (pl.col(\"rot_y\").abs().log1p() * pl.col(\"rot_y\").sign()).alias(\"rot_y_log_scaled\"),\n            (pl.col(\"rot_z\").abs().log1p() * pl.col(\"rot_z\").sign()).alias(\"rot_z_log_scaled\"),\n            (pl.col(\"rot_w\").abs().log1p() * pl.col(\"rot_w\").sign()).alias(\"rot_w_log_scaled\"),\n            \n            # Exponential features\n            (pl.col(\"rot_x\").exp()).alias(\"rot_x_exp\"),\n            (pl.col(\"rot_y\").exp()).alias(\"rot_y_exp\"),\n            (pl.col(\"rot_z\").exp()).alias(\"rot_z_exp\"),\n            (pl.col(\"rot_w\").exp()).alias(\"rot_w_exp\"),             \n        ])\n        \n        # --- Directional Ratio Features ---\n        .with_columns([\n            # Axis dominance ratios\n            (pl.col(\"acc_x\") / (pl.col(\"acc_y\").abs() + 1e-7)).alias(\"acc_x_over_y\"),\n            (pl.col(\"acc_y\") / (pl.col(\"acc_z\").abs() + 1e-7)).alias(\"acc_y_over_z\"),\n            (pl.col(\"acc_x\") / (pl.col(\"acc_z\").abs() + 1e-7)).alias(\"acc_x_over_z\"),\n            \n            # Signed direction ratios\n            (pl.col(\"acc_x\").sign() * (pl.col(\"acc_x\").abs() / (pl.col(\"acc_mag\") + 1e-7))).alias(\"acc_x_direction\"),\n            (pl.col(\"acc_y\").sign() * (pl.col(\"acc_y\").abs() / (pl.col(\"acc_mag\") + 1e-7))).alias(\"acc_y_direction\"),\n            (pl.col(\"acc_z\").sign() * (pl.col(\"acc_z\").abs() / (pl.col(\"acc_mag\") + 1e-7))).alias(\"acc_z_direction\"),\n        ])\n        \n        # --- Rotation-Translation Coupling ---\n        .with_columns([\n            # Rotation-acceleration coupling\n            (pl.col(\"rot_x\") * pl.col(\"acc_x\")).alias(\"rot_x_acc_x_coupling\"),\n            (pl.col(\"rot_y\") * pl.col(\"acc_y\")).alias(\"rot_y_acc_y_coupling\"),\n            (pl.col(\"rot_z\") * pl.col(\"acc_z\")).alias(\"rot_z_acc_z_coupling\"),\n            \n            # Cross-axis rotation effects\n            (pl.col(\"rot_x\") * pl.col(\"acc_y\")).alias(\"rot_x_acc_y_coupling\"),\n            (pl.col(\"rot_y\") * pl.col(\"acc_z\")).alias(\"rot_y_acc_z_coupling\"),\n        ])\n\n        #$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$AUG 12 New features$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n        .with_columns([\n        (pl.col(\"rot_y\") * pl.col(\"acc_z\") - pl.col(\"rot_z\") * pl.col(\"acc_y\")).alias(\"cross_rot_acc_x\"),\n        (pl.col(\"rot_z\") * pl.col(\"acc_x\") - pl.col(\"rot_x\") * pl.col(\"acc_z\")).alias(\"cross_rot_acc_y\"),\n        (pl.col(\"rot_x\") * pl.col(\"acc_y\") - pl.col(\"rot_y\") * pl.col(\"acc_x\")).alias(\"cross_rot_acc_z\"),\n\n        # Additive combinations\n        (pl.col(\"rot_x\") + pl.col(\"rot_y\") + pl.col(\"acc_x\")).alias(\"sum_rotxy_accx\"),\n        (pl.col(\"rot_y\") + pl.col(\"rot_z\") + pl.col(\"acc_y\")).alias(\"sum_rotyz_accy\"),\n        (pl.col(\"rot_z\") + pl.col(\"rot_x\") + pl.col(\"acc_z\")).alias(\"sum_rotzx_accz\"),\n        \n        # Mixed addition/subtraction\n        (pl.col(\"rot_x\") + pl.col(\"acc_y\") - pl.col(\"rot_z\")).alias(\"rotx_accy_minus_rotz\"),\n        (pl.col(\"rot_y\") + pl.col(\"acc_z\") - pl.col(\"rot_x\")).alias(\"roty_accz_minus_rotx\"),\n        (pl.col(\"rot_z\") + pl.col(\"acc_x\") - pl.col(\"rot_y\")).alias(\"rotz_accx_minus_roty\"), \n\n        # --- New: Multiplicative Combinations ---\n        (pl.col(\"rot_x\") * pl.col(\"rot_y\") + pl.col(\"acc_z\")).alias(\"rotxy_plus_accz\"),\n        (pl.col(\"rot_y\") * pl.col(\"rot_z\") - pl.col(\"acc_x\")).alias(\"rotyz_minus_accx\"),\n        (pl.col(\"rot_z\") * pl.col(\"rot_x\") + pl.col(\"acc_y\")).alias(\"rotzx_plus_accy\"),\n        \n        # --- New: Cross-Axis Energy Terms ---\n        (pl.col(\"rot_x\")**2 + pl.col(\"acc_y\")**2).alias(\"rotx2_accy2\"),\n        (pl.col(\"rot_y\")**2 + pl.col(\"acc_z\")**2).alias(\"roty2_accz2\"),\n        (pl.col(\"rot_z\")**2 + pl.col(\"acc_x\")**2).alias(\"rotz2_accx2\"),  \n\n        # --- New: Coupled Jerk Features ---\n        (pl.col(\"rot_x\").diff() + pl.col(\"acc_y\").diff() - pl.col(\"rot_z\").diff()).alias(\"diff_rotx_accy_minus_rotz\"),\n        (pl.col(\"rot_y\").diff() + pl.col(\"acc_z\").diff() - pl.col(\"rot_x\").diff()).alias(\"diff_roty_accz_minus_rotx\"),\n        \n        # --- New: Triple Product Features ---\n        (pl.col(\"rot_x\") * pl.col(\"rot_y\") * pl.col(\"acc_z\")).alias(\"triple_rotxy_accz\"),\n        (pl.col(\"rot_y\") * pl.col(\"rot_z\") * pl.col(\"acc_x\")).alias(\"triple_rotyz_accx\"),\n        (pl.col(\"rot_z\") * pl.col(\"rot_x\") * pl.col(\"acc_y\")).alias(\"triple_rotzx_accy\")])\n    )\n    return base_features \n\nimport polars as pl\nimport numpy as np\nfrom scipy.spatial.transform import Rotation as R\n\ndef compute_roll_pitch_yaw(rot_x, rot_y, rot_z, rot_w):\n    quats = np.stack([rot_x, rot_y, rot_z, rot_w], axis=1)\n    eulers = R.from_quat(quats).as_euler('xyz', degrees=False)\n    return eulers[:, 0], eulers[:, 1], eulers[:, 2]\n\ndef create_advanced_imu_features(df: pl.DataFrame) -> pl.DataFrame:\n    # imu_prefixes = ['acc','rot','linear','angular','freq','quat','coriolis','peak','centripetal','harmonic','dtw','jerk','phase','norm','kinetic','signed',\n    # 'energy','phase','dynamic','norm','triple','diff','rotx2','rotxy','rotz','roty','rotx','rotyz','rotzx','sum','cross','pitch','linear',\n    # 'x_acc','y_acc','z_acc','acc_sum','acc_xy','acc_yz','acc_xz','2acc','alt','normed','thm_','tof_']\n    # imu_cols = [c for c in df.columns if any(c.startswith(f\"{p}_\") for p in imu_prefixes)]\n    non_rows =[ 'row_id',\n     'sequence_type',\n     'sequence_id',\n     'sequence_counter',\n     'subject',\n     'orientation',\n     'behavior',\n     'phase',\n     'gesture']\n    imu_cols = [i for i in df.columns if i not in non_rows]\n    # print(len(imu_cols))\n    # === Add vector magnitude and dot products ===\n    df = df.with_columns([\n        # (pl.col('acc_x')**2 + pl.col('acc_y')**2 + pl.col('acc_z')**2).sqrt().alias('acc_magnitude'),\n        # (pl.col('rot_x')**2 + pl.col('rot_y')**2 + pl.col('rot_z')**2).sqrt().alias('rot_magnitude'),\n        (pl.col('acc_x') * pl.col('rot_x') +\n         pl.col('acc_y') * pl.col('rot_y') +\n         pl.col('acc_z') * pl.col('rot_z')).alias('dot_acc_rot'),\n    ])\n\n    # Append new vector-based feature columns to imu_cols (only if they aren't already there) 'euler_roll', 'euler_pitch', 'euler_yaw' 'acc_magnitude' 'rot_magnitude',\n    vector_features = [ 'dot_acc_rot']\n    imu_cols = list(set(imu_cols + vector_features))  # avoid duplicates\n\n    # === Aggregation expressions ===\n    stats_exprs = []\n    for col in imu_cols:\n        stats_exprs.extend([\n            pl.col(col).mean().alias(f\"{col}_mean\"),\n            pl.col(col).std().alias(f\"{col}_std\"),\n            pl.col(col).min().alias(f\"{col}_min\"),\n            pl.col(col).max().alias(f\"{col}_max\"),\n            pl.col(col).median().alias(f\"{col}_median\"),\n            (pl.col(col).max() - pl.col(col).min()).alias(f\"{col}_range\"),\n            pl.col(col).quantile(0.25).alias(f\"{col}_q25\"),\n            pl.col(col).quantile(0.75).alias(f\"{col}_q75\"),\n            (pl.col(col).quantile(0.75) - pl.col(col).quantile(0.25)).alias(f\"{col}_iqr\"),\n            (pl.col(col) - pl.col(col).mean()).abs().mean().alias(f\"{col}_mad\"),\n            pl.col(col).abs().mean().alias(f\"{col}_mean_abs\"),\n            (pl.col(col)**2).mean().sqrt().alias(f\"{col}_rms\"),\n            (pl.col(col)**2).sum().alias(f\"{col}_energy\"),\n            pl.col(col).skew().alias(f\"{col}_skew\"),\n            pl.col(col).kurtosis().alias(f\"{col}_kurtosis\"),\n            ((pl.col(col).shift(1) * pl.col(col)) < 0).sum().alias(f\"{col}_zero_crossings\"),\n        ])\n\n        for n in range(1,3):\n            diff_expr = pl.col(col).diff(n)\n            stats_exprs.extend([\n                diff_expr.mean().alias(f\"{col}_diff{n}_mean\"),\n                diff_expr.std().alias(f\"{col}_diff{n}_std\"),\n                diff_expr.median().alias(f\"{col}_diff{n}_median\"),\n                diff_expr.quantile(0.25).alias(f\"{col}_diff{n}_q25\"),\n                diff_expr.quantile(0.75).alias(f\"{col}_diff{n}_q75\"),\n                (diff_expr.quantile(0.75) - diff_expr.quantile(0.25)).alias(f\"{col}_diff{n}_iqr\"),\n                (diff_expr**2).mean().sqrt().alias(f\"{col}_diff{n}_rms\"),\n                diff_expr.abs().mean().alias(f\"{col}_diff{n}_mad\"),\n            ])      \n                          \n\n    identity_exprs = [\n        pl.col('subject').first().alias('subject'),\n        # pl.col('gesture').first().alias('gesture'),\n        # pl.col('phase').first().alias('phase'),\n    ]\n\n    df_main = df.group_by('sequence_id').agg(identity_exprs + stats_exprs)\n\n    # === Phase-aware features ===\n    df = df.with_columns([\n        (pl.col('sequence_counter') / pl.col('sequence_counter').max().over('sequence_id')).alias('relative_pos')\n    ])\n\n    def make_phase_expr(col, phase_mask, name):\n        return [\n            pl.when(phase_mask).then(pl.col(col)).otherwise(None).mean().alias(f\"{col}_mean_{name}\"),\n            pl.when(phase_mask).then(pl.col(col)).otherwise(None).std().alias(f\"{col}_std_{name}\"),\n\n            pl.when(phase_mask).then(pl.col(col)).otherwise(None).median().alias(f\"{col}_median_expr_{name}\"),\n            pl.when(phase_mask).then(pl.col(col)).otherwise(None).quantile(0.25).alias(f\"{col}_q25_expr_{name}\"),\n            pl.when(phase_mask).then(pl.col(col)).otherwise(None).quantile(0.5).alias(f\"{col}_q50_expr_{name}\"),\n            pl.when(phase_mask).then(pl.col(col)).otherwise(None).quantile(0.75).alias(f\"{col}_q75_expr_{name}\"),            \n            \n        ]\n\n    phase_exprs = []\n    for col in imu_cols:\n        phase_exprs += make_phase_expr(col, pl.col(\"relative_pos\") < 0.3, \"first_30pct\")\n        phase_exprs += make_phase_expr(col, (pl.col(\"relative_pos\") >= 0.3) & (pl.col(\"relative_pos\") < 0.7), \"middle_40pct\")\n        phase_exprs += make_phase_expr(col, pl.col(\"relative_pos\") >= 0.7, \"last_30pct\")\n\n    df_phase = df.group_by(\"sequence_id\").agg(phase_exprs)\n\n    # === Final merge ===\n    df_final = df_main.join(df_phase, on=\"sequence_id\", how=\"left\").fill_null(0)\n\n    return df_final\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-20T05:21:01.736285Z","iopub.execute_input":"2025-08-20T05:21:01.736817Z","iopub.status.idle":"2025-08-20T05:21:01.822293Z","shell.execute_reply.started":"2025-08-20T05:21:01.736788Z","shell.execute_reply":"2025-08-20T05:21:01.821202Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def final_feature_creation(df):\n    feature_df = feature_engineering_polars(df)\n    final_df = create_advanced_imu_features(feature_df)\n    return final_df.to_pandas()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-20T05:21:01.823189Z","iopub.execute_input":"2025-08-20T05:21:01.823476Z","iopub.status.idle":"2025-08-20T05:21:01.851295Z","shell.execute_reply.started":"2025-08-20T05:21:01.823429Z","shell.execute_reply":"2025-08-20T05:21:01.850399Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"le = joblib.load(f'/kaggle/input/ensemaple-imu-models/ensemaple_allmodel_encoder.pkl')\nfeature = json.load(open(r'/kaggle/input/ensemaple-imu-models/ensemaple_allmodel_features.json'))\nfeature_all = json.load(open(r'/kaggle/input/cat-all-features/ensemaple_allmodel_features.json'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-20T05:21:01.853380Z","iopub.execute_input":"2025-08-20T05:21:01.854019Z","iopub.status.idle":"2025-08-20T05:21:01.890862Z","shell.execute_reply.started":"2025-08-20T05:21:01.853984Z","shell.execute_reply":"2025-08-20T05:21:01.889976Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_cat1 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_cat_fold_1.pkl')\nmodel_cat2 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_cat_fold_2.pkl')\nmodel_cat3 = joblib.load(f'//kaggle/input/ensemaple-imu-models/model_cat_fold_3.pkl')\nmodel_cat4 = joblib.load(f'//kaggle/input/ensemaple-imu-models/model_cat_fold_4.pkl')\nmodel_cat5 = joblib.load(f'//kaggle/input/ensemaple-imu-models/model_cat_fold_5.pkl')\n\nmodel_xgb1 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_xgb_fold_1.pkl')\nmodel_xgb2 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_xgb_fold_2.pkl')\nmodel_xgb3 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_xgb_fold_3.pkl')\nmodel_xgb4 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_xgb_fold_4.pkl')\nmodel_xgb5 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_xgb_fold_5.pkl')\n\nmodel_lgb1 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_lgb_fold_1.pkl')\nmodel_lgb2 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_lgb_fold_2.pkl')\nmodel_lgb3 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_lgb_fold_3.pkl')\nmodel_lgb4 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_lgb_fold_4.pkl')\nmodel_lgb5 = joblib.load(f'/kaggle/input/ensemaple-imu-models/model_lgb_fold_5.pkl')\n\nmodel_cat1_full = joblib.load(f'/kaggle/input/cat-full-data/model_cat_fold_1.pkl')\nmodel_cat2_full = joblib.load(f'/kaggle/input/cat-full-data/model_cat_fold_2.pkl')\nmodel_cat3_full = joblib.load(f'/kaggle/input/cat-full-data/model_cat_fold_3.pkl')\nmodel_cat4_full = joblib.load(f'/kaggle/input/cat-full-data/model_cat_fold_4.pkl')\nmodel_cat5_full = joblib.load(f'/kaggle/input/cat-full-data/model_cat_fold_5.pkl')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-20T05:21:01.891675Z","iopub.execute_input":"2025-08-20T05:21:01.891891Z","iopub.status.idle":"2025-08-20T05:21:16.577066Z","shell.execute_reply.started":"2025-08-20T05:21:01.891874Z","shell.execute_reply":"2025-08-20T05:21:16.576115Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:  \n    demographics = demographics.to_pandas()\n    final_df = final_feature_creation(sequence)\n    final_df = final_df.merge(demographics, on = 'subject', how = 'left')\n    predictions1 = 0\n    predictions2 = 0\n    predictions3 = 0\n    predictions4 = 0\n    predictions5 = 0\n\n    predictions6 = 0\n    predictions7 = 0\n    predictions8 = 0\n    predictions9 = 0\n    predictions10 = 0   \n\n    predictions11 = 0\n    predictions12 = 0\n    predictions13 = 0\n    predictions14 = 0\n    predictions15 = 0       \n\n    tof_cols = [c for c in sequence.columns if c.startswith(\"tof_\")]\n    is_imu_only = (\n        sequence.select(pl.all_horizontal([pl.col(c).is_null() for c in tof_cols]))\n        .select(pl.col(\"*\").all())\n        .item()\n    )\n    if not is_imu_only:\n        # print(\"Ereerer\")\n        predictions1 += model_cat1_full.predict_proba(\n            final_df[feature_all['features']]\n        )\n        predictions2 += model_cat2_full.predict_proba(\n            final_df[feature_all['features']]\n        )\n        predictions3 += model_cat3_full.predict_proba(\n            final_df[feature_all['features']]\n        )\n        predictions4 += model_cat4_full.predict_proba(\n            final_df[feature_all['features']]\n        )\n        predictions5 += model_cat5_full.predict_proba(\n            final_df[feature_all['features']]\n        )      \n        predictions = (predictions1 + predictions2 + predictions3 + predictions4 + predictions5) / 5\n       \n    else:\n        \n        predictions1 += model_cat1.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions2 += model_cat2.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions3 += model_cat3.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions4 += model_cat4.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions5 += model_cat5.predict_proba(\n            final_df[feature['features']]\n        )        \n    \n        predictions6 += model_xgb1.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions7 += model_xgb2.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions8 += model_xgb3.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions9 += model_xgb4.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions10 += model_xgb5.predict_proba(\n            final_df[feature['features']]\n        )    \n    \n        predictions11 += model_lgb1.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions12 += model_lgb2.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions13 += model_lgb3.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions14 += model_lgb4.predict_proba(\n            final_df[feature['features']]\n        )\n        predictions15 += model_lgb5.predict_proba(\n            final_df[feature['features']]\n        )      \n\n        predictions = 0.7*(predictions1 + predictions2 + predictions3 + predictions4 + predictions5) + (predictions6 + predictions7 + predictions8 + predictions9 + predictions10)*0.2 + (predictions11 + predictions12 + predictions13+ predictions14+predictions15)*0.1\n    argmax_indices = np.argmax(predictions, axis=1)\n    predictions = le.inverse_transform(argmax_indices)\n    # print(predictions)\n    return predictions[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-20T05:21:16.578379Z","iopub.execute_input":"2025-08-20T05:21:16.579003Z","iopub.status.idle":"2025-08-20T05:21:16.590262Z","shell.execute_reply.started":"2025-08-20T05:21:16.578979Z","shell.execute_reply":"2025-08-20T05:21:16.589274Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"inference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n\nif os.getenv('KAGGLE_IS_COMPETITION_RERUN'):\n    inference_server.serve()\nelse:\n    inference_server.run_local_gateway(\n        data_paths=(\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv',\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv',\n        )\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-20T05:21:16.591199Z","iopub.execute_input":"2025-08-20T05:21:16.591527Z","iopub.status.idle":"2025-08-20T05:21:32.027088Z","shell.execute_reply.started":"2025-08-20T05:21:16.591483Z","shell.execute_reply":"2025-08-20T05:21:32.026251Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}