{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":59156,"databundleVersionId":13874099,"sourceType":"competition"},{"sourceId":14169546,"sourceType":"datasetVersion","datasetId":9030407}],"dockerImageVersionId":31192,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:10:44.028892Z","iopub.execute_input":"2025-12-15T23:10:44.029244Z","iopub.status.idle":"2025-12-15T23:10:54.929797Z","shell.execute_reply.started":"2025-12-15T23:10:44.029205Z","shell.execute_reply":"2025-12-15T23:10:54.928603Z"},"collapsed":true,"jupyter":{"source_hidden":true,"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# !pip install duckdb\n# !pip install hmmlearn\n# !pip install ipykernel\n# !pip install lightgbm\n# !pip install matplotlib\n# !pip install mlflow\n# !pip install numpy\n# !pip install pandas\n# !pip install pandera\n# !pip install plotly\n# !pip install polars\n# !pip install pyarrow\n# !pip install pydantic\n# !pip install scikit-learn\n# !pip install shap\n# !pip install tqdm\n# !pip install xgboost","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:10:54.931973Z","iopub.execute_input":"2025-12-15T23:10:54.932580Z","iopub.status.idle":"2025-12-15T23:10:54.938245Z","shell.execute_reply.started":"2025-12-15T23:10:54.932547Z","shell.execute_reply":"2025-12-15T23:10:54.936164Z"},"jupyter":{"source_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\n\nsys.path.append(\"/kaggle/input/dal-jet-engine-mabe-challenge/src\")\n\nimport pandas as pd\nfrom tqdm import tqdm\nfrom pathlib import Path\n\nfrom helper import Solution, list_parquet_ids, get_df_test, get_labid_from_videoid\nfrom lgbm import LGBM\nfrom metamodel import MetaLR, default_metalr_params\n# from postprocess import majority_filter_3frame\nfrom xgbm import XGBM\n# from dnn import STGCN\n# from hmm_supervised import HMM\nfrom preprocess import preprocess, get_label\n\nimport polars as pl","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:11:41.490722Z","iopub.execute_input":"2025-12-15T23:11:41.491247Z","iopub.status.idle":"2025-12-15T23:11:41.497668Z","shell.execute_reply.started":"2025-12-15T23:11:41.491215Z","shell.execute_reply":"2025-12-15T23:11:41.496509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_mouse_indices(df_metadata: pd.DataFrame, video_id: int) -> list[int]:\n    \"\"\"指定したメタデータとvideo_idから動画に登場するマウスのIDを取得\n\n    Args:\n        df (pd.DataFrame): メタデータのデータフレーム(train.csv, test.csv)\n        video_id (int): マウスIDを取得する動画のID\n\n    Returns:\n        list[int]: マウスIDのリスト(例:[1,2,3])\n\n    \"\"\"\n    row = df_metadata.loc[df_metadata[\"video_id\"] == video_id].iloc[0]\n    cols = [\"mouse1_strain\", \"mouse2_strain\", \"mouse3_strain\", \"mouse4_strain\"]\n\n    # colsのうち欠損していないものを探し、それに応じてマウスIDを抽出(1~4)\n    mouse_id_list = [\n        i + 1\n        for i, c in enumerate(cols)\n        if pd.notna(row[c]) and row[c] != \"\"  # 念のため空文字も除外\n    ]\n    if video_id in [\n        1260392287,\n        1351098077,\n        1643942986,\n    ]:  # これらの動画データだけマウス3がtrackingデータで4と表記されている\n        mouse_id_list = [1, 2, 4]\n\n    return mouse_id_list","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:11:13.141917Z","iopub.execute_input":"2025-12-15T23:11:13.142721Z","iopub.status.idle":"2025-12-15T23:11:13.149261Z","shell.execute_reply.started":"2025-12-15T23:11:13.142690Z","shell.execute_reply":"2025-12-15T23:11:13.148269Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# モデルのリスト\nmodel_dict = {\"lgbm\": LGBM, \n              \"xgbm\": XGBM, \n              \"hmm\":LGBM,\n              # \"stgcn\":STGCN\n             }\n\n# モデルのパス\nlgbm_results_path = \"/kaggle/input/dal-jet-engine-mabe-challenge/model/LGBM_202512151703\"\nxgbm_results_path = \"/kaggle/input/dal-jet-engine-mabe-challenge/model/XGBM_202512151744\"\n# hmm_results_path = \"/kaggle/input/dal-jet-engine-mabe-challenge/model/hmm_202512151804\"\n# stgcn_results_path = \"/kaggle/input/dal-jet-engine-mabe-challenge/model/STGCN_202512152210\"\nmodel_path_dict = {\"lgbm\":lgbm_results_path,\n                   \"xgbm\":xgbm_results_path,\n                   \"hmm\":lgbm_results_path,\n                   # \"stgcn\":stgcn_results_path,\n                  }\n\n# メタモデル・後処理\n# postprocess_list = [\n#     \"MetaLR\",\n#     # \"MetaHnn\",\n#     \"HMMPostProcessor\",\n#     \"majority_filter_3frame\",\n# ]\n\npostprocess_model_dict = {\n    \"MetaLR\": MetaLR,\n    # \"MetaHnn\": MetaHnn,\n    # \"HMMPostProcessor\": HMMPostProcessor,\n    # \"majority_filter_3frame\": majority_filter_3frame,\n}\n\nmetalr_results_path = \"/kaggle/input/dal-jet-engine-mabe-challenge/model/MetaLR_202512160002\"\n# hmmpp_results_path = \"/kaggle/input/dal-jet-engine-mabe-challenge/model/HMMPP_202512160343\"\n\n# postprocess_path_dict = {\"MetaLR\":metalr_results_path}\nmetalr_path_dict = {\"MetaLR\":metalr_results_path, \n                    # \"HMMPostProcessor\":hmmpp_results_path,\n                   }\n\n# 行動リスト\naction_list = [\"submit\", \"chaseattack\", \"chase\", \"approach\", \"attack\"]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:19:49.144678Z","iopub.execute_input":"2025-12-15T23:19:49.145706Z","iopub.status.idle":"2025-12-15T23:19:49.153438Z","shell.execute_reply.started":"2025-12-15T23:19:49.145641Z","shell.execute_reply":"2025-12-15T23:19:49.152146Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"video_list = list_parquet_ids(\"/kaggle/input/MABe-mouse-behavior-detection/test_tracking\")\ndf_test = get_df_test(video_list)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:19:49.597802Z","iopub.execute_input":"2025-12-15T23:19:49.598287Z","iopub.status.idle":"2025-12-15T23:19:49.616299Z","shell.execute_reply.started":"2025-12-15T23:19:49.598259Z","shell.execute_reply":"2025-12-15T23:19:49.615217Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preprocessed_path = Path(\"/kaggle/working/preprocessed/\")\npreprocessed_path.mkdir(parents=True, exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:11:13.237829Z","iopub.execute_input":"2025-12-15T23:11:13.238151Z","iopub.status.idle":"2025-12-15T23:11:13.242597Z","shell.execute_reply.started":"2025-12-15T23:11:13.238125Z","shell.execute_reply":"2025-12-15T23:11:13.241568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i in range(len(df_test)):\n    video_id = int(df_test.iloc[i][\"video_id\"])\n    agent_id = int(df_test.iloc[i][\"agent_id\"])\n    target_id = int(df_test.iloc[i][\"target_id\"])\n    lab_id = get_labid_from_videoid(video_id)\n\n    mouse_list = list(\n        pd.read_parquet(\n            f\"/kaggle/input/MABe-mouse-behavior-detection/test_tracking/{lab_id}/{video_id}.parquet\"\n        )[\"mouse_id\"].unique()\n    )\n\n    X = preprocess(video_id, agent_id, target_id)\n\n    X = X.filter(\n        ~pl.any_horizontal(\n            pl.all().is_null()\n            | pl.all().is_nan()\n            | pl.all().is_infinite()\n        )\n    )\n\n    X = X.to_pandas()\n    X[\"video_id\"] = video_id\n    X[\"agent_id\"] = agent_id\n    X[\"target_id\"] = target_id\n    X = X.rename(columns={\n        \"nose_centroid_costheta_agent_to_target\": \"head_centroid_costheta_agent_to_target\"\n    })\n\n    X.to_parquet(\"/kaggle/working/preprocessed/\" + f\"{video_id}_{agent_id}_{target_id}.parquet\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:16:03.214877Z","iopub.execute_input":"2025-12-15T23:16:03.215681Z","iopub.status.idle":"2025-12-15T23:16:20.001352Z","shell.execute_reply.started":"2025-12-15T23:16:03.215650Z","shell.execute_reply":"2025-12-15T23:16:20.000176Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"solution = Solution()\nfor action in tqdm(action_list):\n    solution_test_each_model = {}\n\n    # 各モデルの予測結果を取得\n    for model_name, model in model_dict.items():\n        if model_name is \"hmm\":\n            m = model.load(model_path_dict[model_name] + f\"/lgbm_{action}.pkl\")\n        else:\n            m = model.load(model_path_dict[model_name] + f\"/{model_name}_{action}.pkl\")\n\n        sol_test = m.predict(df_test)\n        solution_test_each_model[model_name] = sol_test\n\n    # メタモデル(ロジスティック回帰)でスタッキング\n    metalr = MetaLR.load(metalr_results_path + f\"/metalr_{action}.pkl\")\n    if not hasattr(metalr.model, \"multi_class\"):\n        metalr.model.multi_class = \"auto\" \n    meta_prediction_test = metalr.predict(solution_test_each_model)\n\n    # # HMMでスムージング\n    # hmmpp = HMMPostProcessor.load(hmmpp_results_path + f\"/hmm_postprocessor_{action}.pkl\")\n    # meta_prediction_test = Solution().add_df(hmmpp.smooth(meta_prediction_test.df))\n\n    # # majority filterでスムージング\n    # meta_prediction_test.df = majority_filter_3frame(meta_prediction_test.df)\n    solution.add_df(meta_prediction_test.df)\n\ndf = solution.make_submission_df()\n\ndf_out = (\n    df\n    .assign(\n        # row_id を新規作成\n        row_id=lambda x: range(len(x)),\n\n        # agent_id / target_id を mouseX 形式に変換\n        agent_id=lambda x: \"mouse\" + x[\"agent_id\"].astype(str),\n        target_id=lambda x: \"mouse\" + x[\"target_id\"].astype(str),\n    )\n    # 列順を指定\n    [[\"row_id\", \"video_id\", \"agent_id\", \"target_id\",\n      \"action\", \"start_frame\", \"stop_frame\"]]\n)\n\ndf_out.to_csv(\"/kaggle/working/submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:20:59.223818Z","iopub.execute_input":"2025-12-15T23:20:59.224167Z","iopub.status.idle":"2025-12-15T23:21:30.627969Z","shell.execute_reply.started":"2025-12-15T23:20:59.224141Z","shell.execute_reply":"2025-12-15T23:21:30.626107Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_out","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T23:21:45.228974Z","iopub.execute_input":"2025-12-15T23:21:45.229536Z","iopub.status.idle":"2025-12-15T23:21:45.260726Z","shell.execute_reply.started":"2025-12-15T23:21:45.229506Z","shell.execute_reply":"2025-12-15T23:21:45.259193Z"}},"outputs":[],"execution_count":null}]}