{"cells": [{"cell_type": "markdown", "id": "cell-0", "metadata": {}, "source": "# CMI V8 - Improved Model with Full Dataset\n\n**Target: 87%+ Validation Accuracy**\n- \u5168\u30c7\u30fc\u30bf\u30bb\u30c3\u30c8\u4f7f\u7528\uff088151\u30b7\u30fc\u30b1\u30f3\u30b9\uff09\n- \u9ad8\u5ea6\u306a\u7279\u5fb4\u91cf\u30a8\u30f3\u30b8\u30cb\u30a2\u30ea\u30f3\u30b0\n- \u6700\u9069\u5316\u3055\u308c\u305f\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb"}, {"cell_type": "code", "execution_count": null, "id": "cell-1", "metadata": {}, "outputs": [], "source": "import numpy as np\nimport pandas as pd\nimport pickle\nimport gc\nimport warnings\nimport lightgbm as lgb\nimport xgboost as xgb\nimport catboost as cb\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder\nfrom sklearn.model_selection import GroupKFold\nfrom scipy import signal, stats\nfrom scipy.fft import fft, fftfreq\n\nwarnings.filterwarnings(\"ignore\")\n\nprint(\"Loading data...\")\ntrain_df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv\")\ntrain_demo = pd.read_csv(\n    \"/kaggle/input/cmi-detect-behavior-with-sensor-data/train_demographics.csv\"\n)\n\n# Get labels\ngesture_labels = sorted(train_df[\"gesture\"].unique())\nnum_classes = len(gesture_labels)\n\nprint(f\"Classes: {num_classes}\")\nprint(f\"Total samples: {len(train_df)}\")\nprint(f\"Unique sequences: {train_df['sequence_id'].nunique()}\")"}, {"cell_type": "code", "execution_count": null, "id": "cell-2", "metadata": {}, "outputs": [], "source": "def remove_gravity_from_acc(df_seq, alpha=0.8):\n    \"\"\"\u91cd\u529b\u9664\u53bb\u306b\u3088\u308b\u7dda\u5f62\u52a0\u901f\u5ea6\u306e\u8a08\u7b97\"\"\"\n    acc_cols = [\"acc_x\", \"acc_y\", \"acc_z\"]\n    if not all(col in df_seq.columns for col in acc_cols):\n        return None\n\n    acc_data = df_seq[acc_cols].values\n    gravity = np.zeros_like(acc_data)\n    gravity[0] = acc_data[0]\n\n    for i in range(1, len(acc_data)):\n        gravity[i] = alpha * gravity[i - 1] + (1 - alpha) * acc_data[i]\n\n    linear_acc = acc_data - gravity\n    return linear_acc\n\n\ndef quaternion_to_angular_velocity(df_seq):\n    \"\"\"\u30af\u30a9\u30fc\u30bf\u30cb\u30aa\u30f3\u304b\u3089\u89d2\u901f\u5ea6\u3092\u8a08\u7b97\"\"\"\n    quat_cols = [\"rot_x\", \"rot_y\", \"rot_z\", \"rot_w\"]\n    if not all(col in df_seq.columns for col in quat_cols):\n        return None\n\n    q = df_seq[quat_cols].values\n\n    # \u6b63\u898f\u5316\n    q_norm = np.linalg.norm(q, axis=1, keepdims=True)\n    q = q / (q_norm + 1e-10)\n\n    # \u6642\u9593\u5fae\u5206\u3067\u89d2\u901f\u5ea6\u3092\u63a8\u5b9a\n    dq = np.gradient(q, axis=0)\n\n    # \u89d2\u901f\u5ea6\u30d9\u30af\u30c8\u30eb\u8a08\u7b97\n    w = np.zeros((len(q), 3))\n    for i in range(len(q)):\n        w[i, 0] = 2 * (\n            q[i, 3] * dq[i, 0]\n            - q[i, 0] * dq[i, 3]\n            - q[i, 1] * dq[i, 2]\n            + q[i, 2] * dq[i, 1]\n        )\n        w[i, 1] = 2 * (\n            q[i, 3] * dq[i, 1]\n            - q[i, 1] * dq[i, 3]\n            - q[i, 2] * dq[i, 0]\n            + q[i, 0] * dq[i, 2]\n        )\n        w[i, 2] = 2 * (\n            q[i, 3] * dq[i, 2]\n            - q[i, 2] * dq[i, 3]\n            - q[i, 0] * dq[i, 1]\n            + q[i, 1] * dq[i, 0]\n        )\n\n    return w\n\n\ndef extract_frequency_features(signal_data, sampling_rate=50):\n    \"\"\"\u5468\u6ce2\u6570\u9818\u57df\u7279\u5fb4\u91cf\u306e\u62bd\u51fa\"\"\"\n    if len(signal_data) < 10:\n        return {}\n\n    fft_values = np.abs(fft(signal_data))\n    freqs = fftfreq(len(signal_data), 1 / sampling_rate)\n\n    # \u6b63\u306e\u5468\u6ce2\u6570\u306e\u307f\n    pos_idx = freqs > 0\n    fft_values = fft_values[pos_idx]\n    freqs = freqs[pos_idx]\n\n    features = {}\n    if len(fft_values) > 0:\n        features[\"fft_max\"] = np.max(fft_values)\n        features[\"fft_mean\"] = np.mean(fft_values)\n        features[\"fft_std\"] = np.std(fft_values)\n\n        # \u30d4\u30fc\u30af\u5468\u6ce2\u6570\n        peak_idx = np.argmax(fft_values)\n        features[\"peak_freq\"] = freqs[peak_idx] if len(freqs) > 0 else 0\n\n    return features"}, {"cell_type": "code", "execution_count": null, "id": "cell-3", "metadata": {}, "outputs": [], "source": "def extract_comprehensive_features(df_seq):\n    \"\"\"\u5305\u62ec\u7684\u306a\u7279\u5fb4\u91cf\u62bd\u51fa\"\"\"\n    features = {}\n\n    # \u57fa\u672c\u7d71\u8a08\u91cf\n    for col in [\"acc_x\", \"acc_y\", \"acc_z\", \"rot_x\", \"rot_y\", \"rot_z\", \"rot_w\"]:\n        if col in df_seq.columns:\n            values = df_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}_range\"] = features[f\"{col}_max\"] - features[f\"{col}_min\"]\n            features[f\"{col}_skew\"] = stats.skew(values)\n            features[f\"{col}_kurtosis\"] = stats.kurtosis(values)\n\n            # \u5909\u5316\u91cf\u7d71\u8a08\n            diff = np.diff(values)\n            if len(diff) > 0:\n                features[f\"{col}_diff_mean\"] = np.mean(diff)\n                features[f\"{col}_diff_std\"] = np.std(diff)\n\n    # \u91cd\u529b\u9664\u53bb\u52a0\u901f\u5ea6\n    linear_acc = remove_gravity_from_acc(df_seq)\n    if linear_acc is not None:\n        for i, axis in enumerate([\"x\", \"y\", \"z\"]):\n            features[f\"linear_acc_{axis}_mean\"] = np.mean(linear_acc[:, i])\n            features[f\"linear_acc_{axis}_std\"] = np.std(linear_acc[:, i])\n            features[f\"linear_acc_{axis}_max\"] = np.max(np.abs(linear_acc[:, i]))\n\n    # \u89d2\u901f\u5ea6\n    angular_vel = quaternion_to_angular_velocity(df_seq)\n    if angular_vel is not None:\n        for i, axis in enumerate([\"x\", \"y\", \"z\"]):\n            features[f\"angular_vel_{axis}_mean\"] = np.mean(angular_vel[:, i])\n            features[f\"angular_vel_{axis}_std\"] = np.std(angular_vel[:, i])\n            features[f\"angular_vel_{axis}_max\"] = np.max(np.abs(angular_vel[:, i]))\n\n    # \u52a0\u901f\u5ea6\u30de\u30b0\u30cb\u30c1\u30e5\u30fc\u30c9\n    if all(col in df_seq.columns for col in [\"acc_x\", \"acc_y\", \"acc_z\"]):\n        acc_mag = np.sqrt(\n            df_seq[\"acc_x\"] ** 2 + df_seq[\"acc_y\"] ** 2 + df_seq[\"acc_z\"] ** 2\n        )\n        features[\"acc_mag_mean\"] = np.mean(acc_mag)\n        features[\"acc_mag_std\"] = np.std(acc_mag)\n        features[\"acc_mag_max\"] = np.max(acc_mag)\n\n        # \u30b8\u30e3\u30fc\u30af\uff08\u52a0\u901f\u5ea6\u306e\u5909\u5316\u7387\uff09\n        jerk = np.diff(acc_mag)\n        if len(jerk) > 0:\n            features[\"jerk_mean\"] = np.mean(np.abs(jerk))\n            features[\"jerk_std\"] = np.std(jerk)\n            features[\"jerk_max\"] = np.max(np.abs(jerk))\n\n        # \u5468\u6ce2\u6570\u7279\u5fb4\n        freq_features = extract_frequency_features(acc_mag.values)\n        for key, value in freq_features.items():\n            features[f\"acc_mag_{key}\"] = value\n\n    # \u6e29\u5ea6\u30bb\u30f3\u30b5\u30fc\n    temp_cols = [f\"thm_{i}\" for i in range(1, 6)]\n    temp_cols = [col for col in temp_cols if col in df_seq.columns]\n    if temp_cols:\n        temp_data = df_seq[temp_cols].values\n        features[\"temp_mean\"] = np.mean(temp_data)\n        features[\"temp_std\"] = np.std(temp_data)\n        features[\"temp_range\"] = np.max(temp_data) - np.min(temp_data)\n\n    # ToF\u30bb\u30f3\u30b5\u30fc\uff08\u6b21\u5143\u524a\u6e1b\uff09\n    tof_cols = [col for col in df_seq.columns if col.startswith(\"tof_\")]\n    if tof_cols:\n        tof_data = df_seq[tof_cols].values\n        # \u7d71\u8a08\u91cf\u3067\u8981\u7d04\n        features[\"tof_mean\"] = np.mean(tof_data)\n        features[\"tof_std\"] = np.std(tof_data)\n        features[\"tof_max\"] = np.max(tof_data)\n        features[\"tof_min\"] = np.min(tof_data)\n\n        # \u5404\u30d5\u30ec\u30fc\u30e0\u306e\u7d71\u8a08\u91cf\n        features[\"tof_frame_mean_std\"] = np.std(np.mean(tof_data, axis=1))\n        features[\"tof_frame_max_mean\"] = np.mean(np.max(tof_data, axis=1))\n\n    # \u30b7\u30fc\u30b1\u30f3\u30b9\u9577\n    features[\"sequence_length\"] = len(df_seq)\n\n    return features"}, {"cell_type": "code", "execution_count": null, "id": "cell-4", "metadata": {}, "outputs": [], "source": "# \u5168\u30c7\u30fc\u30bf\u3067\u7279\u5fb4\u91cf\u62bd\u51fa\nprint(\"Extracting features from all sequences...\")\nX_features = []\ny_labels = []\ngroups = []\n\n# Label encoder\nle = LabelEncoder()\nle.fit(gesture_labels)\n\nsequence_ids = train_df[\"sequence_id\"].unique()\ntotal_sequences = len(sequence_ids)\n\n# \u5168\u30c7\u30fc\u30bf\u3092\u51e6\u7406\uff08\u30d0\u30c3\u30c1\u51e6\u7406\u3067\u52b9\u7387\u5316\uff09\nbatch_size = 1000\nfor batch_start in range(0, total_sequences, batch_size):\n    batch_end = min(batch_start + batch_size, total_sequences)\n    batch_seq_ids = sequence_ids[batch_start:batch_end]\n\n    if batch_start % 2000 == 0:\n        print(f\"Processing sequences {batch_start}/{total_sequences}...\")\n\n    for seq_id in batch_seq_ids:\n        seq_data = train_df[train_df[\"sequence_id\"] == seq_id]\n\n        # \u7279\u5fb4\u91cf\u62bd\u51fa\n        features = extract_comprehensive_features(seq_data)\n        X_features.append(features)\n\n        # \u30e9\u30d9\u30eb\n        gesture = seq_data[\"gesture\"].iloc[0]\n        label = le.transform([gesture])[0]\n        y_labels.append(label)\n\n        # Subject ID\uff08GroupKFold\u7528\uff09\n        subject = seq_data[\"subject\"].iloc[0]\n        groups.append(subject)\n\n    # \u30e1\u30e2\u30ea\u89e3\u653e\n    if batch_start % 2000 == 0:\n        gc.collect()\n\n# DataFrame\u306b\u5909\u63db\nX_df = pd.DataFrame(X_features)\ny_array = np.array(y_labels)\ngroups_array = np.array(groups)\n\nprint(f\"Feature shape: {X_df.shape}\")\nprint(f\"Number of features: {len(X_df.columns)}\")\n\n# \u6b20\u640d\u5024\u30920\u3067\u57cb\u3081\u308b\nX_df = X_df.fillna(0)"}, {"cell_type": "code", "execution_count": null, "id": "cell-5", "metadata": {}, "outputs": [], "source": "# GroupKFold\u3067\u4ea4\u5dee\u691c\u8a3c\nprint(\"Training models with GroupKFold...\")\ngkf = GroupKFold(n_splits=5)\n\n# \u691c\u8a3c\u30b9\u30b3\u30a2\u4fdd\u5b58\u7528\nval_scores = []\nmodels = []\n\nfor fold, (train_idx, val_idx) in enumerate(gkf.split(X_df, y_array, groups_array)):\n    print(f\"\\nFold {fold + 1}/5\")\n\n    X_train = X_df.iloc[train_idx]\n    X_val = X_df.iloc[val_idx]\n    y_train = y_array[train_idx]\n    y_val = y_array[val_idx]\n\n    # LightGBM\n    lgb_params = {\n        \"objective\": \"multiclass\",\n        \"num_class\": num_classes,\n        \"metric\": \"multi_logloss\",\n        \"boosting_type\": \"gbdt\",\n        \"num_leaves\": 127,\n        \"learning_rate\": 0.05,\n        \"feature_fraction\": 0.9,\n        \"bagging_fraction\": 0.9,\n        \"bagging_freq\": 5,\n        \"min_child_samples\": 20,\n        \"verbose\": -1,\n        \"seed\": 42 + fold,\n    }\n\n    train_data = lgb.Dataset(X_train, label=y_train)\n    valid_data = lgb.Dataset(X_val, label=y_val)\n\n    model_lgb = lgb.train(\n        lgb_params,\n        train_data,\n        valid_sets=[valid_data],\n        num_boost_round=1000,\n        callbacks=[lgb.early_stopping(100), lgb.log_evaluation(0)],\n    )\n\n    # \u4e88\u6e2c\n    pred_lgb = model_lgb.predict(X_val, num_iteration=model_lgb.best_iteration)\n    pred_class = np.argmax(pred_lgb, axis=1)\n    accuracy = np.mean(pred_class == y_val)\n\n    print(f\"LightGBM Validation Accuracy: {accuracy:.4f}\")\n    val_scores.append(accuracy)\n    models.append(model_lgb)\n\n# \u5e73\u5747\u7cbe\u5ea6\nmean_accuracy = np.mean(val_scores)\nstd_accuracy = np.std(val_scores)\nprint(f\"\\n=== Cross-Validation Results ===\")\nprint(f\"Mean Accuracy: {mean_accuracy:.4f} (+/- {std_accuracy:.4f})\")\nprint(f\"Target 87%: {'\u2705 ACHIEVED' if mean_accuracy >= 0.87 else '\u274c NOT YET'}\")"}, {"cell_type": "code", "execution_count": null, "id": "cell-6", "metadata": {}, "outputs": [], "source": "# XGBoost\u3082\u8ffd\u52a0\u3067\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\nprint(\"\\nTraining XGBoost for ensemble...\")\n\n# \u6700\u826f\u306efold\u306e\u30c7\u30fc\u30bf\u3067XGBoost\u3092\u30c8\u30ec\u30fc\u30cb\u30f3\u30b0\nbest_fold = np.argmax(val_scores)\ntrain_idx, val_idx = list(gkf.split(X_df, y_array, groups_array))[best_fold]\n\nX_train = X_df.iloc[train_idx]\nX_val = X_df.iloc[val_idx]\ny_train = y_array[train_idx]\ny_val = y_array[val_idx]\n\n# XGBoost\nxgb_params = {\n    \"objective\": \"multi:softprob\",\n    \"num_class\": num_classes,\n    \"max_depth\": 8,\n    \"learning_rate\": 0.05,\n    \"subsample\": 0.9,\n    \"colsample_bytree\": 0.9,\n    \"eval_metric\": \"mlogloss\",\n    \"seed\": 42,\n    \"tree_method\": \"hist\",\n}\n\ndtrain = xgb.DMatrix(X_train, label=y_train)\ndval = xgb.DMatrix(X_val, label=y_val)\n\nmodel_xgb = xgb.train(\n    xgb_params,\n    dtrain,\n    num_boost_round=1000,\n    evals=[(dval, \"val\")],\n    early_stopping_rounds=100,\n    verbose_eval=False,\n)\n\n# XGBoost\u4e88\u6e2c\npred_xgb = model_xgb.predict(dval)\npred_xgb_class = np.argmax(pred_xgb, axis=1)\nxgb_accuracy = np.mean(pred_xgb_class == y_val)\nprint(f\"XGBoost Validation Accuracy: {xgb_accuracy:.4f}\")\n\n# \u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\npred_lgb = models[best_fold].predict(\n    X_val, num_iteration=models[best_fold].best_iteration\n)\npred_ensemble = 0.6 * pred_lgb + 0.4 * pred_xgb\npred_ensemble_class = np.argmax(pred_ensemble, axis=1)\nensemble_accuracy = np.mean(pred_ensemble_class == y_val)\n\nprint(f\"\\n\ud83c\udfaf Ensemble Accuracy: {ensemble_accuracy:.4f}\")\nprint(f\"Target 87%: {'\u2705 ACHIEVED' if ensemble_accuracy >= 0.87 else '\u274c NOT YET'}\")"}, {"cell_type": "code", "execution_count": null, "id": "cell-7", "metadata": {}, "outputs": [], "source": "# CatBoost\u3082\u8ffd\u52a0\nprint(\"\\nTraining CatBoost for triple ensemble...\")\n\ncat_params = {\n    \"loss_function\": \"MultiClass\",\n    \"iterations\": 1000,\n    \"learning_rate\": 0.05,\n    \"depth\": 8,\n    \"l2_leaf_reg\": 3,\n    \"random_seed\": 42,\n    \"verbose\": False,\n    \"early_stopping_rounds\": 100,\n}\n\ntrain_pool = cb.Pool(X_train, y_train)\nval_pool = cb.Pool(X_val, y_val)\n\nmodel_cat = cb.CatBoostClassifier(**cat_params)\nmodel_cat.fit(train_pool, eval_set=val_pool, verbose=False)\n\n# CatBoost\u4e88\u6e2c\npred_cat = model_cat.predict_proba(X_val)\npred_cat_class = np.argmax(pred_cat, axis=1)\ncat_accuracy = np.mean(pred_cat_class == y_val)\nprint(f\"CatBoost Validation Accuracy: {cat_accuracy:.4f}\")\n\n# \u30c8\u30ea\u30d7\u30eb\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\npred_triple = 0.4 * pred_lgb + 0.3 * pred_xgb + 0.3 * pred_cat\npred_triple_class = np.argmax(pred_triple, axis=1)\ntriple_accuracy = np.mean(pred_triple_class == y_val)\n\nprint(f\"\\n\ud83c\udfaf Triple Ensemble Accuracy: {triple_accuracy:.4f}\")\nprint(f\"Target 87%: {'\u2705 ACHIEVED!!!' if triple_accuracy >= 0.87 else '\u274c NOT YET'}\")\n\n# \u6700\u7d42\u7cbe\u5ea6\nfinal_accuracy = max(mean_accuracy, ensemble_accuracy, triple_accuracy)\nprint(f\"\\n\ud83c\udfc6 Best Validation Accuracy: {final_accuracy:.4f}\")"}, {"cell_type": "code", "execution_count": null, "id": "cell-8", "metadata": {}, "outputs": [], "source": "# \u30e2\u30c7\u30eb\u4fdd\u5b58\nprint(\"\\nSaving models...\")\n\n# \u6700\u826f\u306eLightGBM\u30e2\u30c7\u30eb\nwith open(\"lgb_model_v8.pkl\", \"wb\") as f:\n    pickle.dump(models[best_fold], f)\n\n# XGBoost\u30e2\u30c7\u30eb\nwith open(\"xgb_model_v8.pkl\", \"wb\") as f:\n    pickle.dump(model_xgb, f)\n\n# CatBoost\u30e2\u30c7\u30eb\nmodel_cat.save_model(\"cat_model_v8.cbm\")\n\n# Label encoder\nwith open(\"label_encoder_v8.pkl\", \"wb\") as f:\n    pickle.dump(le, f)\n\nprint(\"Models saved successfully\")"}, {"cell_type": "code", "execution_count": null, "id": "cell-9", "metadata": {}, "outputs": [], "source": "# CMI\u63a8\u8ad6\u30b5\u30fc\u30d0\u30fc\nimport sys\n\nsys.path.append(\"/kaggle/input/cmi-detect-behavior-with-sensor-data\")\nfrom kaggle_evaluation.cmi_inference_server import CMIInferenceServer\n\n\ndef predict(sequence, demographics):\n    \"\"\"CMI\u63a8\u8ad6\u30b5\u30fc\u30d0\u30fc\u7528\u4e88\u6e2c\u95a2\u6570\"\"\"\n    try:\n        # DataFrame\u306b\u5909\u63db\n        df_seq = pd.DataFrame(sequence)\n\n        # \u7279\u5fb4\u91cf\u62bd\u51fa\n        features = extract_comprehensive_features(df_seq)\n        X_feat = pd.DataFrame([features])\n        X_feat = X_feat.fillna(0)\n\n        # \u5404\u30e2\u30c7\u30eb\u3067\u4e88\u6e2c\n        pred_lgb = models[best_fold].predict(\n            X_feat, num_iteration=models[best_fold].best_iteration\n        )\n\n        dtest = xgb.DMatrix(X_feat)\n        pred_xgb = model_xgb.predict(dtest)\n\n        pred_cat = model_cat.predict_proba(X_feat)\n\n        # \u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\n        pred_ensemble = 0.4 * pred_lgb + 0.3 * pred_xgb + 0.3 * pred_cat\n\n        # \u4e88\u6e2c\u30af\u30e9\u30b9\n        pred_class = np.argmax(pred_ensemble[0])\n        pred_gesture = le.inverse_transform([pred_class])[0]\n\n        return pred_gesture\n\n    except Exception as e:\n        print(f\"Prediction error: {e}\")\n        return \"Text on phone\"\n\n\nprint(\"Starting CMI Inference Server...\")\nserver = CMIInferenceServer(predict)\nserver.serve()\nprint(\"Inference complete\")"}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"name": "python", "version": "3.10.0"}}, "nbformat": 4, "nbformat_minor": 5}