{"cells": [{"cell_type": "markdown", "metadata": {}, "source": "# CMI V14 Corrected - \u6b63\u78ba\u306aV12\u7279\u5fb4\u91cf\u5b9f\u88c5\n\nV12\u30e2\u30c7\u30eb\u306e\u7279\u5fb4\u91cf\u4e0d\u6574\u5408\u3092\u4fee\u6b63\u3057\u305f\u78ba\u5b9f\u306a\u30d9\u30fc\u30b9\u30e9\u30a4\u30f3\n- V12\u671f\u5f85\u7279\u5fb4\u91cf70\u500b\u3092\u6b63\u78ba\u306b\u5b9f\u88c5\n- \u5b9f\u30c7\u30fc\u30bf\u306e\u307f\u3067\u306e\u5b89\u5b9a\u3057\u305f\u63a8\u8ad6"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "import os\nimport numpy as np\nimport pandas as pd\nimport polars as pl\nimport pickle\nimport warnings\nimport kaggle_evaluation.cmi_inference_server\n\nwarnings.filterwarnings(\"ignore\")\n\n# \u74b0\u5883\u5224\u5b9a\nIS_KAGGLE = (\n    os.getenv('KAGGLE_IS_COMPETITION_RERUN') is not None or\n    os.getenv('KAGGLE_KERNEL_RUN_TYPE') is not None or\n    os.path.exists('/kaggle/input')\n)\n\nprint(f\"Running on Kaggle: {IS_KAGGLE}\")\n\n# \u30e2\u30c7\u30eb\u30d1\u30b9\nV12_MODEL_PATH = \"/kaggle/input/cmi-v12-real-data-models\"\nprint(\"Loading V14 corrected models...\")"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "import lightgbm as lgb\nimport xgboost as xgb\nfrom catboost import CatBoostClassifier\nimport joblib\n\n# \u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u540d\u5b9a\u7fa9\nGESTURE_NAMES = [\n    \"Wave hello\",\n    \"Text on phone\",\n    \"Raise hand\",\n    \"Put hand to mouth\",\n    \"Point\",\n    \"Clap\",\n    \"Shake head\",\n    \"Nod head\",\n    \"Check watch or wrist\",\n    \"Cross arms\",\n    \"Adjust glasses\",\n    \"Touch face\",\n    \"Scratch head\",\n    \"Brush hair\",\n    \"Stretch\",\n    \"Yawn\",\n    \"Take a photo\",\n    \"Other gesture\",\n]\n\n# \u30e2\u30c7\u30eb\u3068\u30e1\u30bf\u30c7\u30fc\u30bf\u306e\u30ed\u30fc\u30c9\nprint(\"Loading V12 models...\")\nlgb_model = lgb.Booster(model_file=f\"{V12_MODEL_PATH}/lgb_model_v12_final.txt\")\nxgb_model = xgb.Booster()\nxgb_model.load_model(f\"{V12_MODEL_PATH}/xgb_model_v12_final.json\")\ncat_model = CatBoostClassifier()\ncat_model.load_model(f\"{V12_MODEL_PATH}/cat_model_v12_final.cbm\")\n\n# \u30b9\u30b1\u30fc\u30e9\u30fc\u3068\u7279\u5fb4\u91cf\u540d\u306e\u30ed\u30fc\u30c9\nscaler = joblib.load(f\"{V12_MODEL_PATH}/scaler_v12.pkl\")\nfeature_names = joblib.load(f\"{V12_MODEL_PATH}/feature_names_v12.pkl\")\n\nprint(f\"Models loaded. Expected features: {len(feature_names)}\")\nprint(f\"First 5 features: {feature_names[:5]}\")\nprint(f\"Last 5 features: {feature_names[-5:]}\")"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "def extract_v12_compatible_features(seq_df):\n    \"\"\"V12\u30e2\u30c7\u30eb\u3068\u5b8c\u5168\u306b\u4e92\u63db\u6027\u306e\u3042\u308b\u7279\u5fb4\u91cf\u62bd\u51fa\uff0870\u500b\u306e\u7279\u5fb4\u91cf\uff09\"\"\"\n    features = {}\n\n    # Polars\u306e\u5834\u5408\u306fPandas\u306b\u5909\u63db\n    if isinstance(seq_df, pl.DataFrame):\n        df = seq_df.to_pandas()\n    else:\n        df = seq_df.copy()\n\n    # Basic info\n    features[\"subject_id\"] = df[\"subject\"].iloc[0] if \"subject\" in df.columns else 0\n    features[\"seq_length\"] = len(df)\n    features[\"seq_length_log\"] = np.log1p(len(df))\n\n    # Sensor features for acc_x, acc_y, acc_z\n    for sensor in [\"acc_x\", \"acc_y\", \"acc_z\"]:\n        if sensor in df.columns:\n            values = df[sensor].values\n            \n            # Basic statistics\n            features[f\"{sensor}_mean\"] = np.mean(values)\n            features[f\"{sensor}_std\"] = np.std(values)\n            features[f\"{sensor}_max\"] = np.max(values)\n            features[f\"{sensor}_min\"] = np.min(values)\n            features[f\"{sensor}_range\"] = np.max(values) - np.min(values)\n            features[f\"{sensor}_skew\"] = pd.Series(values).skew() if len(values) > 1 else 0\n            features[f\"{sensor}_kurt\"] = pd.Series(values).kurtosis() if len(values) > 1 else 0\n            \n            # Quantiles\n            features[f\"{sensor}_q25\"] = np.percentile(values, 25)\n            features[f\"{sensor}_q50\"] = np.percentile(values, 50)\n            features[f\"{sensor}_q75\"] = np.percentile(values, 75)\n            features[f\"{sensor}_iqr\"] = features[f\"{sensor}_q75\"] - features[f\"{sensor}_q25\"]\n            \n            # FFT features\n            if len(values) > 1:\n                fft = np.abs(np.fft.fft(values))\n                features[f\"{sensor}_fft_max\"] = np.max(fft)\n                features[f\"{sensor}_fft_mean\"] = np.mean(fft)\n                features[f\"{sensor}_fft_std\"] = np.std(fft)\n                features[f\"{sensor}_fft_energy\"] = np.sum(fft**2)\n                features[f\"{sensor}_dominant_freq\"] = np.argmax(fft)\n            else:\n                features[f\"{sensor}_fft_max\"] = 0\n                features[f\"{sensor}_fft_mean\"] = 0\n                features[f\"{sensor}_fft_std\"] = 0\n                features[f\"{sensor}_fft_energy\"] = 0\n                features[f\"{sensor}_dominant_freq\"] = 0\n            \n            # Jerk features\n            if len(values) > 1:\n                jerk = np.diff(values)\n                features[f\"{sensor}_jerk_mean\"] = np.mean(jerk)\n                features[f\"{sensor}_jerk_std\"] = np.std(jerk)\n                features[f\"{sensor}_jerk_max\"] = np.max(np.abs(jerk))\n            else:\n                features[f\"{sensor}_jerk_mean\"] = 0\n                features[f\"{sensor}_jerk_std\"] = 0\n                features[f\"{sensor}_jerk_max\"] = 0\n            \n            # Zero crossing\n            features[f\"{sensor}_zero_cross\"] = np.sum(np.diff(np.sign(values)) != 0) if len(values) > 1 else 0\n        else:\n            # \u30bb\u30f3\u30b5\u30fc\u304c\u5b58\u5728\u3057\u306a\u3044\u5834\u5408\u306f\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\n            for suffix in [\"_mean\", \"_std\", \"_max\", \"_min\", \"_range\", \"_skew\", \"_kurt\", \n                          \"_q25\", \"_q50\", \"_q75\", \"_iqr\", \"_fft_max\", \"_fft_mean\", \"_fft_std\", \n                          \"_fft_energy\", \"_dominant_freq\", \"_jerk_mean\", \"_jerk_std\", \"_jerk_max\", \"_zero_cross\"]:\n                features[f\"{sensor}{suffix}\"] = 0\n\n    # Magnitude features\n    if all(col in df.columns for col in [\"acc_x\", \"acc_y\", \"acc_z\"]):\n        acc_mag = np.sqrt(df[\"acc_x\"]**2 + df[\"acc_y\"]**2 + df[\"acc_z\"]**2)\n        features[\"acc_magnitude_mean\"] = np.mean(acc_mag)\n        features[\"acc_magnitude_std\"] = np.std(acc_mag)\n        features[\"acc_magnitude_max\"] = np.max(acc_mag)\n        features[\"acc_magnitude_energy\"] = np.sum(acc_mag**2)\n        \n        # Linear acceleration (gravity removed)\n        gravity = np.array([np.mean(df[\"acc_x\"]), np.mean(df[\"acc_y\"]), np.mean(df[\"acc_z\"])])\n        linear_acc = acc_mag - np.linalg.norm(gravity)\n        features[\"linear_acc_mean\"] = np.mean(linear_acc)\n        features[\"linear_acc_std\"] = np.std(linear_acc)\n        features[\"linear_acc_max\"] = np.max(np.abs(linear_acc))\n    else:\n        features[\"acc_magnitude_mean\"] = 0\n        features[\"acc_magnitude_std\"] = 0\n        features[\"acc_magnitude_max\"] = 0\n        features[\"acc_magnitude_energy\"] = 0\n        features[\"linear_acc_mean\"] = 0\n        features[\"linear_acc_std\"] = 0\n        features[\"linear_acc_max\"] = 0\n\n    return features\n\nprint(\"V12-compatible feature extraction function defined.\")"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    \"\"\"V14\u4fee\u6b63\u7248: V12\u30e2\u30c7\u30eb\u3068\u5b8c\u5168\u4e92\u63db\u306e\u4e88\u6e2c\u95a2\u6570\"\"\"\n    \n    try:\n        # \u7279\u5fb4\u91cf\u62bd\u51fa\n        features = extract_v12_compatible_features(sequence)\n        \n        # DataFrame\u306b\u5909\u63db\n        X = pd.DataFrame([features])\n        \n        # V12\u671f\u5f85\u7279\u5fb4\u91cf\u306e\u9806\u5e8f\u3067\u6574\u7406\n        X_aligned = pd.DataFrame(index=X.index)\n        for feature_name in feature_names:\n            if feature_name in X.columns:\n                X_aligned[feature_name] = X[feature_name]\n            else:\n                X_aligned[feature_name] = 0  # \u6b20\u640d\u7279\u5fb4\u91cf\u306f\u30bc\u30ed\u3067\u57cb\u3081\u308b\n        \n        print(f\"Feature alignment: Expected {len(feature_names)}, Got {len(X_aligned.columns)}\")\n        \n        # \u30b9\u30b1\u30fc\u30ea\u30f3\u30b0\n        X_scaled = scaler.transform(X_aligned)\n        \n        # \u4e88\u6e2c\n        pred_lgb = lgb_model.predict(X_scaled, num_iteration=lgb_model.best_iteration)[0]\n        \n        dmatrix = xgb.DMatrix(X_scaled, feature_names=feature_names)\n        pred_xgb = xgb_model.predict(dmatrix)[0]\n        \n        pred_cat = cat_model.predict_proba(X_scaled)[0]\n        \n        # \u30a2\u30f3\u30b5\u30f3\u30d6\u30eb (V12\u3068\u540c\u3058\u91cd\u307f)\n        ensemble_probs = 0.4 * pred_lgb + 0.3 * pred_xgb + 0.3 * pred_cat\n        \n        # \u6700\u3082\u78ba\u7387\u306e\u9ad8\u3044\u30af\u30e9\u30b9\n        pred_class = np.argmax(ensemble_probs)\n        \n        # \u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u540d\u3092\u8fd4\u3059\n        gesture_name = GESTURE_NAMES[pred_class] if pred_class < len(GESTURE_NAMES) else \"Wave hello\"\n        \n        print(f\"Predicted: {gesture_name} (class {pred_class}, prob {ensemble_probs[pred_class]:.3f})\")\n        \n        return gesture_name\n    \n    except Exception as e:\n        print(f\"Prediction error: {e}\")\n        return \"Wave hello\"  # \u30d5\u30a9\u30fc\u30eb\u30d0\u30c3\u30af\n\nprint(\"V14 prediction function defined.\")"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "# \u63a8\u8ad6\u30b5\u30fc\u30d0\u30fc\u8a2d\u5b9a\nprint(\"Setting up CMI Inference Server...\")\ninference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n\nif IS_KAGGLE:\n    print(\"Competition environment detected - serving predictions...\")\n    inference_server.serve()\nelse:\n    print(\"Local environment - running gateway test...\")\n    # \u30ed\u30fc\u30ab\u30eb\u30c6\u30b9\u30c8\u7528\n    test_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    \n    try:\n        inference_server.run_local_gateway(data_paths=test_data_paths)\n    except Exception as e:\n        print(f\"Local test failed: {e}\")\n        print(\"This is expected in a local environment without test data.\")\n\nprint(\"V14 Corrected inference complete!\")"}], "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.8.5"}}, "nbformat": 4, "nbformat_minor": 4}