{"cells": [{"cell_type": "markdown", "metadata": {}, "source": "# CMI V12: \u5b9f\u30c7\u30fc\u30bf\u5c02\u7528\u30e2\u30c7\u30eb\uff08\u30cf\u30a4\u30d6\u30ea\u30c3\u30c9\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\u7528\uff09\n\n100%\u5b9f\u30c7\u30fc\u30bf\u3067\u30c8\u30ec\u30fc\u30cb\u30f3\u30b0\u3059\u308b\u9ad8\u7cbe\u5ea6\u30e2\u30c7\u30eb"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "import numpy as np\nimport pandas as pd\nimport os\nfrom pathlib import Path\nimport json\nimport pickle\nimport warnings\nfrom sklearn.model_selection import train_test_split, StratifiedKFold\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.metrics import accuracy_score, classification_report\nimport lightgbm as lgb\nimport xgboost as xgb\nfrom catboost import CatBoostClassifier\n\nwarnings.filterwarnings('ignore')\nprint('Libraries imported successfully')"}, {"cell_type": "markdown", "metadata": {}, "source": "## 1. \u30c7\u30fc\u30bf\u8aad\u307f\u8fbc\u307f\uff08100%\u5b9f\u30c7\u30fc\u30bf\uff09"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "# \u30c7\u30fc\u30bf\u30d1\u30b9\u8a2d\u5b9a\nDATA_DIR = Path('/kaggle/input/cmi-detect-behavior-with-sensor-data')\n\n# train.csv\u306e\u8aad\u307f\u8fbc\u307f\nprint('Loading real training data...')\ntrain_data = pd.read_csv(DATA_DIR / 'train.csv')\nprint(f'  Loaded train.csv: {len(train_data)} rows')\n\n# sequence_id\u3067\u30b0\u30eb\u30fc\u30d7\u5316\u3057\u3066\u30e1\u30bf\u30c7\u30fc\u30bf\u4f5c\u6210\ntrain_metadata = train_data.groupby('sequence_id').agg({\n    'subject': 'first',\n    'gesture': 'first',\n    'sequence_counter': 'count'\n}).reset_index()\ntrain_metadata.columns = ['sequence_id', 'subject', 'gesture', 'sequence_length']\n\n# \u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u306e\u30e9\u30d9\u30eb\u30de\u30c3\u30d4\u30f3\u30b0\ngesture_labels = sorted(train_metadata['gesture'].unique())\ngesture_to_id = {label: i for i, label in enumerate(gesture_labels)}\nid_to_gesture = {i: label for label, i in gesture_to_id.items()}\n\nprint(f'\\nData Summary:')\nprint(f'  Total sequences: {len(train_metadata)}')\nprint(f'  Gesture labels: {len(gesture_labels)} types')\nprint(f'  Average sequence length: {train_metadata[\"sequence_length\"].mean():.1f}')\nprint(f'\\nGesture distribution:')\nprint(train_metadata['gesture'].value_counts())"}, {"cell_type": "markdown", "metadata": {}, "source": "## 2. \u9ad8\u5ea6\u306a\u7279\u5fb4\u91cf\u30a8\u30f3\u30b8\u30cb\u30a2\u30ea\u30f3\u30b0"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "def extract_advanced_features(df, seq_id, metadata_row):\n    \"\"\"\u9ad8\u5ea6\u306a\u7279\u5fb4\u91cf\u62bd\u51fa\uff08\u5b9f\u30c7\u30fc\u30bf\u7528\u306b\u6700\u9069\u5316\uff09\"\"\"\n    features = {}\n    \n    # \u30e1\u30bf\u30c7\u30fc\u30bf\u7279\u5fb4\n    features['subject_id'] = hash(metadata_row['subject']) % 1000\n    features['seq_length'] = len(df)\n    features['seq_length_log'] = np.log1p(len(df))\n    \n    # \u52a0\u901f\u5ea6\u8a08\u7279\u5fb4\uff08\u62e1\u5f35\u7248\uff09\n    for axis in ['x', 'y', 'z']:\n        col = f'acc_{axis}'\n        if col in df.columns:\n            values = df[col].values\n            \n            # \u57fa\u672c\u7d71\u8a08\u91cf\n            features[f'acc_{axis}_mean'] = np.mean(values)\n            features[f'acc_{axis}_std'] = np.std(values)\n            features[f'acc_{axis}_max'] = np.max(values)\n            features[f'acc_{axis}_min'] = np.min(values)\n            features[f'acc_{axis}_range'] = np.ptp(values)\n            features[f'acc_{axis}_skew'] = pd.Series(values).skew()\n            features[f'acc_{axis}_kurt'] = pd.Series(values).kurt()\n            \n            # \u30d1\u30fc\u30bb\u30f3\u30bf\u30a4\u30eb\n            features[f'acc_{axis}_q25'] = np.percentile(values, 25)\n            features[f'acc_{axis}_q50'] = np.percentile(values, 50)\n            features[f'acc_{axis}_q75'] = np.percentile(values, 75)\n            features[f'acc_{axis}_iqr'] = features[f'acc_{axis}_q75'] - features[f'acc_{axis}_q25']\n            \n            # \u5468\u6ce2\u6570\u9818\u57df\u7279\u5fb4\uff08\u62e1\u5f35\uff09\n            fft_vals = np.abs(np.fft.fft(values))[:len(values)//2]\n            if len(fft_vals) > 0:\n                features[f'acc_{axis}_fft_max'] = np.max(fft_vals)\n                features[f'acc_{axis}_fft_mean'] = np.mean(fft_vals)\n                features[f'acc_{axis}_fft_std'] = np.std(fft_vals)\n                features[f'acc_{axis}_fft_energy'] = np.sum(fft_vals**2)\n                # \u4e3b\u8981\u5468\u6ce2\u6570\n                features[f'acc_{axis}_dominant_freq'] = np.argmax(fft_vals)\n            else:\n                features[f'acc_{axis}_fft_max'] = 0\n                features[f'acc_{axis}_fft_mean'] = 0\n                features[f'acc_{axis}_fft_std'] = 0\n                features[f'acc_{axis}_fft_energy'] = 0\n                features[f'acc_{axis}_dominant_freq'] = 0\n            \n            # \u30b8\u30e3\u30fc\u30af\uff08\u52a0\u901f\u5ea6\u306e\u5909\u5316\u7387\uff09\n            if len(values) > 1:\n                jerk = np.diff(values)\n                features[f'acc_{axis}_jerk_mean'] = np.mean(np.abs(jerk))\n                features[f'acc_{axis}_jerk_std'] = np.std(jerk)\n                features[f'acc_{axis}_jerk_max'] = np.max(np.abs(jerk))\n            else:\n                features[f'acc_{axis}_jerk_mean'] = 0\n                features[f'acc_{axis}_jerk_std'] = 0\n                features[f'acc_{axis}_jerk_max'] = 0\n            \n            # \u30bc\u30ed\u4ea4\u5dee\u7387\n            features[f'acc_{axis}_zero_cross'] = np.sum(np.diff(np.sign(values)) != 0)\n    \n    # \u52a0\u901f\u5ea6\u306e\u5927\u304d\u3055\u3068\u91cd\u529b\u9664\u53bb\n    if all(f'acc_{axis}' in df.columns for axis in ['x', 'y', 'z']):\n        # \u52a0\u901f\u5ea6\u30d9\u30af\u30c8\u30eb\u306e\u5927\u304d\u3055\n        acc_magnitude = np.sqrt(df['acc_x']**2 + df['acc_y']**2 + df['acc_z']**2)\n        features['acc_magnitude_mean'] = np.mean(acc_magnitude)\n        features['acc_magnitude_std'] = np.std(acc_magnitude)\n        features['acc_magnitude_max'] = np.max(acc_magnitude)\n        features['acc_magnitude_energy'] = np.sum(acc_magnitude**2)\n        \n        # \u91cd\u529b\u6210\u5206\u306e\u63a8\u5b9a\u3068\u9664\u53bb\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        linear_magnitude = np.sqrt(linear_acc_x**2 + linear_acc_y**2 + linear_acc_z**2)\n        features['linear_acc_mean'] = np.mean(linear_magnitude)\n        features['linear_acc_std'] = np.std(linear_magnitude)\n        features['linear_acc_max'] = np.max(linear_magnitude)\n    \n    # \u30b8\u30e3\u30a4\u30ed\u30b9\u30b3\u30fc\u30d7\u7279\u5fb4\uff08\u62e1\u5f35\u7248\uff09\n    for axis in ['x', 'y', 'z']:\n        col = f'gyr_{axis}'\n        if col in df.columns:\n            values = df[col].values\n            features[f'gyr_{axis}_mean'] = np.mean(values)\n            features[f'gyr_{axis}_std'] = np.std(values)\n            features[f'gyr_{axis}_max'] = np.max(values)\n            features[f'gyr_{axis}_min'] = np.min(values)\n            features[f'gyr_{axis}_energy'] = np.sum(values**2)\n            features[f'gyr_{axis}_rms'] = np.sqrt(np.mean(values**2))\n            \n            # \u89d2\u52a0\u901f\u5ea6\n            if len(values) > 1:\n                angular_acc = np.diff(values)\n                features[f'gyr_{axis}_angular_acc_mean'] = np.mean(np.abs(angular_acc))\n                features[f'gyr_{axis}_angular_acc_max'] = np.max(np.abs(angular_acc))\n            else:\n                features[f'gyr_{axis}_angular_acc_mean'] = 0\n                features[f'gyr_{axis}_angular_acc_max'] = 0\n    \n    # \u89d2\u901f\u5ea6\u306e\u5927\u304d\u3055\n    if all(f'gyr_{axis}' in df.columns for axis in ['x', 'y', 'z']):\n        gyr_magnitude = np.sqrt(df['gyr_x']**2 + df['gyr_y']**2 + df['gyr_z']**2)\n        features['gyr_magnitude_mean'] = np.mean(gyr_magnitude)\n        features['gyr_magnitude_std'] = np.std(gyr_magnitude)\n        features['gyr_magnitude_max'] = np.max(gyr_magnitude)\n        features['gyr_magnitude_energy'] = np.sum(gyr_magnitude**2)\n    \n    # \u30af\u30a9\u30fc\u30bf\u30cb\u30aa\u30f3\u7279\u5fb4\uff08\u59ff\u52e2\u63a8\u5b9a\uff09\n    for comp in ['w', 'x', 'y', 'z']:\n        col = f'quat_{comp}'\n        if col in df.columns:\n            values = df[col].values\n            features[f'quat_{comp}_mean'] = np.mean(values)\n            features[f'quat_{comp}_std'] = np.std(values)\n            features[f'quat_{comp}_change'] = values[-1] - values[0] if len(values) > 0 else 0\n            features[f'quat_{comp}_range'] = np.ptp(values)\n    \n    # \u30aa\u30a4\u30e9\u30fc\u89d2\u3078\u306e\u5909\u63db\uff08\u8fd1\u4f3c\uff09\n    if all(f'quat_{comp}' in df.columns for comp in ['w', 'x', 'y', 'z']):\n        qw = df['quat_w'].mean()\n        qx = df['quat_x'].mean()\n        qy = df['quat_y'].mean()\n        qz = df['quat_z'].mean()\n        \n        # Roll\n        features['euler_roll'] = np.arctan2(2*(qw*qx + qy*qz), 1 - 2*(qx**2 + qy**2))\n        # Pitch\n        features['euler_pitch'] = np.arcsin(2*(qw*qy - qz*qx))\n        # Yaw\n        features['euler_yaw'] = np.arctan2(2*(qw*qz + qx*qy), 1 - 2*(qy**2 + qz**2))\n    \n    # ToF\u30bb\u30f3\u30b5\u30fc\u7279\u5fb4\uff08\u8ddd\u96e2\u30bb\u30f3\u30b5\u30fc\uff09\n    tof_stats = []\n    for i in range(8):\n        col = f'tof_{i}'\n        if col in df.columns:\n            values = df[col].values\n            tof_stats.extend([\n                np.mean(values),\n                np.std(values),\n                np.median(values),\n                np.min(values),\n                np.max(values)\n            ])\n    \n    # ToF\u7d71\u8a08\u91cf\u3092\u4e3b\u6210\u5206\u3068\u3057\u3066\u4fdd\u5b58\n    if tof_stats:\n        # \u6700\u521d\u306e10\u500b\u306e\u7d71\u8a08\u91cf\u3092\u4f7f\u7528\n        for i in range(min(10, len(tof_stats))):\n            features[f'tof_stat_{i}'] = tof_stats[i]\n        \n        # ToF\u5168\u4f53\u306e\u7d71\u8a08\n        features['tof_global_mean'] = np.mean(tof_stats)\n        features['tof_global_std'] = np.std(tof_stats)\n        features['tof_global_range'] = np.ptp(tof_stats)\n    \n    # \u30bb\u30f3\u30b5\u30fc\u9593\u306e\u76f8\u95a2\u7279\u5fb4\n    if all(f'acc_{axis}' in df.columns for axis in ['x', 'y', 'z']) and \\\n       all(f'gyr_{axis}' in df.columns for axis in ['x', 'y', 'z']):\n        # \u52a0\u901f\u5ea6\u3068\u30b8\u30e3\u30a4\u30ed\u306e\u76f8\u95a2\n        for axis in ['x', 'y', 'z']:\n            corr = np.corrcoef(df[f'acc_{axis}'], df[f'gyr_{axis}'])[0, 1]\n            features[f'acc_gyr_corr_{axis}'] = corr if not np.isnan(corr) else 0\n    \n    # \u30e9\u30d9\u30eb\uff08\u6574\u6570ID\uff09\n    features['gesture'] = gesture_to_id[metadata_row['gesture']]\n    \n    return features\n\nprint('Advanced feature extractor ready')"}, {"cell_type": "markdown", "metadata": {}, "source": "## 3. \u5168\u5b9f\u30c7\u30fc\u30bf\u304b\u3089\u7279\u5fb4\u91cf\u62bd\u51fa"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "# \u5168\u5b9f\u30c7\u30fc\u30bf\u304b\u3089\u7279\u5fb4\u91cf\u62bd\u51fa\nprint(f'Extracting features from {len(train_metadata)} real sequences...')\n\nreal_features = []\nfailed_count = 0\n\nfor idx, row in train_metadata.iterrows():\n    try:\n        # train.csv\u304b\u3089\u8a72\u5f53\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\n        seq_data = train_data[train_data['sequence_id'] == row['sequence_id']]\n        if len(seq_data) > 0:\n            features = extract_advanced_features(seq_data, row['sequence_id'], row)\n            real_features.append(features)\n    except Exception as e:\n        failed_count += 1\n        if failed_count <= 3:\n            print(f'  Failed: {row[\"sequence_id\"]}: {e}')\n        continue\n    \n    # \u9032\u6357\u8868\u793a\n    if (idx + 1) % 1000 == 0:\n        print(f'  Processed {idx + 1}/{len(train_metadata)} sequences')\n\nprint(f'\\nFeature extraction completed:')\nprint(f'  Success: {len(real_features)} sequences')\nif failed_count > 0:\n    print(f'  Failed: {failed_count} sequences')\n\n# DataFrame\u306b\u5909\u63db\nfeature_df = pd.DataFrame(real_features)\nfeature_df = feature_df.fillna(0)\n\nprint(f'\\nFeature matrix shape: {feature_df.shape}')\nprint(f'Features: {feature_df.shape[1] - 1} dimensions')"}, {"cell_type": "markdown", "metadata": {}, "source": "## 4. \u30e2\u30c7\u30eb\u30c8\u30ec\u30fc\u30cb\u30f3\u30b0\uff085-Fold CV\uff09"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "# \u7279\u5fb4\u91cf\u3068\u30e9\u30d9\u30eb\u306e\u5206\u96e2\nX = feature_df.drop('gesture', axis=1)\ny = feature_df['gesture']\n\n# \u30b9\u30b1\u30fc\u30ea\u30f3\u30b0\nscaler = StandardScaler()\nX_scaled = scaler.fit_transform(X)\n\n# 5-Fold Cross Validation\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n\n# \u691c\u8a3c\u30b9\u30b3\u30a2\u4fdd\u5b58\u7528\ncv_scores = {\n    'lgb': [],\n    'xgb': [],\n    'cat': [],\n    'ensemble': []\n}\n\n# \u5168Fold\u306e\u30e2\u30c7\u30eb\u3092\u4fdd\u5b58\uff08\u6700\u5f8c\u306b\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\uff09\nall_models = {\n    'lgb': [],\n    'xgb': [],\n    'cat': []\n}\n\nprint('Starting 5-Fold Cross Validation...')\nprint('=' * 50)"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "for fold, (train_idx, val_idx) in enumerate(skf.split(X_scaled, y), 1):\n    print(f'\\nFold {fold}/5:')\n    print('-' * 30)\n    \n    X_train, X_val = X_scaled[train_idx], X_scaled[val_idx]\n    y_train, y_val = y.iloc[train_idx], y.iloc[val_idx]\n    \n    # LightGBM\n    lgb_params = {\n        'objective': 'multiclass',\n        'num_class': 18,\n        'metric': 'multi_logloss',\n        'boosting_type': 'gbdt',\n        'num_leaves': 100,\n        'learning_rate': 0.05,\n        'feature_fraction': 0.8,\n        'bagging_fraction': 0.8,\n        'bagging_freq': 5,\n        'min_child_samples': 20,\n        'verbose': -1,\n        'seed': 42 + fold,\n        'n_jobs': -1\n    }\n    \n    lgb_train = lgb.Dataset(X_train, label=y_train)\n    lgb_val = lgb.Dataset(X_val, label=y_val, reference=lgb_train)\n    \n    lgb_model = lgb.train(\n        lgb_params,\n        lgb_train,\n        valid_sets=[lgb_val],\n        num_boost_round=500,\n        callbacks=[lgb.early_stopping(100), lgb.log_evaluation(0)]\n    )\n    \n    lgb_pred = lgb_model.predict(X_val, num_iteration=lgb_model.best_iteration)\n    lgb_pred_class = np.argmax(lgb_pred, axis=1)\n    lgb_acc = accuracy_score(y_val, lgb_pred_class)\n    cv_scores['lgb'].append(lgb_acc)\n    all_models['lgb'].append(lgb_model)\n    print(f'  LightGBM: {lgb_acc:.4f}')\n    \n    # XGBoost\n    xgb_params = {\n        'objective': 'multi:softprob',\n        'num_class': 18,\n        'max_depth': 8,\n        'learning_rate': 0.05,\n        'subsample': 0.8,\n        'colsample_bytree': 0.8,\n        'min_child_weight': 3,\n        'seed': 42 + fold,\n        'n_jobs': -1,\n        'eval_metric': 'mlogloss'\n    }\n    \n    dtrain = xgb.DMatrix(X_train, label=y_train)\n    dval = xgb.DMatrix(X_val, label=y_val)\n    \n    xgb_model = xgb.train(\n        xgb_params,\n        dtrain,\n        num_boost_round=500,\n        evals=[(dval, 'val')],\n        early_stopping_rounds=100,\n        verbose_eval=False\n    )\n    \n    xgb_pred = xgb_model.predict(dval)\n    xgb_pred_class = np.argmax(xgb_pred, axis=1)\n    xgb_acc = accuracy_score(y_val, xgb_pred_class)\n    cv_scores['xgb'].append(xgb_acc)\n    all_models['xgb'].append(xgb_model)\n    print(f'  XGBoost: {xgb_acc:.4f}')\n    \n    # CatBoost\n    cat_model = CatBoostClassifier(\n        iterations=500,\n        learning_rate=0.05,\n        depth=8,\n        loss_function='MultiClass',\n        classes_count=18,\n        random_seed=42 + fold,\n        verbose=False,\n        early_stopping_rounds=100,\n        task_type='GPU' if os.path.exists('/proc/driver/nvidia/version') else 'CPU'\n    )\n    \n    cat_model.fit(\n        X_train, y_train,\n        eval_set=(X_val, y_val),\n        use_best_model=True\n    )\n    \n    cat_pred_class = cat_model.predict(X_val)\n    cat_acc = accuracy_score(y_val, cat_pred_class)\n    cv_scores['cat'].append(cat_acc)\n    all_models['cat'].append(cat_model)\n    print(f'  CatBoost: {cat_acc:.4f}')\n    \n    # \u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\uff08Fold\u5185\uff09\n    lgb_weight = 0.4\n    xgb_weight = 0.3\n    cat_weight = 0.3\n    \n    ensemble_proba = (\n        lgb_weight * lgb_pred + \n        xgb_weight * xgb_pred + \n        cat_weight * cat_model.predict_proba(X_val)\n    )\n    ensemble_pred = np.argmax(ensemble_proba, axis=1)\n    ensemble_acc = accuracy_score(y_val, ensemble_pred)\n    cv_scores['ensemble'].append(ensemble_acc)\n    print(f'  Ensemble: {ensemble_acc:.4f}')"}, {"cell_type": "markdown", "metadata": {}, "source": "## 5. Cross Validation\u7d50\u679c"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "print('\\n' + '=' * 50)\nprint('Cross Validation Results:')\nprint('=' * 50)\n\nfor model_name in ['lgb', 'xgb', 'cat', 'ensemble']:\n    scores = cv_scores[model_name]\n    print(f'\\n{model_name.upper()}:')\n    print(f'  Folds: {scores}')\n    print(f'  Mean: {np.mean(scores):.4f} \u00b1 {np.std(scores):.4f}')\n\n# \u6700\u7d42\u7684\u306a\u5e73\u5747\u30b9\u30b3\u30a2\nfinal_score = np.mean(cv_scores['ensemble'])\nprint(f'\\n\\nFinal CV Score (Ensemble): {final_score:.4f}')"}, {"cell_type": "markdown", "metadata": {}, "source": "## 6. \u5168\u30c7\u30fc\u30bf\u3067\u6700\u7d42\u30e2\u30c7\u30eb\u3092\u30c8\u30ec\u30fc\u30cb\u30f3\u30b0"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "print('Training final models on full dataset...')\nprint('=' * 50)\n\n# \u5168\u30c7\u30fc\u30bf\u3067\u30c8\u30ec\u30fc\u30cb\u30f3\u30b0\nX_full = X_scaled\ny_full = y\n\n# LightGBM\u6700\u7d42\u30e2\u30c7\u30eb\nprint('Training final LightGBM...')\nlgb_train_full = lgb.Dataset(X_full, label=y_full)\nlgb_final = lgb.train(\n    lgb_params,\n    lgb_train_full,\n    num_boost_round=400,  # CV\u7d50\u679c\u304b\u3089\u6c7a\u5b9a\n    callbacks=[lgb.log_evaluation(100)]\n)\n\n# XGBoost\u6700\u7d42\u30e2\u30c7\u30eb\nprint('Training final XGBoost...')\ndtrain_full = xgb.DMatrix(X_full, label=y_full)\nxgb_final = xgb.train(\n    xgb_params,\n    dtrain_full,\n    num_boost_round=400,\n    verbose_eval=100\n)\n\n# CatBoost\u6700\u7d42\u30e2\u30c7\u30eb\nprint('Training final CatBoost...')\ncat_final = CatBoostClassifier(\n    iterations=400,\n    learning_rate=0.05,\n    depth=8,\n    loss_function='MultiClass',\n    classes_count=18,\n    random_seed=42,\n    verbose=100,\n    task_type='GPU' if os.path.exists('/proc/driver/nvidia/version') else 'CPU'\n)\ncat_final.fit(X_full, y_full)\n\nprint('\\nAll models trained successfully!')"}, {"cell_type": "markdown", "metadata": {}, "source": "## 7. \u30e2\u30c7\u30eb\u306e\u4fdd\u5b58"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "# \u30e2\u30c7\u30eb\u4fdd\u5b58\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\nmodel_dir = Path('/kaggle/working/models_v12')\nmodel_dir.mkdir(exist_ok=True)\n\n# \u6700\u7d42\u30e2\u30c7\u30eb\u3092\u4fdd\u5b58\nlgb_final.save_model(str(model_dir / 'lgb_model_v12_final.txt'))\nxgb_final.save_model(str(model_dir / 'xgb_model_v12_final.json'))\ncat_final.save_model(str(model_dir / 'cat_model_v12_final.cbm'))\n\n# CV Fold\u30e2\u30c7\u30eb\u3082\u4fdd\u5b58\uff08\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb\u7528\uff09\nfor fold in range(5):\n    all_models['lgb'][fold].save_model(str(model_dir / f'lgb_model_v12_fold{fold}.txt'))\n    all_models['xgb'][fold].save_model(str(model_dir / f'xgb_model_v12_fold{fold}.json'))\n    all_models['cat'][fold].save_model(str(model_dir / f'cat_model_v12_fold{fold}.cbm'))\n\n# \u30b9\u30b1\u30fc\u30e9\u30fc\u3068\u7279\u5fb4\u91cf\u540d\u3092\u4fdd\u5b58\nwith open(model_dir / 'scaler_v12.pkl', 'wb') as f:\n    pickle.dump(scaler, f)\n\nwith open(model_dir / 'feature_names_v12.pkl', 'wb') as f:\n    pickle.dump(list(X.columns), f)\n\n# \u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u30de\u30c3\u30d4\u30f3\u30b0\u3092\u4fdd\u5b58\nwith open(model_dir / 'gesture_mapping_v12.pkl', 'wb') as f:\n    pickle.dump({'gesture_to_id': gesture_to_id, 'id_to_gesture': id_to_gesture}, f)\n\n# \u30e2\u30c7\u30eb\u60c5\u5831\nmodel_info = {\n    'version': 'v12_real_data_only',\n    'training_data': {\n        'real_samples': len(feature_df),\n        'synthetic_samples': 0,\n        'total_samples': len(feature_df)\n    },\n    'cv_scores': {\n        'lgb': {\n            'mean': float(np.mean(cv_scores['lgb'])),\n            'std': float(np.std(cv_scores['lgb'])),\n            'folds': [float(s) for s in cv_scores['lgb']]\n        },\n        'xgb': {\n            'mean': float(np.mean(cv_scores['xgb'])),\n            'std': float(np.std(cv_scores['xgb'])),\n            'folds': [float(s) for s in cv_scores['xgb']]\n        },\n        'catboost': {\n            'mean': float(np.mean(cv_scores['cat'])),\n            'std': float(np.std(cv_scores['cat'])),\n            'folds': [float(s) for s in cv_scores['cat']]\n        },\n        'ensemble': {\n            'mean': float(np.mean(cv_scores['ensemble'])),\n            'std': float(np.std(cv_scores['ensemble'])),\n            'folds': [float(s) for s in cv_scores['ensemble']]\n        }\n    },\n    'ensemble_weights': {\n        'lgb': 0.4,\n        'xgb': 0.3,\n        'catboost': 0.3\n    },\n    'feature_count': X.shape[1],\n    'n_folds': 5\n}\n\nwith open(model_dir / 'model_info_v12.json', 'w') as f:\n    json.dump(model_info, f, indent=2)\n\nprint(f'\\nModels saved to {model_dir}')\nprint(f'Files created:')\nfor file in sorted(model_dir.glob('*')):\n    print(f'  - {file.name}')"}, {"cell_type": "markdown", "metadata": {}, "source": "## 8. \u6700\u7d42\u30b5\u30de\u30ea\u30fc"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "source": "print('=' * 60)\nprint('V12 \u5b9f\u30c7\u30fc\u30bf\u5c02\u7528\u30e2\u30c7\u30eb - \u30c8\u30ec\u30fc\u30cb\u30f3\u30b0\u5b8c\u4e86')\nprint('=' * 60)\nprint(f'\\n\ud83d\udcca \u30c7\u30fc\u30bf:')\nprint(f'  - \u5b9f\u30c7\u30fc\u30bf: {len(feature_df)} samples (100%)')\nprint(f'  - \u7279\u5fb4\u91cf\u6b21\u5143: {X.shape[1]}')\nprint(f'\\n\ud83c\udfaf Cross Validation\u7d50\u679c:')\nprint(f'  - LightGBM: {np.mean(cv_scores[\"lgb\"]):.2%} \u00b1 {np.std(cv_scores[\"lgb\"]):.2%}')\nprint(f'  - XGBoost: {np.mean(cv_scores[\"xgb\"]):.2%} \u00b1 {np.std(cv_scores[\"xgb\"]):.2%}')\nprint(f'  - CatBoost: {np.mean(cv_scores[\"cat\"]):.2%} \u00b1 {np.std(cv_scores[\"cat\"]):.2%}')\nprint(f'  - Ensemble: {np.mean(cv_scores[\"ensemble\"]):.2%} \u00b1 {np.std(cv_scores[\"ensemble\"]):.2%}')\nprint(f'\\n\ud83d\udcbe \u4fdd\u5b58\u6e08\u307f\u30e2\u30c7\u30eb:')\nprint(f'  - \u6700\u7d42\u30e2\u30c7\u30eb: 3\u500b\uff08LGB, XGB, CatBoost\uff09')\nprint(f'  - Fold\u30e2\u30c7\u30eb: 15\u500b\uff085-Fold \u00d7 3\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0\uff09')\nprint(f'\\n\ud83d\ude80 \u6b21\u306e\u30b9\u30c6\u30c3\u30d7:')\nprint(f'  1. \u30e2\u30c7\u30eb\u3092Kaggle Dataset\u3068\u3057\u3066\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9')\nprint(f'  2. V11\uff08\u5408\u6210\u30c7\u30fc\u30bf\uff09+ V12\uff08\u5b9f\u30c7\u30fc\u30bf\uff09\u306e\u30cf\u30a4\u30d6\u30ea\u30c3\u30c9\u30a2\u30f3\u30b5\u30f3\u30d6\u30eb')\nprint(f'  3. Test Time Augmentation (TTA)\u306e\u5b9f\u88c5')\nprint(f'  4. \u6700\u7d42\u63d0\u51fa')"}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"name": "python", "version": "3.10.0"}}, "nbformat": 4, "nbformat_minor": 4}