{"cells": [{"cell_type": "markdown", "metadata": {}, "source": "# CMI Hybrid Ensemble V12 - \u5408\u6210\u30c7\u30fc\u30bf + \u5b9f\u30c7\u30fc\u30bf\u30e2\u30c7\u30eb\n\nV11\uff08\u5408\u6210\u30c7\u30fc\u30bf\uff09\u3068V12\uff08\u5b9f\u30c7\u30fc\u30bf\uff09\u30e2\u30c7\u30eb\u306e\u30cf\u30a4\u30d6\u30ea\u30c3\u30c9\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\u63a8\u8ad6"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "import os\nimport sys\nimport numpy as np\nimport pandas as pd\nimport polars as pl\nimport pickle\nimport warnings\n\nwarnings.filterwarnings(\"ignore\")\n\n# \u74b0\u5883\u5909\u6570\u3092\u78ba\u8a8d - Kaggle\u74b0\u5883\u306e\u8907\u6570\u306e\u5224\u5b9a\u65b9\u6cd5\nIS_KAGGLE = (\n    os.getenv(\"KAGGLE_IS_COMPETITION_RERUN\") is not None\n    or os.getenv(\"KAGGLE_KERNEL_RUN_TYPE\") is not None\n    or os.path.exists(\"/kaggle/input\")\n)\nprint(f\"Running on Kaggle: {IS_KAGGLE}\")\n\nif IS_KAGGLE:\n    DATA_PATH = \"/kaggle/input/cmi-detect-behavior-with-sensor-data/test\"\n    # V11\u30e2\u30c7\u30eb\uff08\u5408\u6210\u30c7\u30fc\u30bf\u30e2\u30c7\u30eb\uff09- \u6b63\u3057\u3044Dataset\u540d\u3092\u4f7f\u7528\n    V11_MODEL_PATH = \"/kaggle/input/cmi-v11-models\"\n    # V12\u30e2\u30c7\u30eb\uff08\u5b9f\u30c7\u30fc\u30bf\u30e2\u30c7\u30eb\uff09\n    V12_MODEL_PATH = \"/kaggle/input/cmi-v12-real-data-models\"\nelse:\n    DATA_PATH = \"/kaggle/input/cmi-detect-behavior-with-sensor-data/test\"\n    V11_MODEL_PATH = \"cmi-v11-dataset\"\n    V12_MODEL_PATH = \"models_v12\""}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "# \u30e2\u30c7\u30eb\u3092\u30ed\u30fc\u30c9\nimport lightgbm as lgb\nimport xgboost as xgb\nfrom catboost import CatBoostClassifier\nfrom sklearn.preprocessing import StandardScaler\nimport joblib\n\nprint(\"Loading V11 models (synthetic data)...\")\n# V11\u30e2\u30c7\u30eb - \u6700\u7d42\u30e2\u30c7\u30eb\u306e\u307f\u4f7f\u7528\nlgb_model_v11 = lgb.Booster(model_file=os.path.join(V11_MODEL_PATH, \"lgb_model_v11.txt\"))\ncat_model_v11 = CatBoostClassifier()\ncat_model_v11.load_model(os.path.join(V11_MODEL_PATH, \"cat_model_v11.cbm\"))\n\nprint(\"Loading V12 models (real data)...\")\n# V12\u30e2\u30c7\u30eb - \u6700\u7d42\u30e2\u30c7\u30eb\u306e\u307f\u4f7f\u7528\nlgb_model_v12 = lgb.Booster(\n    model_file=os.path.join(V12_MODEL_PATH, \"lgb_model_v12_final.txt\")\n)\nxgb_model_v12 = xgb.Booster()\nxgb_model_v12.load_model(os.path.join(V12_MODEL_PATH, \"xgb_model_v12_final.json\"))\ncat_model_v12 = CatBoostClassifier()\ncat_model_v12.load_model(os.path.join(V12_MODEL_PATH, \"cat_model_v12_final.cbm\"))\n\n# V12\u7528\u306escaler\u3068\u305d\u306e\u4ed6\u306e\u30e1\u30bf\u30c7\u30fc\u30bf\nwith open(os.path.join(V12_MODEL_PATH, \"scaler_v12.pkl\"), \"rb\") as f:\n    scaler_v12 = pickle.load(f)\nwith open(os.path.join(V12_MODEL_PATH, \"feature_names_v12.pkl\"), \"rb\") as f:\n    feature_names_v12 = pickle.load(f)\nwith open(os.path.join(V12_MODEL_PATH, \"gesture_mapping_v12.pkl\"), \"rb\") as f:\n    gesture_mapping_v12 = pickle.load(f)\n\nprint(f\"Loaded models successfully\")\nprint(f\"V12 features: {len(feature_names_v12)}\")\nprint(f\"Gesture mapping: {gesture_mapping_v12}\")"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "def extract_advanced_features(df, seq_id, metadata_row):\n    \"\"\"V12\u3067\u4f7f\u7528\u3059\u308b\u9ad8\u5ea6\u306a\u7279\u5fb4\u91cf\u62bd\u51fa\uff08V12\u3068\u540c\u3058\u5b9f\u88c5\uff09\"\"\"\n    features = {}\n\n    # \u57fa\u672c\u7d71\u8a08\u91cf\n    for col in df.columns:\n        if col != \"timestamp\":\n            features[f\"{col}_mean\"] = np.mean(df[col])\n            features[f\"{col}_std\"] = np.std(df[col])\n            features[f\"{col}_min\"] = np.min(df[col])\n            features[f\"{col}_max\"] = np.max(df[col])\n            features[f\"{col}_median\"] = np.median(df[col])\n            features[f\"{col}_q25\"] = np.percentile(df[col], 25)\n            features[f\"{col}_q75\"] = np.percentile(df[col], 75)\n            features[f\"{col}_iqr\"] = features[f\"{col}_q75\"] - features[f\"{col}_q25\"]\n            features[f\"{col}_skew\"] = df[col].skew() if len(df[col]) > 2 else 0\n            features[f\"{col}_kurtosis\"] = df[col].kurtosis() if len(df[col]) > 3 else 0\n\n    # \u91cd\u529b\u9664\u53bb\u7dda\u5f62\u52a0\u901f\u5ea6\n    gravity_x = np.mean(df[\"acc_x\"])\n    gravity_y = np.mean(df[\"acc_y\"])\n    gravity_z = np.mean(df[\"acc_z\"])\n\n    linear_acc_x = df[\"acc_x\"] - gravity_x\n    linear_acc_y = df[\"acc_y\"] - gravity_y\n    linear_acc_z = df[\"acc_z\"] - gravity_z\n\n    features[\"linear_acc_x_mean\"] = np.mean(linear_acc_x)\n    features[\"linear_acc_y_mean\"] = np.mean(linear_acc_y)\n    features[\"linear_acc_z_mean\"] = np.mean(linear_acc_z)\n    features[\"linear_acc_magnitude\"] = np.mean(\n        np.sqrt(linear_acc_x**2 + linear_acc_y**2 + linear_acc_z**2)\n    )\n\n    # \u30af\u30a9\u30fc\u30bf\u30cb\u30aa\u30f3\u304b\u3089\u30aa\u30a4\u30e9\u30fc\u89d2\n    qw = df[\"quat_w\"].values\n    qx = df[\"quat_x\"].values\n    qy = df[\"quat_y\"].values\n    qz = df[\"quat_z\"].values\n\n    # \u30ed\u30fc\u30eb\u3001\u30d4\u30c3\u30c1\u3001\u30e8\u30fc\n    roll = np.arctan2(2 * (qw * qx + qy * qz), 1 - 2 * (qx**2 + qy**2))\n    pitch = np.arcsin(np.clip(2 * (qw * qy - qz * qx), -1, 1))\n    yaw = np.arctan2(2 * (qw * qz + qx * qy), 1 - 2 * (qy**2 + qz**2))\n\n    features[\"euler_roll_mean\"] = np.mean(roll)\n    features[\"euler_pitch_mean\"] = np.mean(pitch)\n    features[\"euler_yaw_mean\"] = np.mean(yaw)\n    features[\"euler_roll_std\"] = np.std(roll)\n    features[\"euler_pitch_std\"] = np.std(pitch)\n    features[\"euler_yaw_std\"] = np.std(yaw)\n\n    # \u89d2\u901f\u5ea6\uff08\u30af\u30a9\u30fc\u30bf\u30cb\u30aa\u30f3\u306e\u6642\u9593\u5fae\u5206\uff09\n    if len(df) > 1:\n        dt = np.diff(df[\"timestamp\"].values) / 1000.0\n        dqw = np.diff(qw) / dt\n        dqx = np.diff(qx) / dt\n        dqy = np.diff(qy) / dt\n        dqz = np.diff(qz) / dt\n\n        features[\"angular_velocity_mean\"] = np.mean(np.sqrt(dqx**2 + dqy**2 + dqz**2))\n        features[\"angular_velocity_std\"] = np.std(np.sqrt(dqx**2 + dqy**2 + dqz**2))\n    else:\n        features[\"angular_velocity_mean\"] = 0\n        features[\"angular_velocity_std\"] = 0\n\n    # \u30b8\u30e3\u30fc\u30af\uff08\u52a0\u901f\u5ea6\u306e\u5909\u5316\u7387\uff09\n    if len(df) > 1:\n        jerk_x = np.diff(df[\"acc_x\"]) / dt\n        jerk_y = np.diff(df[\"acc_y\"]) / dt\n        jerk_z = np.diff(df[\"acc_z\"]) / dt\n\n        features[\"jerk_x_mean\"] = np.mean(jerk_x)\n        features[\"jerk_y_mean\"] = np.mean(jerk_y)\n        features[\"jerk_z_mean\"] = np.mean(jerk_z)\n        features[\"jerk_magnitude\"] = np.mean(np.sqrt(jerk_x**2 + jerk_y**2 + jerk_z**2))\n    else:\n        features[\"jerk_x_mean\"] = 0\n        features[\"jerk_y_mean\"] = 0\n        features[\"jerk_z_mean\"] = 0\n        features[\"jerk_magnitude\"] = 0\n\n    # ToF\u30bb\u30f3\u30b5\u30fc\u7d71\u8a08\n    tof_cols = [col for col in df.columns if col.startswith(\"tof_\")]\n    if tof_cols:\n        tof_values = df[tof_cols].values.flatten()\n        features[\"tof_global_mean\"] = np.mean(tof_values)\n        features[\"tof_global_std\"] = np.std(tof_values)\n        features[\"tof_global_min\"] = np.min(tof_values)\n        features[\"tof_global_max\"] = np.max(tof_values)\n\n    # \u30b7\u30fc\u30b1\u30f3\u30b9\u9577\n    features[\"sequence_length\"] = len(df)\n    features[\"duration_ms\"] = df[\"timestamp\"].max() - df[\"timestamp\"].min()\n\n    return features\n\n\ndef extract_simple_features(df, seq_id, metadata_row):\n    \"\"\"V11\u3067\u4f7f\u7528\u3059\u308b\u30b7\u30f3\u30d7\u30eb\u306a\u7279\u5fb4\u91cf\u62bd\u51fa\"\"\"\n    features = {}\n\n    # IMU\u30bb\u30f3\u30b5\u30fc\u30c7\u30fc\u30bf\u306e\u57fa\u672c\u7d71\u8a08\u91cf\n    imu_cols = [\"acc_x\", \"acc_y\", \"acc_z\", \"quat_w\", \"quat_x\", \"quat_y\", \"quat_z\"]\n    for col in imu_cols:\n        if col in df.columns:\n            features[f\"{col}_mean\"] = df[col].mean()\n            features[f\"{col}_std\"] = df[col].std()\n            features[f\"{col}_min\"] = df[col].min()\n            features[f\"{col}_max\"] = df[col].max()\n\n    # ToF\u30bb\u30f3\u30b5\u30fc\u306e\u7d71\u8a08\u91cf\n    tof_cols = [col for col in df.columns if col.startswith(\"tof_\")]\n    if tof_cols:\n        tof_values = df[tof_cols].values.flatten()\n        features[\"tof_mean\"] = np.mean(tof_values)\n        features[\"tof_std\"] = np.std(tof_values)\n        features[\"tof_min\"] = np.min(tof_values)\n        features[\"tof_max\"] = np.max(tof_values)\n\n    # \u52a0\u901f\u5ea6\u306e\u5927\u304d\u3055\n    if all(col in df.columns for col in [\"acc_x\", \"acc_y\", \"acc_z\"]):\n        acc_magnitude = np.sqrt(df[\"acc_x\"] ** 2 + df[\"acc_y\"] ** 2 + df[\"acc_z\"] ** 2)\n        features[\"acc_magnitude_mean\"] = acc_magnitude.mean()\n        features[\"acc_magnitude_std\"] = acc_magnitude.std()\n\n    # \u30b7\u30fc\u30b1\u30f3\u30b9\u9577\n    features[\"sequence_length\"] = len(df)\n\n    return features"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "# CMI\u63a8\u8ad6\u30b5\u30fc\u30d0\u30fc\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\uff08\u7af6\u6280\u63d0\u51fa\u7528\uff09\nif IS_KAGGLE:\n    from kaggle_evaluation.cmi_inference_server import CMIInferenceServer\n\n    def predict(test_data: pl.DataFrame, metadata: pl.DataFrame) -> pl.DataFrame:\n        \"\"\"\u30cf\u30a4\u30d6\u30ea\u30c3\u30c9\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\u4e88\u6e2c\"\"\"\n        print(f\"Processing {len(metadata)} sequences for prediction\")\n\n        # pandas DataFrame\u306b\u5909\u63db\n        test_df = test_data.to_pandas()\n        metadata_df = metadata.to_pandas()\n\n        predictions = []\n\n        for idx, row in metadata_df.iterrows():\n            seq_id = row[\"sequence_id\"]\n\n            # \u30b7\u30fc\u30b1\u30f3\u30b9\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\n            seq_data = test_df[test_df[\"sequence_id\"] == seq_id].copy()\n\n            if len(seq_data) == 0:\n                print(f\"Warning: No data for sequence {seq_id}\")\n                # \u30c7\u30d5\u30a9\u30eb\u30c8\u306f\u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u540d\u3067\u8fd4\u3059\n                predictions.append(\"Wave hello\")\n                continue\n\n            # V11\u7528\u306e\u7279\u5fb4\u91cf\u62bd\u51fa\uff08\u30b7\u30f3\u30d7\u30eb\uff09\n            features_v11 = extract_simple_features(seq_data, seq_id, row)\n            X_v11 = pd.DataFrame([features_v11])\n\n            # V11\u4e88\u6e2c\uff08LightGBM + CatBoost\uff09\n            pred_lgb_v11 = lgb_model_v11.predict(\n                X_v11, num_iteration=lgb_model_v11.best_iteration\n            )[0]\n            pred_cat_v11 = cat_model_v11.predict_proba(X_v11)[0]\n\n            # V11\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\uff08LightGBM 50% + CatBoost 50%\uff09\n            pred_v11 = 0.5 * pred_lgb_v11 + 0.5 * pred_cat_v11\n\n            # V12\u7528\u306e\u7279\u5fb4\u91cf\u62bd\u51fa\uff08\u9ad8\u5ea6\uff09\n            features_v12 = extract_advanced_features(seq_data, seq_id, row)\n            X_v12 = pd.DataFrame([features_v12])\n\n            # V12\u7528\u306e\u7279\u5fb4\u91cf\u3092\u6574\u5f62\n            X_v12_aligned = X_v12[feature_names_v12]\n            X_v12_scaled = scaler_v12.transform(X_v12_aligned)\n\n            # V12\u4e88\u6e2c\uff08LightGBM + XGBoost + CatBoost\uff09\n            pred_lgb_v12 = lgb_model_v12.predict(\n                X_v12_scaled, num_iteration=lgb_model_v12.best_iteration\n            )[0]\n\n            dmatrix_v12 = xgb.DMatrix(X_v12_scaled, feature_names=feature_names_v12)\n            pred_xgb_v12 = xgb_model_v12.predict(dmatrix_v12)[0]\n\n            pred_cat_v12 = cat_model_v12.predict_proba(X_v12_scaled)[0]\n\n            # V12\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\uff08LightGBM 40% + XGBoost 30% + CatBoost 30%\uff09\n            pred_v12 = 0.4 * pred_lgb_v12 + 0.3 * pred_xgb_v12 + 0.3 * pred_cat_v12\n\n            # \u30cf\u30a4\u30d6\u30ea\u30c3\u30c9\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\n            # V11\uff08\u5408\u6210\u30c7\u30fc\u30bf\uff0920% + V12\uff08\u5b9f\u30c7\u30fc\u30bf\uff0980%\n            hybrid_probs = 0.2 * pred_v11 + 0.8 * pred_v12\n\n            # \u6700\u3082\u78ba\u7387\u306e\u9ad8\u3044\u30af\u30e9\u30b9\u3092\u9078\u629e\n            pred_class = np.argmax(hybrid_probs)\n\n            # gesture_mapping\u3067\u5143\u306e\u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u540d\u306b\u623b\u3059\n            # gesture_mapping_v12\u306f{'gesture_to_id': {...}, 'id_to_gesture': {...}}\u306e\u69cb\u9020\n            if (\n                isinstance(gesture_mapping_v12, dict)\n                and \"id_to_gesture\" in gesture_mapping_v12\n            ):\n                gesture_name = gesture_mapping_v12[\"id_to_gesture\"].get(\n                    pred_class, \"Wave hello\"\n                )\n            else:\n                # \u30d5\u30a9\u30fc\u30eb\u30d0\u30c3\u30af\uff1a\u76f4\u63a5\u30de\u30c3\u30d4\u30f3\u30b0\n                gesture_names = [\n                    \"Above ear - pull hair\",\n                    \"Cheek - pinch skin\",\n                    \"Drink from bottle/cup\",\n                    \"Eyebrow - pull hair\",\n                    \"Eyelash - pull hair\",\n                    \"Feel around in tray and pull out an object\",\n                    \"Forehead - pull hairline\",\n                    \"Forehead - scratch\",\n                    \"Glasses on/off\",\n                    \"Neck - pinch skin\",\n                    \"Neck - scratch\",\n                    \"Pinch knee/leg skin\",\n                    \"Pull air toward your face\",\n                    \"Scratch knee/leg skin\",\n                    \"Text on phone\",\n                    \"Wave hello\",\n                    \"Write name in air\",\n                    \"Write name on leg\",\n                ]\n                gesture_name = (\n                    gesture_names[pred_class] if pred_class < 18 else \"Wave hello\"\n                )\n\n            predictions.append(gesture_name)\n\n        # Polars DataFrame\u3068\u3057\u3066\u8fd4\u3059\n        result = pl.DataFrame(\n            {\"sequence_id\": metadata[\"sequence_id\"], \"gesture\": predictions}\n        )\n\n        print(f\"Predictions completed. Shape: {result.shape}\")\n        print(f\"Sample predictions: {result.head()}\")\n\n        return result\n\n    # \u63a8\u8ad6\u30b5\u30fc\u30d0\u30fc\u3092\u958b\u59cb\n    print(\"Starting CMI Inference Server...\")\n    inference_server = CMIInferenceServer(predict)\n    print(\"CMI Inference Server initialized\")\n\n    # serve()\u3092\u547c\u3076 - \u7af6\u6280\u30c7\u30fc\u30bf\u3092\u51e6\u7406\n    print(\"Calling serve() - processing competition data...\")\n    inference_server.serve()\n    print(\"serve() completed\")\n\nelse:\n    print(\"Local testing mode - CMI inference server not available\")\n    print(\"Creating dummy submission for local testing...\")\n\n    # \u30ed\u30fc\u30ab\u30eb\u30c6\u30b9\u30c8\u7528\u306e\u30c0\u30df\u30fc\u51fa\u529b\n    gesture_names = [\n        \"Above ear - pull hair\",\n        \"Cheek - pinch skin\",\n        \"Drink from bottle/cup\",\n        \"Eyebrow - pull hair\",\n        \"Eyelash - pull hair\",\n        \"Feel around in tray and pull out an object\",\n        \"Forehead - pull hairline\",\n        \"Forehead - scratch\",\n        \"Glasses on/off\",\n        \"Neck - pinch skin\",\n        \"Neck - scratch\",\n        \"Pinch knee/leg skin\",\n        \"Pull air toward your face\",\n        \"Scratch knee/leg skin\",\n        \"Text on phone\",\n        \"Wave hello\",\n        \"Write name in air\",\n        \"Write name on leg\",\n    ]\n\n    dummy_submission = pl.DataFrame(\n        {\n            \"sequence_id\": list(range(1, 101)),\n            \"gesture\": [gesture_names[i % 18] for i in range(100)],\n        }\n    )\n    dummy_submission.write_parquet(\"submission.parquet\")\n    print(f\"Dummy submission.parquet created with shape {dummy_submission.shape}\")"}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12"}}, "nbformat": 4, "nbformat_minor": 4}