{"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":"import polars as pl\nimport pandas as pd\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import f1_score","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:34:39.316857Z","iopub.execute_input":"2025-07-27T04:34:39.317150Z","iopub.status.idle":"2025-07-27T04:34:41.095571Z","shell.execute_reply.started":"2025-07-27T04:34:39.317129Z","shell.execute_reply":"2025-07-27T04:34:41.094483Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 1: Import Libraries & Load Data\n* Here, we load the CSV files (like big spreadsheets) into memory so Python can use them.\n* Why: Before building a model, you must see and understand your data.","metadata":{}},{"cell_type":"code","source":"# Load the train and test CSV files into Polars DataFrames (like tables)\ntrain = pl.read_csv('/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv')\ntest = pl.read_csv('/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv')\n\n# Convert Polars DataFrames to pandas DataFrames for compatibility with sklearn (the model library)\ntrain_pd = train.to_pandas()\ntest_pd = test.to_pandas()\n\n# Print the first few rows of train and test data to see what they look like\nprint(train_pd.head())    # Shows 5 rows by default\nprint(test_pd.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:34:45.436244Z","iopub.execute_input":"2025-07-27T04:34:45.436688Z","iopub.status.idle":"2025-07-27T04:35:07.096143Z","shell.execute_reply.started":"2025-07-27T04:34:45.436663Z","shell.execute_reply":"2025-07-27T04:35:07.095378Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 2: Select IMU Features\n\n- We only want to use some sensor columns (the IMU ones) to keep things simple at first.\n- Picking these columns reduces the data to only the features we want to use.\n- Using only a few features helps you learn and makes the model run faster.\n","metadata":{}},{"cell_type":"code","source":"# Pick column names that start with 'acc_' or 'rot_' (all IMU sensor columns)\nimu_cols = [col for col in train_pd.columns if col.startswith('acc_') or col.startswith('rot_')]\n\n# Print out the list of IMU columns so we know which features we’re using\nprint(\"Selected IMU columns:\", imu_cols)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:14.252516Z","iopub.execute_input":"2025-07-27T04:35:14.252973Z","iopub.status.idle":"2025-07-27T04:35:14.258557Z","shell.execute_reply.started":"2025-07-27T04:35:14.252930Z","shell.execute_reply":"2025-07-27T04:35:14.257344Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 3: Aggregate Data by Gesture (Sequence)\n- Each “sequence” represents a whole gesture, but there are many data points (rows) for each gesture.\n- We want to summarize all these rows into just one row per gesture by taking the average (mean) value for each feature.\n- Why: Classic machine learning models expect one row per example (here: one gesture), not hundreds of rows per gesture.","metadata":{}},{"cell_type":"code","source":"# For each gesture (identified by 'sequence_id'), calculate the average value of each IMU feature\ntrain_agg = train_pd.groupby('sequence_id')[imu_cols].mean().reset_index()\n\n# Print the shape of the new DataFrame (how many rows and columns), and see the first few rows\nprint(\"Aggregated train shape:\", train_agg.shape)\nprint(train_agg.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:16.140812Z","iopub.execute_input":"2025-07-27T04:35:16.141409Z","iopub.status.idle":"2025-07-27T04:35:16.221014Z","shell.execute_reply.started":"2025-07-27T04:35:16.141383Z","shell.execute_reply":"2025-07-27T04:35:16.220185Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 4: Prepare Labels\n- Each sequence/gesture also needs a label telling us if it’s a BFRB (target) or not (non-target).\n- We extract this label from the original data (using the first row for each gesture).\n- Why: You need labels (“answers”) to train a supervised machine learning model.","metadata":{}},{"cell_type":"code","source":"# For each sequence, get the 'sequence_type' (our label: target or non-target)\nlabels = train_pd.groupby('sequence_id')['sequence_type'].first().reset_index()\nprint(labels.head())   # Show the first few labels\n\n# Add (merge) the labels to our feature DataFrame so each row has both features and its label\ntrain_agg = train_agg.merge(labels, on='sequence_id')\nprint(train_agg.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:18.576908Z","iopub.execute_input":"2025-07-27T04:35:18.577281Z","iopub.status.idle":"2025-07-27T04:35:18.667406Z","shell.execute_reply.started":"2025-07-27T04:35:18.577253Z","shell.execute_reply":"2025-07-27T04:35:18.666523Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 5: Prepare Features and Targets\n- We separate the features (X) and labels (y) to feed them into the model.\n- We also convert the text labels to numbers (1 for target, 0 for non-target).\n- Why: Models need features as input (X) and labels as output (y), with labels as numbers for classification.","metadata":{}},{"cell_type":"code","source":"X = train_agg[imu_cols]   # Features: the IMU columns (acceleration & rotation)\ny = train_agg['sequence_type'].map({'Target': 1, 'Non-Target': 0})  # Labels as numbers\n\n# Print the shape of X and how many targets/non-targets we have\nprint(\"X shape:\", X.shape)\nprint(\"y distribution:\", y.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:22.621821Z","iopub.execute_input":"2025-07-27T04:35:22.622174Z","iopub.status.idle":"2025-07-27T04:35:22.630564Z","shell.execute_reply.started":"2025-07-27T04:35:22.622150Z","shell.execute_reply":"2025-07-27T04:35:22.629679Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(X.isnull().sum())      # See how many NaNs per feature\nprint(X.isnull().sum().sum()) # Total NaNs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:24.721776Z","iopub.execute_input":"2025-07-27T04:35:24.722042Z","iopub.status.idle":"2025-07-27T04:35:24.729106Z","shell.execute_reply.started":"2025-07-27T04:35:24.722022Z","shell.execute_reply":"2025-07-27T04:35:24.728188Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### How to remove rows with NaN in your features:","metadata":{}},{"cell_type":"code","source":"# After creating X and y\nX_clean = X.dropna()\ny_clean = y[X_clean.index]   # Make sure labels match the cleaned features\n\nprint(X_clean.shape)         # Check how many rows remain\nprint(y_clean.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:27.121567Z","iopub.execute_input":"2025-07-27T04:35:27.122266Z","iopub.status.idle":"2025-07-27T04:35:27.131203Z","shell.execute_reply.started":"2025-07-27T04:35:27.122232Z","shell.execute_reply":"2025-07-27T04:35:27.130388Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(X_clean.isnull().sum())      # See how many NaNs per feature\nprint(X_clean.isnull().sum().sum()) # Total NaNs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:28.806553Z","iopub.execute_input":"2025-07-27T04:35:28.806821Z","iopub.status.idle":"2025-07-27T04:35:28.813569Z","shell.execute_reply.started":"2025-07-27T04:35:28.806801Z","shell.execute_reply":"2025-07-27T04:35:28.812868Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 6: Split for Validation\n- We divide the data into a “training set” (to learn) and a “validation set” (to check if our model really works).\n- This helps prevent overfitting (memorizing instead of learning patterns).\n- Why: Testing on new (unseen) data tells us if our model is really learning, not just memorizing.","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split    # Tool for splitting data\n\n# Split: 80% for training, 20% for validation; set random_state for repeatability\nX_train, X_val, y_train, y_val = train_test_split(X_clean, y_clean, test_size=0.2, random_state=42)\n\n# Show the size of each split\nprint(\"Train shape:\", X_train.shape)\nprint(\"Validation shape:\", X_val.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:31.128218Z","iopub.execute_input":"2025-07-27T04:35:31.128514Z","iopub.status.idle":"2025-07-27T04:35:31.137925Z","shell.execute_reply.started":"2025-07-27T04:35:31.128495Z","shell.execute_reply":"2025-07-27T04:35:31.136889Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 7: Build and Train the Model\n\nWe create a logistic regression model and teach it (fit) using our training data.","metadata":{}},{"cell_type":"code","source":"from sklearn.linear_model import LogisticRegression     # Our simple model\n\n# Create the logistic regression model; max_iter helps it finish training if data is tricky\nmodel = LogisticRegression(max_iter=200)\nmodel.fit(X_train, y_train)    # Teach the model to predict y_train from X_train\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:33.593133Z","iopub.execute_input":"2025-07-27T04:35:33.593451Z","iopub.status.idle":"2025-07-27T04:35:33.780369Z","shell.execute_reply.started":"2025-07-27T04:35:33.593431Z","shell.execute_reply":"2025-07-27T04:35:33.779276Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 8: Validate the Model\n- After training, we use the model to predict the labels for the validation set and measure its performance.\n- Why: Validation checks if the model can make good predictions on new data, not just on the data it was trained with.\n\n","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import f1_score    # F1 score is a good metric for imbalanced data\n\ny_pred = model.predict(X_val)           # Predict labels for the validation features\nprint(\"Validation F1 Score:\", f1_score(y_val, y_pred))   # Print F1 score","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-27T04:35:36.040153Z","iopub.execute_input":"2025-07-27T04:35:36.040451Z","iopub.status.idle":"2025-07-27T04:35:36.053712Z","shell.execute_reply.started":"2025-07-27T04:35:36.040430Z","shell.execute_reply":"2025-07-27T04:35:36.052560Z"}},"outputs":[],"execution_count":null}]}