{"cells":[{"cell_type":"markdown","metadata":{},"source":"# V13 LightGBM Inference - LB 0.80 Hybrid\n\nLightGBM推論ノートブック（窓ベース特徴量）"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"import os\nimport sys\nimport numpy as np\nimport pandas as pd\nimport lightgbm as lgb\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder\nimport joblib\nfrom pathlib import Path\nimport gc\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    MODEL_DIR = Path('/kaggle/input/cmi-bfrb-v13-lgbm-models')  # 学習済みモデル\n    SOURCE_DIR = Path('/kaggle/input/cmi-bfrb-v13-hybrid-source')\n    \n    # ソースコードの追加\n    sys.path.append(str(SOURCE_DIR))\nelse:\n    # ローカル環境\n    DATA_DIR = Path('../../../data/cmi-detect-behavior-with-sensor-data')\n    MODEL_DIR = Path('../models/lgbm')\n    sys.path.append('../src')\n\nprint(f\"Data directory: {DATA_DIR}\")\nprint(f\"Model directory: {MODEL_DIR}\")\nprint(f\"Model directory exists: {MODEL_DIR.exists()}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# モジュールのインポート\nfrom feature_engineering_v13 import (\n    engineer_features_v13,\n    aggregate_tof_features,\n    get_feature_columns_v13,\n    add_dummy_thermopile_features\n)\nfrom train_lgbm_v13 import create_windows_from_sequences"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# モデルとオブジェクトの読み込み\ndef load_models_and_objects(model_dir):\n    \"\"\"保存されたモデルとオブジェクトの読み込み\"\"\"\n    models = []\n    \n    # モデルファイルの検索と読み込み\n    for i in range(10):  # 最大10foldまで対応\n        model_file = model_dir / f'lgbm_model_fold{i}.txt'\n        if model_file.exists():\n            print(f\"Loading model from {model_file}\")\n            model = lgb.Booster(model_file=str(model_file))\n            models.append(model)\n        else:\n            break\n    \n    print(f\"Loaded {len(models)} models\")\n    \n    # スケーラーとエンコーダーの読み込み\n    scaler = joblib.load(model_dir / 'scaler_lgbm.pkl')\n    label_encoder = joblib.load(model_dir / 'label_encoder.pkl')\n    feature_cols = joblib.load(model_dir / 'feature_columns.pkl')\n    \n    return models, scaler, label_encoder, feature_cols\n\n# モデルの読み込み\nmodels, scaler, label_encoder, feature_cols = load_models_and_objects(MODEL_DIR)"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# テストデータの読み込み\ntest_df = pd.read_csv(DATA_DIR / 'test.csv')\nsubmission = pd.read_csv(DATA_DIR / 'sample_submission.csv')\n\nprint(f\"Test data shape: {test_df.shape}\")\nprint(f\"Number of test sequences: {test_df['sequence_id'].nunique()}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 特徴量エンジニアリング\nprint(\"Applying feature engineering...\")\ntest_df = engineer_features_v13(test_df)\ntest_df = aggregate_tof_features(test_df)\ntest_df = add_dummy_thermopile_features(test_df)\n\nprint(f\"Features after engineering: {len(test_df.columns)}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 予測関数\ndef predict_sequence(seq_df, models, scaler, window_size=100, stride=50):\n    \"\"\"シーケンスごとの予測\"\"\"\n    # 特徴量の抽出\n    seq_features = seq_df[feature_cols].ffill().bfill().fillna(0).values\n    \n    # ウィンドウが取れない短いシーケンスの処理\n    if len(seq_features) < window_size:\n        # パディングして1つのウィンドウを作成\n        padded = np.pad(seq_features, \n                       ((0, window_size - len(seq_features)), (0, 0)), \n                       mode='edge')\n        windows = [padded]\n    else:\n        # 通常のウィンドウ作成\n        n_windows = (len(seq_features) - window_size) // stride + 1\n        windows = []\n        \n        for i in range(n_windows):\n            start_idx = i * stride\n            end_idx = start_idx + window_size\n            windows.append(seq_features[start_idx:end_idx])\n    \n    # 各ウィンドウから統計量を抽出\n    window_features = []\n    for window in windows:\n        features = []\n        for col_idx in range(window.shape[1]):\n            col_data = window[:, col_idx]\n            features.extend([\n                np.mean(col_data),\n                np.std(col_data),\n                np.min(col_data),\n                np.max(col_data),\n                np.percentile(col_data, 25),\n                np.percentile(col_data, 75),\n            ])\n        window_features.append(features)\n    \n    # スケーリング\n    X = scaler.transform(window_features)\n    \n    # 各モデルで予測\n    predictions = []\n    for model in models:\n        pred = model.predict(X, num_iteration=model.best_iteration)\n        predictions.append(pred)\n    \n    # アンサンブル（平均）\n    ensemble_pred = np.mean(predictions, axis=0)\n    \n    # ウィンドウ予測の集約（平均）\n    final_pred = np.mean(ensemble_pred, axis=0)\n    \n    return final_pred"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 全シーケンスの予測\nprint(\"Making predictions...\")\nall_predictions = []\n\nfor seq_id in test_df['sequence_id'].unique():\n    seq_df = test_df[test_df['sequence_id'] == seq_id]\n    \n    # 予測\n    pred = predict_sequence(seq_df, models, scaler)\n    all_predictions.append(pred)\n    \n    if len(all_predictions) % 100 == 0:\n        print(f\"Processed {len(all_predictions)} sequences\")\n\nprint(f\"Total predictions: {len(all_predictions)}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 予測結果の整形\npredictions_array = np.array(all_predictions)\nprint(f\"Predictions shape: {predictions_array.shape}\")\n\n# クラス名の取得\nclass_names = label_encoder.classes_\nprint(f\"Classes: {class_names}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 提出ファイルの作成\nsubmission_df = pd.DataFrame({\n    'sequence_id': test_df['sequence_id'].unique()\n})\n\n# 各クラスの確率を追加\nfor i, class_name in enumerate(class_names):\n    submission_df[class_name] = predictions_array[:, i]\n\n# 確認\nprint(f\"Submission shape: {submission_df.shape}\")\nprint(f\"\\nFirst few rows:\")\nprint(submission_df.head())\n\n# 予測値の合計確認（各行が1.0になるはず）\nrow_sums = submission_df[class_names].sum(axis=1)\nprint(f\"\\nRow sums - min: {row_sums.min():.4f}, max: {row_sums.max():.4f}\")"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"# 提出ファイルの保存\nsubmission_df.to_csv('submission_v13_lgbm.csv', index=False)\nprint(\"Submission file saved as 'submission_v13_lgbm.csv'\")\n\n# メモリクリーンアップ\ndel test_df, predictions_array\ngc.collect()"}],"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}