{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":81933,"databundleVersionId":9643020,"sourceType":"competition"},{"sourceId":10009936,"sourceType":"datasetVersion","datasetId":6162371},{"sourceId":10198334,"sourceType":"datasetVersion","datasetId":6301632},{"sourceId":10237390,"sourceType":"datasetVersion","datasetId":6330560},{"sourceId":10335643,"sourceType":"datasetVersion","datasetId":6399874}],"dockerImageVersionId":30786,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport copy\nfrom datetime import datetime\n\nfrom joblib import dump, load\n\nfrom tqdm import tqdm\n\nimport pandas as pd\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import mean_squared_error\nfrom sklearn.metrics import cohen_kappa_score\nfrom sklearn.experimental import enable_iterative_imputer\nfrom sklearn.impute import IterativeImputer\nfrom scipy.optimize import minimize\nimport numpy as np\n\nimport optuna\n\nimport lightgbm as lgb\nimport catboost as cb\nimport xgboost as xgb","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2024-12-30T15:35:41.323038Z","iopub.execute_input":"2024-12-30T15:35:41.323373Z","iopub.status.idle":"2024-12-30T15:35:46.415997Z","shell.execute_reply.started":"2024-12-30T15:35:41.323338Z","shell.execute_reply":"2024-12-30T15:35:46.414749Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Config:\n    feature_cols = [\n        'Basic_Demos-Enroll_Season', 'Basic_Demos-Age', 'Basic_Demos-Sex',\n        'CGAS-Season', 'CGAS-CGAS_Score', 'Physical-Season', 'Physical-BMI',\n        'Physical-Height', 'Physical-Weight', 'Physical-Waist_Circumference',\n        'Physical-Diastolic_BP', 'Physical-HeartRate', 'Physical-Systolic_BP',\n        'Fitness_Endurance-Season', 'Fitness_Endurance-Max_Stage',\n        'Fitness_Endurance-Time_Mins', 'Fitness_Endurance-Time_Sec',\n        'FGC-Season', 'FGC-FGC_CU', 'FGC-FGC_CU_Zone', 'FGC-FGC_GSND',\n        'FGC-FGC_GSND_Zone', 'FGC-FGC_GSD', 'FGC-FGC_GSD_Zone', 'FGC-FGC_PU',\n        'FGC-FGC_PU_Zone', 'FGC-FGC_SRL', 'FGC-FGC_SRL_Zone', 'FGC-FGC_SRR',\n        'FGC-FGC_SRR_Zone', 'FGC-FGC_TL', 'FGC-FGC_TL_Zone', 'BIA-Season',\n        'BIA-BIA_Activity_Level_num', 'BIA-BIA_BMC', 'BIA-BIA_BMI',\n        'BIA-BIA_BMR', 'BIA-BIA_DEE', 'BIA-BIA_ECW', 'BIA-BIA_FFM',\n        'BIA-BIA_FFMI', 'BIA-BIA_FMI', 'BIA-BIA_Fat', 'BIA-BIA_Frame_num',\n        'BIA-BIA_ICW', 'BIA-BIA_LDM', 'BIA-BIA_LST', 'BIA-BIA_SMM',\n        'BIA-BIA_TBW', 'PAQ_A-Season', 'PAQ_A-PAQ_A_Total', 'PAQ_C-Season',\n        'PAQ_C-PAQ_C_Total', 'SDS-Season', 'SDS-SDS_Total_Raw',\n        'SDS-SDS_Total_T', 'PreInt_EduHx-Season',\n        'PreInt_EduHx-computerinternet_hoursday'\n    ]\n\n    cat_cols = [\n        'Basic_Demos-Enroll_Season', 'CGAS-Season', 'Physical-Season', 'Fitness_Endurance-Season', \n        'FGC-Season', 'BIA-Season', 'PAQ_A-Season', 'PAQ_C-Season', 'SDS-Season', 'PreInt_EduHx-Season'\n    ]\n\n    remove_ts_columns = {\n        'X': ['count'],\n        'Y': ['count'],\n        'Z': ['count'],\n        'enmo': ['count'],\n        'anglez': ['count'],\n        'non-wear_flag': ['count'],\n        'light': ['count'],\n        # 特徴量エンジニアリング\n        'XYZ': ['count'],\n        'abs_X': ['count'],\n        'abs_Y': ['count'],\n        'abs_Z': ['count'],\n        'abs_anglez': ['count']\n    }\n\n    drop_ts_columns = ['step', 'battery_voltage', 'time_of_day', 'weekday', 'quarter', 'relative_date_PCIAT']\n\n    n_splits = 5\n\n    seed = 42\n\n    k_fold_seeds = [777, 42, 1732]\n\n    bins = [0, 21600, 43200, 64800, 86400]\n\n    select_feature_cols1 = ['Basic_Demos-Age', 'Basic_Demos-Sex', 'Physical-Height', 'Physical-Weight', 'FGC-FGC_CU', 'FGC-FGC_GSND', 'FGC-FGC_GSD', 'FGC-FGC_PU', 'BIA-BIA_Activity_Level_num', 'SDS-SDS_Total_Raw', 'SDS-SDS_Total_T', 'PreInt_EduHx-computerinternet_hoursday', 'light_max']\n    select_feature_cols2 = ['Basic_Demos-Age', 'Basic_Demos-Sex', 'Physical-Height', 'Physical-Weight', 'Physical-Waist_Circumference', 'FGC-FGC_CU', 'FGC-FGC_GSND', 'FGC-FGC_GSND_Zone', 'FGC-FGC_GSD', 'FGC-FGC_PU', 'PAQ_A-PAQ_A_Total', 'SDS-SDS_Total_Raw', 'SDS-SDS_Total_T', 'PreInt_EduHx-computerinternet_hoursday', 'X_25%_0-21600', 'Y_std', 'Z_mean_0-21600', 'Z_min_43200-64800', 'Z_75%_64800-86400', 'enmo_50%_43200-64800', 'non-wear_flag_mean_0-21600', 'light_std', 'light_max_21600-43200', 'XYZ_50%_21600-43200', 'XYZ_mean_43200-64800', 'XYZ_mean_64800-86400', 'XYZ_std_64800-86400', 'XYZ_50%_64800-86400', 'abs_X_50%_21600-43200', 'abs_X_25%_64800-86400', 'abs_X_75%_64800-86400', 'abs_Y_75%_0-21600', 'abs_Y_min_21600-43200', 'abs_Y_75%_64800-86400', 'abs_Z_75%_21600-43200', 'abs_Z_75%_43200-64800', 'abs_anglez_min_43200-64800', 'BMI_Age', 'Internet_Hours_Age', 'Muscle_to_Fat']\n    select_feature_cols3 = ['Basic_Demos-Age', 'Basic_Demos-Sex', 'Physical-Height', 'Physical-Weight', 'Fitness_Endurance-Max_Stage', 'FGC-FGC_CU', 'FGC-FGC_GSND', 'FGC-FGC_GSD', 'FGC-FGC_PU', 'BIA-BIA_Activity_Level_num', 'PAQ_A-PAQ_A_Total', 'SDS-SDS_Total_Raw', 'SDS-SDS_Total_T', 'PreInt_EduHx-computerinternet_hoursday']\n    \n    lgb_dir1 = '/kaggle/input/cmi2-8th-place-models/models/lgb/plain'\n    xgb_dir1 = '/kaggle/input/cmi2-8th-place-models/models/xgb/plain'\n    cat_dir1 = '/kaggle/input/cmi2-8th-place-models/models/cat/plain'\n\n    lgb_dir2 = '/kaggle/input/cmi2-8th-place-models/models/lgb/feateng_tsgroup'\n    xgb_dir2 = '//kaggle/input/cmi2-8th-place-models/models/xgb/feateng_tsgroup'\n    cat_dir2 = '/kaggle/input/cmi2-8th-place-models/models/cat/feateng_tsgroup'\n\n    lgb_dir3 = '/kaggle/input/cmi2-8th-place-models/models/lgb/plain_no-ts'\n    xgb_dir3 = '/kaggle/input/cmi2-8th-place-models/models/xgb/plain_no-ts'\n    cat_dir3 = '/kaggle/input/cmi2-8th-place-models/models/cat/plain_no-ts'\n\n    imputer_dir = '/kaggle/input/cmi2-8th-place-models/models/imputer'\n\n    threshold = [0.57721265, 1.01302488, 2.66556245]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-30T15:35:46.418589Z","iopub.execute_input":"2024-12-30T15:35:46.419180Z","iopub.status.idle":"2024-12-30T15:35:46.434797Z","shell.execute_reply.started":"2024-12-30T15:35:46.419143Z","shell.execute_reply":"2024-12-30T15:35:46.433359Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def update(df):\n    for c in Config.cat_cols: \n        df[c] = df[c].fillna('Missing')\n        df[c] = df[c].astype('category')\n    return df\n\ndef create_mapping(column, df):\n    unique_values = df[column].unique()\n    return {value: idx for idx, value in enumerate(unique_values)}\n\ndef quadratic_weighted_kappa(y_true, y_pred):\n    return cohen_kappa_score(y_true, y_pred, weights='quadratic')\n\ndef threshold_Rounder(oof_non_rounded, thresholds):\n    return np.where(oof_non_rounded < thresholds[0], 0,\n                    np.where(oof_non_rounded < thresholds[1], 1,\n                             np.where(oof_non_rounded < thresholds[2], 2, 3)))\n\ndef evaluate_predictions(thresholds, y_true, oof_non_rounded):\n    rounded_p = threshold_Rounder(oof_non_rounded, thresholds)\n    return -quadratic_weighted_kappa(y_true, rounded_p)\n\ndef ts_feature_engineering(df):\n    df['XYZ'] = np.sqrt(df['X']**2 + df['Y']**2 + df['Z']**2)\n    df['abs_X'] = np.abs(df['X'])\n    df['abs_Y'] = np.abs(df['Y'])\n    df['abs_Z'] = np.abs(df['Z'])\n    df['abs_anglez'] = np.abs(df['anglez'])\n\n    # 時刻を0〜86500にスケーリング\n    df['time_of_day'] = (df['time_of_day'] // 1e+9).astype(np.int64)    \n    df['time_of_day_bins'] = pd.cut(df['time_of_day'], bins=Config.bins)\n\n    return df\n\ndef create_TimeSeries():\n    # TimeSeriesのIDリストを作成(id=を除去)\n    ts_dirs = os.listdir('/kaggle/input/child-mind-institute-problematic-internet-use/series_test.parquet')\n    ts_ids = [s.split('=')[1] for s in ts_dirs]\n\n    ts_records = []\n    for ts_id in tqdm(ts_ids):\n        # 時系列データの読み込み\n        ts_df = pd.read_parquet(f'/kaggle/input/child-mind-institute-problematic-internet-use/series_test.parquet/id={ts_id}/part-0.parquet')\n        # 時系列要約特徴量エンジニアリング\n        ts_df = ts_feature_engineering(ts_df)\n        # 不要な特徴量を削減\n        ts_df.drop(Config.drop_ts_columns, axis=1, inplace=True)\n        \n        record = {}\n        # 特徴量ごとに統計量を算出\n        for feature in ts_df.columns.tolist():\n            if feature == 'time_of_day_bins':\n                continue\n            desc = ts_df[feature].describe()\n            # 不要な統計量を除去\n            desc = desc.drop(Config.remove_ts_columns[feature])\n            for stat_name, value in desc.items():\n                record[f'{feature}_{stat_name}'] = value\n\n            # 時間帯でグルーピングして、統計量を算出\n            for time_range_idx in range(len(Config.bins) - 1):\n                desc_time_range = ts_df.groupby('time_of_day_bins', observed=False)[feature].describe().iloc[time_range_idx]\n                # 不要な統計量を除去\n                desc_time_range = desc_time_range.drop(Config.remove_ts_columns[feature])\n                for stat_name, value in desc_time_range.items():\n                    record[f'{feature}_{stat_name}_{Config.bins[time_range_idx]}-{Config.bins[time_range_idx+1]}'] = value\n\n        record['id'] = ts_id\n\n        ts_records.append(record)\n\n    ts_df = pd.DataFrame(ts_records)\n\n    return ts_df\n\ndef feature_engineering(df):\n    df['BMI_Age'] = df['Physical-BMI'] * df['Basic_Demos-Age']\n    df['Internet_Hours_Age'] = df['PreInt_EduHx-computerinternet_hoursday'] * df['Basic_Demos-Age']\n    df['BMI_Internet_Hours'] = df['Physical-BMI'] * df['PreInt_EduHx-computerinternet_hoursday']\n    df['BFP_BMI'] = df['BIA-BIA_Fat'] / df['BIA-BIA_BMI']\n    df['FFMI_BFP'] = df['BIA-BIA_FFMI'] / df['BIA-BIA_Fat']\n    df['FMI_BFP'] = df['BIA-BIA_FMI'] / df['BIA-BIA_Fat']\n    df['LST_TBW'] = df['BIA-BIA_LST'] / df['BIA-BIA_TBW']\n    df['BFP_BMR'] = df['BIA-BIA_Fat'] * df['BIA-BIA_BMR']\n    df['BFP_DEE'] = df['BIA-BIA_Fat'] * df['BIA-BIA_DEE']\n    df['BMR_Weight'] = df['BIA-BIA_BMR'] / df['Physical-Weight']\n    df['DEE_Weight'] = df['BIA-BIA_DEE'] / df['Physical-Weight']\n    df['SMM_Height'] = df['BIA-BIA_SMM'] / df['Physical-Height']\n    df['Muscle_to_Fat'] = df['BIA-BIA_SMM'] / df['BIA-BIA_FMI']\n    df['Hydration_Status'] = df['BIA-BIA_TBW'] / df['Physical-Weight']\n    df['ICW_TBW'] = df['BIA-BIA_ICW'] / df['BIA-BIA_TBW']\n    \n    return df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-30T15:35:46.437081Z","iopub.execute_input":"2024-12-30T15:35:46.437635Z","iopub.status.idle":"2024-12-30T15:35:46.473228Z","shell.execute_reply.started":"2024-12-30T15:35:46.437565Z","shell.execute_reply":"2024-12-30T15:35:46.471871Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 数値特徴量リストを作成\nnum_cols = [item for item in Config.feature_cols if item not in Config.cat_cols]\n\n# 学習データの読み込み\ndf = pd.read_csv('/kaggle/input/child-mind-institute-problematic-internet-use/test.csv')\ntrain_df = pd.read_csv('/kaggle/input/child-mind-institute-problematic-internet-use/train.csv')\n\n# カテゴリ変数のエンコード\ndf = update(df)\ntrain_df = update(train_df)\nfor cat_col in Config.cat_cols:\n    mapping = create_mapping(cat_col, train_df)\n    df[cat_col] = df[cat_col].replace(mapping).astype(int)\n\n# 時系列データフレームを作成\nts_df = create_TimeSeries()\n\n# 時系列データを結合\ndf = pd.merge(df, ts_df, how=\"left\", on='id')\n\n# 時系列特徴量を保存\nts_features = df[ts_df.drop('id', axis=1).columns.tolist()]\n\nids = df['id'].to_numpy()\npreds = np.zeros((len(df)), np.float64)\n\n# 異なるランダムSeedで層化分別\nfor i, k_fold_seed in tqdm(enumerate(Config.k_fold_seeds)):\n    # クロスバリデーション\n    for k in range(Config.n_splits):\n        # モデル読み込み\n        imputer = load(os.path.join(Config.imputer_dir, str(k_fold_seed), str(k), 'model.joblib'))\n\n        lgb_model1 = load(os.path.join(Config.lgb_dir1, str(k_fold_seed), str(k), 'model.joblib'))\n        xgb_model1 = load(os.path.join(Config.xgb_dir1, str(k_fold_seed), str(k), 'model.joblib'))\n\n        xgb_model2 = load(os.path.join(Config.xgb_dir2, str(k_fold_seed), str(k), 'model.joblib'))\n\n        lgb_model3 = load(os.path.join(Config.lgb_dir3, str(k_fold_seed), str(k), 'model.joblib'))\n        cat_model3 = load(os.path.join(Config.cat_dir3, str(k_fold_seed), str(k), 'model.joblib'))\n        xgb_model3 = load(os.path.join(Config.xgb_dir3, str(k_fold_seed), str(k), 'model.joblib'))\n\n        # 入力データ準備\n        X = df.copy()\n        X.loc[:, num_cols] = imputer.transform(X[num_cols])\n\n        # 特徴量エンジニアリング\n        X = feature_engineering(X)\n\n        # 入力特徴量作成\n        X1 = X[Config.select_feature_cols1]\n        X2 = X[Config.select_feature_cols2]\n        X3 = X[Config.select_feature_cols3]\n\n        # 検証\n        preds += (lgb_model1.predict(X1, num_iteration=lgb_model1.best_iteration_) * 0.2 + xgb_model1.predict(X1) * 0.2 \\\n                    + xgb_model2.predict(X2) * 0.2 \\\n                        + lgb_model3.predict(X3, num_iteration=lgb_model3.best_iteration_) * 0.2 + cat_model3.predict(X3) * 0.1 + xgb_model3.predict(X3) * 0.1)\n\npreds /= (len(Config.k_fold_seeds) * Config.n_splits)\noof_tuned = threshold_Rounder(preds, Config.threshold)\nsub_df = pd.DataFrame({\n    'id': ids,\n    'sii': oof_tuned\n})\nsub_df.to_csv('submission.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-30T15:35:46.474556Z","iopub.execute_input":"2024-12-30T15:35:46.474980Z","iopub.status.idle":"2024-12-30T15:35:53.146299Z","shell.execute_reply.started":"2024-12-30T15:35:46.474944Z","shell.execute_reply":"2024-12-30T15:35:53.145223Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}