{"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"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"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!pip install pykalman\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nfrom pykalman import KalmanFilter\nfrom scipy.spatial.transform import Rotation as R\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d import Axes3D\nimport seaborn as sns\nfrom matplotlib import animation\nfrom IPython.display import HTML\nimport warnings\nfrom matplotlib.animation import FuncAnimation\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-08T08:11:20.547503Z","iopub.execute_input":"2025-08-08T08:11:20.547845Z","iopub.status.idle":"2025-08-08T08:11:24.863194Z","shell.execute_reply.started":"2025-08-08T08:11:20.547810Z","shell.execute_reply":"2025-08-08T08:11:24.862141Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 1. Data Prep.","metadata":{}},{"cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv\")\ndf_subjects=pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train_demographics.csv\")\ngrouped = df.groupby(\"sequence_id\")\nprint(df[\"sequence_id\"].unique())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-08T08:12:23.819442Z","iopub.execute_input":"2025-08-08T08:12:23.819900Z","iopub.status.idle":"2025-08-08T08:12:47.968405Z","shell.execute_reply.started":"2025-08-08T08:12:23.819873Z","shell.execute_reply":"2025-08-08T08:12:47.967286Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def apply_kalman_filter_to_sequence(seq, columns):\n    seq_filtered = seq.copy()\n    \n    for col in columns:\n        data = seq_filtered[col].values\n        mask = np.isnan(data)\n\n        if mask.sum() == 0:\n            continue  # Eksik veri yoksa geç\n\n        # Kalman filtresi tanımı\n        kf = KalmanFilter(initial_state_mean=0, n_dim_obs=1)\n        data_filled = kf.em(data, n_iter=10).smooth(data)[0]\n        seq_filtered[col] = data_filled\n\n    return seq_filtered\n\ndef compute_gravity_vector_from_quaternion(qx, qy, qz, qw):\n    # Quaternion'dan gravity vektörü çıkarımı\n    gravity_x = 2 * (qx * qz - qw * qy)\n    gravity_y = 2 * (qw * qx + qy * qz)\n    gravity_z = qw**2 - qx**2 - qy**2 + qz**2\n    return np.array([gravity_x, gravity_y, gravity_z])\ndef remove_gravity_from_acceleration(seq):\n    acc_no_gravity = []\n\n    for _, row in seq.iterrows():\n        gravity = compute_gravity_vector_from_quaternion(\n            row[\"rot_x\"], row[\"rot_y\"],\n            row[\"rot_z\"], row[\"rot_w\"]\n        )\n        acc = np.array([row[\"acc_x\"], row[\"acc_y\"], row[\"acc_z\"]])\n        acc_corrected = acc - gravity\n        acc_no_gravity.append(acc_corrected)\n\n    acc_no_gravity = np.array(acc_no_gravity)\n    seq[\"acc_x_nograv\"] = acc_no_gravity[:, 0]\n    seq[\"acc_y_nograv\"] = acc_no_gravity[:, 1]\n    seq[\"acc_z_nograv\"] = acc_no_gravity[:, 2]\n    return seq\n\n\ndef remove_gravity_from_acceleration(seq):\n    acc = seq[[\"acc_x\", \"acc_y\", \"acc_z\"]].values\n    quat = seq[[\"rot_x\", \"rot_y\", \"rot_z\", \"rot_w\"]].values\n    rotation = R.from_quat(quat)\n\n    # Yerçekimi vektörü (dünya koordinatlarında [0, 0, -9.81])\n    gravity_world = np.array([9.81, 0, 0])\n    gravity_sensor = rotation.apply(gravity_world, inverse=True)\n\n    # Gerçek ivme = ölçülen ivme - yerçekimi\n    acc_corrected = acc - gravity_sensor\n    seq[\"acc_x_nograv\"], seq[\"acc_y_nograv\"], seq[\"acc_z_nograv\"] = acc_corrected.T\n    return seq\ndef estimate_position_xyz_from_seq(seq, dt=0.01):\n    # Gravity'den arındırılmış ivme verileri\n    acc_x = seq[\"acc_x_nograv\"].values\n    acc_y = seq[\"acc_y_nograv\"].values\n    acc_z = seq[\"acc_z_nograv\"].values\n\n    # Hız ve konum entegrasyonu\n    velocity_x = np.cumsum(acc_x * dt)\n    velocity_y = np.cumsum(acc_y * dt)\n    velocity_z = np.cumsum(acc_z * dt)\n\n    position_x = np.cumsum(velocity_x * dt)\n    position_y = np.cumsum(velocity_y * dt)\n    position_z = np.cumsum(velocity_z * dt)\n\n    return position_x, position_y, position_z\n\ndef animate_combined_sequence(seq, pixels, interval=100):\n    warnings.filterwarnings(\"ignore\")  \n\n    fig, axs = plt.subplots(1, 2, figsize=(12, 4))\n\n    def update(i):\n        axs[0].clear()\n        axs[1].clear()\n\n        # IMU ivme\n        axs[0].plot(seq[\"sequence_counter\"][:i], seq[\"acc_x\"][:i], label=\"acc_x\")\n        axs[0].plot(seq[\"sequence_counter\"][:i], seq[\"acc_y\"][:i], label=\"acc_y\")\n        axs[0].plot(seq[\"sequence_counter\"][:i], seq[\"acc_z\"][:i], label=\"acc_z\")\n        axs[0].legend(); axs[0].set_title(f\"IMU İvme (Frame {i})\")\n\n        # ToF grid\n        grid = np.array(seq.iloc[i][pixels].fillna(0).astype(float)).reshape(8, 8)\n        sns.heatmap(grid, cmap=\"viridis\", cbar=False, ax=axs[1])\n        axs[1].set_title(\"ToF Mesafe Heatmap\")\n\n    ani = animation.FuncAnimation(fig, update, frames=range(0, len(seq)), interval=interval)\n    return HTML(ani.to_jshtml())\ndef animate_trajectory_3d_kaggle(x_vals, y_vals, z_vals):\n    fig = plt.figure(figsize=(10, 8))\n    ax = fig.add_subplot(111, projection='3d')\n    ax.set_title(\"Sensor Trajectory (Gravity Removed)\", fontsize=14)\n    ax.set_xlabel(\"X Position\")\n    ax.set_ylabel(\"Y Position\")\n    ax.set_zlabel(\"Z Position\")\n\n    margin = 0.1\n    ax.set_xlim(min(x_vals) - margin, max(x_vals) + margin)\n    ax.set_ylim(min(y_vals) - margin, max(y_vals) + margin)\n    ax.set_zlim(min(z_vals) - margin, max(z_vals) + margin)\n\n    trajectory, = ax.plot([], [], [], lw=2, color='royalblue')\n    point = ax.scatter([], [], [], color='red', s=50)\n\n    def init():\n        trajectory.set_data([], [])\n        trajectory.set_3d_properties([])\n        point._offsets3d = ([], [], [])\n        return trajectory, point\n\n    def update(frame):\n        trajectory.set_data(x_vals[:frame], y_vals[:frame])\n        trajectory.set_3d_properties(z_vals[:frame])\n        point._offsets3d = ([x_vals[frame]], [y_vals[frame]], [z_vals[frame]])\n        return trajectory, point\n\n    ani = FuncAnimation(fig, update, frames=len(x_vals), init_func=init,\n                        interval=40, blit=False)\n\n    return HTML(ani.to_jshtml())\ndef extract_features_from_sequence(seq):\n    features = {}\n\n    # Quaternion → Euler dönüşümü\n    if all(col in seq.columns for col in [\"quat_w\", \"quat_x\", \"quat_y\", \"quat_z\"]):\n        quat = seq[[\"quat_w\", \"quat_x\", \"quat_y\", \"quat_z\"]].fillna(0).values\n        euler = R.from_quat(quat).as_euler(\"xyz\", degrees=False)\n        seq[\"euler_x\"], seq[\"euler_y\"], seq[\"euler_z\"] = euler.T\n\n        for axis in [\"euler_x\", \"euler_y\", \"euler_z\"]:\n            values = seq[axis].values\n            features[f\"{axis}_mean\"] = np.mean(values)\n            features[f\"{axis}_std\"] = np.std(values)\n            features[f\"{axis}_max\"] = np.max(values)\n            features[f\"{axis}_min\"] = np.min(values)\n            features[f\"{axis}_energy\"] = np.sum(values ** 2)\n\n    # Acceleration öznitelikleri\n    for col in [\"acc_x\", \"acc_y\", \"acc_z\"]:\n        if col in seq.columns:\n            values = seq[col].values\n            features[f\"{col}_mean\"] = np.mean(values)\n            features[f\"{col}_std\"] = np.std(values)\n            features[f\"{col}_max\"] = np.max(values)\n            features[f\"{col}_min\"] = np.min(values)\n            features[f\"{col}_energy\"] = np.sum(values ** 2)\n\n    # ToF öznitelikleri (örnek: tof_1 sensörü)\n    tof_cols = [f\"tof_1_v{i}\" for i in range(64) if f\"tof_1_v{i}\" in seq.columns]\n    if len(tof_cols) == 64:\n        tof_matrix = seq[tof_cols].fillna(0).astype(float).values\n        avg_grid = np.mean(tof_matrix, axis=0).reshape(8, 8)\n        features[\"tof_mean_center\"] = avg_grid[3:5, 3:5].mean()\n        features[\"tof_entropy\"] = -np.sum((avg_grid / avg_grid.sum()) * np.log1p(avg_grid / avg_grid.sum()))\n\n    # Hareket süresi\n    if \"sequence_counter\" in seq.columns:\n        features[\"duration\"] = seq[\"sequence_counter\"].max() - seq[\"sequence_counter\"].min()\n\n    return pd.Series(features)\n\n\ndef apply_kalman_filter_to_sequence(seq, columns):\n    seq_filtered = seq.copy()\n    for col in columns:\n        if col in seq.columns:\n            values = seq[col].values\n            mask = np.isnan(values)\n            if np.all(mask):  # tamamen eksikse atla\n                continue\n            kf = KalmanFilter(initial_state_mean=0, n_dim_obs=1)\n            values_filled = values.copy()\n            values_filled[mask] = 0  # NaN'leri geçici olarak sıfırla\n            filtered_state_means, _ = kf.smooth(values_filled.reshape(-1, 1))\n            seq_filtered[col] = filtered_state_means.ravel()\n    return seq_filtered\nimu_cols = [\"acc_x\", \"acc_y\", \"acc_z\", \"rot_w\", \"rot_x\", \"rot_y\", \"rot_z\"]\ntof_cols = [f\"tof_1_v{i}\" for i in range(64)]\n\ndef preprocess_sequence(seq):\n    cols_to_filter = [col for col in imu_cols + tof_cols if col in seq.columns]\n    return apply_kalman_filter_to_sequence(seq, cols_to_filter)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-08T08:49:28.488632Z","iopub.execute_input":"2025-08-08T08:49:28.489022Z","iopub.status.idle":"2025-08-08T08:49:28.702647Z","shell.execute_reply.started":"2025-08-08T08:49:28.489000Z","shell.execute_reply":"2025-08-08T08:49:28.701132Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 2. IMU Data Exploration\n## A. Acc/time series","metadata":{}},{"cell_type":"code","source":"\nvalid_id = df[\"sequence_id\"].unique()[0]  # first seq.\nseq = grouped.get_group(valid_id)\n\nplt.plot(seq[\"sequence_counter\"], seq[\"acc_x\"], label=\"acc_x\")\nplt.plot(seq[\"sequence_counter\"], seq[\"acc_y\"], label=\"acc_y\")\nplt.plot(seq[\"sequence_counter\"], seq[\"acc_z\"], label=\"acc_z\")\nplt.legend(); plt.title(\"Acc/time series\")\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-08T08:16:41.675415Z","iopub.execute_input":"2025-08-08T08:16:41.675745Z","iopub.status.idle":"2025-08-08T08:16:41.942069Z","shell.execute_reply.started":"2025-08-08T08:16:41.675724Z","shell.execute_reply":"2025-08-08T08:16:41.940897Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## B. Quaternion → Euler  ","metadata":{}},{"cell_type":"code","source":"\n\nrot = R.from_quat(seq[[\"rot_x\", \"rot_y\", \"rot_z\", \"rot_w\"]])\neuler = rot.as_euler(\"xyz\", degrees=True)\nplt.plot(seq[\"sequence_counter\"], euler[:, 0], label=\"Roll\")\nplt.plot(seq[\"sequence_counter\"], euler[:, 1], label=\"Pitch\")\nplt.plot(seq[\"sequence_counter\"], euler[:, 2], label=\"Yaw\")\nplt.legend(); plt.title(\"IMU Rotations (Euler)\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-08T08:16:45.708581Z","iopub.execute_input":"2025-08-08T08:16:45.708912Z","iopub.status.idle":"2025-08-08T08:16:45.963121Z","shell.execute_reply.started":"2025-08-08T08:16:45.708887Z","shell.execute_reply":"2025-08-08T08:16:45.961960Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"warnings.filterwarnings(\"ignore\")\n\n\nvalid_id = np.random.choice(df[\"sequence_id\"].unique())\n\n\nseq = df[df[\"sequence_id\"] == valid_id]\nseq = remove_gravity_from_acceleration(seq)\nx_vals, y_vals, z_vals = estimate_position_xyz_from_seq(seq)\nanimate_trajectory_3d_kaggle(x_vals, y_vals, z_vals)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-08T08:49:41.317452Z","iopub.execute_input":"2025-08-08T08:49:41.317822Z","iopub.status.idle":"2025-08-08T08:49:49.946780Z","shell.execute_reply.started":"2025-08-08T08:49:41.317798Z","shell.execute_reply":"2025-08-08T08:49:49.945646Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3. ToF Data Exploration","metadata":{}},{"cell_type":"code","source":"\n\n\npixels = [f\"tof_1_v{i}\" for i in range(64)]\ngrid = np.array(seq.iloc[50][pixels].astype(float)).reshape(8, 8)\nsns.heatmap(grid, cmap=\"viridis\", cbar=True)\nplt.title(\"ToF Sensor 1 – Distance Heatmap\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-08T09:00:59.132876Z","iopub.execute_input":"2025-08-08T09:00:59.133273Z","iopub.status.idle":"2025-08-08T09:00:59.413137Z","shell.execute_reply.started":"2025-08-08T09:00:59.133223Z","shell.execute_reply":"2025-08-08T09:00:59.412210Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\nfig, ax = plt.subplots()\n\ndef update(i):\n    grid = np.array(seq.iloc[i][pixels].astype(float)).reshape(8, 8)\n    ax.clear()\n    sns.heatmap(grid, cmap=\"viridis\", cbar=False, ax=ax)\n\nani = animation.FuncAnimation(fig, update, frames=range(0, len(seq)), interval=100)\n\nHTML(ani.to_jshtml())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-08T09:01:07.426551Z","iopub.execute_input":"2025-08-08T09:01:07.426985Z","iopub.status.idle":"2025-08-08T09:01:14.502921Z","shell.execute_reply.started":"2025-08-08T09:01:07.426951Z","shell.execute_reply":"2025-08-08T09:01:14.501927Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 4. IMU + ToF Combined Visualization\n## A. Synchronized Visualization (single time point)","metadata":{}},{"cell_type":"code","source":"fig, axs = plt.subplots(1, 2, figsize=(12, 4))\n\n# IMU ivme\naxs[0].plot(seq[\"sequence_counter\"], seq[\"acc_x\"], label=\"acc_x\")\naxs[0].plot(seq[\"sequence_counter\"], seq[\"acc_y\"], label=\"acc_y\")\naxs[0].plot(seq[\"sequence_counter\"], seq[\"acc_z\"], label=\"acc_z\")\naxs[0].legend(); axs[0].set_title(\"IMU Acc/time\")\n\n# ToF grid (örnek zaman noktası: 50)\ngrid = np.array(seq.iloc[50][pixels].astype(float)).reshape(8, 8)\nsns.heatmap(grid, cmap=\"viridis\", ax=axs[1], cbar=True)\naxs[1].set_title(\"ToF Sensor – Distance Heatmap\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-08T09:14:27.203264Z","iopub.execute_input":"2025-08-08T09:14:27.203705Z","iopub.status.idle":"2025-08-08T09:14:27.739591Z","shell.execute_reply.started":"2025-08-08T09:14:27.203678Z","shell.execute_reply":"2025-08-08T09:14:27.738472Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pixels = [f\"tof_1_v{i}\" for i in range(64)]\nvalid_id = df[\"sequence_id\"].unique()[0]\nseq = df[df[\"sequence_id\"] == valid_id]\n\nanimate_combined_sequence(seq, pixels)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-08T09:14:33.168891Z","iopub.execute_input":"2025-08-08T09:14:33.169968Z","iopub.status.idle":"2025-08-08T09:14:51.657047Z","shell.execute_reply.started":"2025-08-08T09:14:33.169936Z","shell.execute_reply":"2025-08-08T09:14:51.656184Z"}},"outputs":[],"execution_count":null}]}