{"cells":[{"cell_type":"markdown","metadata":{},"source":"# V13 Hybrid Inference - LightGBM + TensorFlow Ensemble\n\nLightGBMとTensorFlowの予測を組み合わせた最終推論"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"import os\nimport numpy as np\nimport pandas as pd\nfrom pathlib import Path\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Kaggle環境の確認\nIS_KAGGLE = os.path.exists('/kaggle/input')\nprint(f\"Running on Kaggle: {IS_KAGGLE}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# パスの設定\nif IS_KAGGLE:\n    # Kaggle環境\n    DATA_DIR = Path('/kaggle/input/cmi-detect-behavior-with-sensor-data')\n    LGBM_PRED_PATH = Path('/kaggle/input/cmi-bfrb-v13-lgbm-predictions/submission_v13_lgbm.csv')\n    TF_PRED_PATH = Path('/kaggle/input/cmi-bfrb-v13-tf-predictions/submission_v13_tf.csv')\nelse:\n    # ローカル環境\n    DATA_DIR = Path('../../../data/cmi-detect-behavior-with-sensor-data')\n    LGBM_PRED_PATH = Path('./submission_v13_lgbm.csv')\n    TF_PRED_PATH = Path('./submission_v13_tf.csv')\n\nprint(f\"LightGBM predictions: {LGBM_PRED_PATH}\")\nprint(f\"TensorFlow predictions: {TF_PRED_PATH}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 予測ファイルの読み込み\nlgbm_pred = pd.read_csv(LGBM_PRED_PATH)\ntf_pred = pd.read_csv(TF_PRED_PATH)\n\nprint(f\"LightGBM predictions shape: {lgbm_pred.shape}\")\nprint(f\"TensorFlow predictions shape: {tf_pred.shape}\")\n\n# sequence_idの確認\nassert (lgbm_pred['sequence_id'].values == tf_pred['sequence_id'].values).all(), \\\n    \"Sequence IDs don't match between predictions!\"\n\nprint(\"\\nSequence IDs match confirmed\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# クラス名の取得\nclass_names = [col for col in lgbm_pred.columns if col != 'sequence_id']\nprint(f\"Number of classes: {len(class_names)}\")\nprint(f\"Classes: {class_names}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 予測値の確認\nprint(\"\\nLightGBM predictions summary:\")\nprint(lgbm_pred[class_names].describe().loc[['mean', 'std', 'min', 'max']])\n\nprint(\"\\nTensorFlow predictions summary:\")\nprint(tf_pred[class_names].describe().loc[['mean', 'std', 'min', 'max']])"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 重み付き平均によるアンサンブル\n# LB 0.80では通常、TensorFlowの重みを高めに設定\nTF_WEIGHT = 0.7  # TensorFlowの重み\nLGBM_WEIGHT = 0.3  # LightGBMの重み\n\nprint(f\"\\nEnsemble weights:\")\nprint(f\"TensorFlow: {TF_WEIGHT}\")\nprint(f\"LightGBM: {LGBM_WEIGHT}\")\n\n# 重み付き平均の計算\nhybrid_pred = lgbm_pred.copy()\n\nfor class_name in class_names:\n    hybrid_pred[class_name] = (\n        TF_WEIGHT * tf_pred[class_name] + \n        LGBM_WEIGHT * lgbm_pred[class_name]\n    )"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 正規化（念のため）\nrow_sums = hybrid_pred[class_names].sum(axis=1)\nprint(f\"\\nRow sums before normalization:\")\nprint(f\"Min: {row_sums.min():.6f}, Max: {row_sums.max():.6f}\")\n\n# 正規化\nfor class_name in class_names:\n    hybrid_pred[class_name] = hybrid_pred[class_name] / row_sums\n\n# 確認\nrow_sums_after = hybrid_pred[class_names].sum(axis=1)\nprint(f\"\\nRow sums after normalization:\")\nprint(f\"Min: {row_sums_after.min():.6f}, Max: {row_sums_after.max():.6f}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 予測の分布比較\nimport matplotlib.pyplot as plt\n\nfig, axes = plt.subplots(1, 3, figsize=(18, 5))\n\n# LightGBM\nmean_probs_lgbm = lgbm_pred[class_names].mean().sort_values(ascending=False)\naxes[0].bar(range(len(mean_probs_lgbm)), mean_probs_lgbm.values)\naxes[0].set_title('LightGBM Mean Predictions')\naxes[0].set_xlabel('Class Index')\naxes[0].set_ylabel('Mean Probability')\n\n# TensorFlow\nmean_probs_tf = tf_pred[class_names].mean().sort_values(ascending=False)\naxes[1].bar(range(len(mean_probs_tf)), mean_probs_tf.values)\naxes[1].set_title('TensorFlow Mean Predictions')\naxes[1].set_xlabel('Class Index')\n\n# Hybrid\nmean_probs_hybrid = hybrid_pred[class_names].mean().sort_values(ascending=False)\naxes[2].bar(range(len(mean_probs_hybrid)), mean_probs_hybrid.values)\naxes[2].set_title('Hybrid Mean Predictions')\naxes[2].set_xlabel('Class Index')\n\nplt.tight_layout()\nplt.show()\n\n# 上位クラスの表示\nprint(\"\\nTop 5 classes by mean probability (Hybrid):\")\nfor class_name, prob in mean_probs_hybrid.head():\n    print(f\"{class_name}: {prob:.4f}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 異なる重みでの実験\nweight_combinations = [\n    (0.3, 0.7),  # LightGBM重視\n    (0.5, 0.5),  # 均等\n    (0.7, 0.3),  # TensorFlow重視（デフォルト）\n    (0.8, 0.2),  # TensorFlowより重視\n]\n\n# 各重みでの最大確率の平均を計算\nfor tf_w, lgbm_w in weight_combinations:\n    temp_pred = lgbm_pred.copy()\n    \n    for class_name in class_names:\n        temp_pred[class_name] = (\n            tf_w * tf_pred[class_name] + \n            lgbm_w * lgbm_pred[class_name]\n        )\n    \n    # 正規化\n    row_sums = temp_pred[class_names].sum(axis=1)\n    for class_name in class_names:\n        temp_pred[class_name] = temp_pred[class_name] / row_sums\n    \n    # 最大確率の平均\n    max_probs = temp_pred[class_names].max(axis=1)\n    print(f\"TF:{tf_w}, LGBM:{lgbm_w} -> Mean max prob: {max_probs.mean():.4f}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 最終的な提出ファイルの確認\nprint(f\"\\nFinal submission shape: {hybrid_pred.shape}\")\nprint(f\"\\nFirst few rows:\")\nprint(hybrid_pred.head())\n\nprint(f\"\\nLast few rows:\")\nprint(hybrid_pred.tail())"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 提出ファイルの保存\nhybrid_pred.to_csv('submission_v13_hybrid.csv', index=False)\nprint(\"\\nSubmission file saved as 'submission_v13_hybrid.csv'\")\n\n# 別の重みバージョンも保存\n# TensorFlowをより重視したバージョン\nhybrid_pred_tf_heavy = lgbm_pred.copy()\nfor class_name in class_names:\n    hybrid_pred_tf_heavy[class_name] = (\n        0.8 * tf_pred[class_name] + \n        0.2 * lgbm_pred[class_name]\n    )\n\n# 正規化\nrow_sums = hybrid_pred_tf_heavy[class_names].sum(axis=1)\nfor class_name in class_names:\n    hybrid_pred_tf_heavy[class_name] = hybrid_pred_tf_heavy[class_name] / row_sums\n\nhybrid_pred_tf_heavy.to_csv('submission_v13_hybrid_tf08.csv', index=False)\nprint(\"Alternative submission saved as 'submission_v13_hybrid_tf08.csv'\")"}],"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.0"}},"nbformat":4,"nbformat_minor":4}