{"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"}],"dockerImageVersionId":30804,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib\nimport matplotlib.pyplot as plt\nimport os\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport pandas as pd\nfrom sklearn.preprocessing import StandardScaler\nfrom scipy.stats import mode\n\nfrom sklearn.preprocessing import LabelEncoder\nimport lightgbm as lgb\nfrom scipy.optimize import minimize\nfrom sklearn.metrics import cohen_kappa_score\nfrom sklearn.model_selection import KFold, RepeatedStratifiedKFold\nfrom sklearn.base import clone\nfrom tqdm import tqdm\nfrom colorama import Fore, Style\nfrom IPython.display import clear_output\n\nimport seaborn as sns\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:23:35.372295Z","iopub.execute_input":"2024-12-31T09:23:35.372841Z","iopub.status.idle":"2024-12-31T09:23:35.379259Z","shell.execute_reply.started":"2024-12-31T09:23:35.372801Z","shell.execute_reply":"2024-12-31T09:23:35.378416Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Actigraphy Data","metadata":{}},{"cell_type":"code","source":"class AutoEncoder(nn.Module):\n    def __init__(self, input_dim, encoding_dim):\n        super(AutoEncoder, self).__init__()\n        self.encoder = nn.Sequential(\n            nn.Linear(input_dim, encoding_dim*3),\n            nn.ReLU(),\n            nn.Linear(encoding_dim*3, encoding_dim*2),\n            nn.ReLU(),\n            nn.Linear(encoding_dim*2, encoding_dim),\n            nn.ReLU()\n        )\n        self.decoder = nn.Sequential(\n            nn.Linear(encoding_dim, input_dim*2),\n            nn.ReLU(),\n            nn.Linear(input_dim*2, input_dim*3),\n            nn.ReLU(),\n            nn.Linear(input_dim*3, input_dim),\n            nn.Sigmoid()\n        )\n        \n    def forward(self, x):\n        encoded = self.encoder(x)\n        decoded = self.decoder(encoded)\n        return decoded\n         \ndef perform_autoencoder(df, encoding_dim=50, epochs=50, batch_size=32):\n    scaler = StandardScaler()\n    df_scaled = scaler.fit_transform(df)\n    \n    data_tensor = torch.FloatTensor(df_scaled)\n    \n    input_dim = data_tensor.shape[1]\n    autoencoder = AutoEncoder(input_dim, encoding_dim)\n    \n    criterion = nn.MSELoss()\n    optimizer = optim.Adam(autoencoder.parameters())\n    \n    for epoch in range(epochs):\n        for i in range(0, len(data_tensor), batch_size):\n            batch = data_tensor[i : i + batch_size]\n            optimizer.zero_grad()\n            reconstructed = autoencoder(batch)\n            loss = criterion(reconstructed, batch)\n            loss.backward()\n            optimizer.step()\n            \n        if (epoch + 1) % 10 == 0:\n            print(f'Epoch [{epoch + 1}/{epochs}], Loss: {loss.item():.4f}]')\n    \n    return autoencoder, scaler\n\n\ndef encode_features(df, autoencoder, scaler, prefix='Enc_'):\n    df_scaled = scaler.transform(df)\n    data_tensor = torch.FloatTensor(df_scaled)\n\n    with torch.no_grad():\n        encoded_data = autoencoder.encoder(data_tensor).numpy()\n        \n    return pd.DataFrame(encoded_data, columns=[f'{prefix}{i + 1}' for i in range(encoded_data.shape[1])])\n\ndef label_encode(df, encoders = None):\n    if encoders is None : encoders = {}\n    df_encoded = df.copy()\n    \n    for col in df.columns:\n        if df[col].dtype != 'object' and df[col].dtype.name != 'category': continue\n        encoder =  encoders[col] if col in encoders else LabelEncoder()\n        df_encoded[col] = encoder.transform(df[col].astype(str)) if col in encoders else encoder.fit_transform(df[col].astype(str))\n        encoders[col] = encoder\n            \n    return df_encoded, encoders","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:23:35.412086Z","iopub.execute_input":"2024-12-31T09:23:35.412580Z","iopub.status.idle":"2024-12-31T09:23:35.423634Z","shell.execute_reply.started":"2024-12-31T09:23:35.412549Z","shell.execute_reply":"2024-12-31T09:23:35.422672Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Actigraphy\nimport os\nfrom concurrent.futures import ThreadPoolExecutor\nfrom tqdm import tqdm\n\ndef get_stat(df, stat_config=None):\n    stat_config = stat_config or {attr: ['count', 'mean', 'std', 'min', '25%', '50%', '75%', 'max'] for attr in df.columns}\n\n    df_stat = df.describe()\n\n    flat_data = {\n        f\"{attr}_{stat_name}\": df_stat.loc[stat_name, attr]\n        for attr, stats in stat_config.items() if attr in df_stat.columns\n        for stat_name in stats if stat_name in df_stat.index\n    }\n\n    return pd.DataFrame([flat_data])\n\ndef actigraphy_feature_selection(df):\n    features_df = pd.DataFrame()\n    \n    non_wear_percentage = (df['non-wear_flag'].sum() / len(df)) * 100\n    df = df[df['non-wear_flag'] == 0].copy()\n    \n    df['time_of_day'] = df['time_of_day'] / 1e9 / 3600 #nanoseconds to hours\n    df['hour_time'] = df['relative_date_PCIAT'] * 24 + df['time_of_day']\n\n    # Statistical Feature Selection\n    stat_config = {\n        'enmo': ['mean', 'std', 'min', '25%', '50%', '75%', 'max'],\n        'anglez': ['mean', 'std', 'min', '25%', '50%', '75%', 'max'],\n        'light': ['mean', 'std', 'min', '25%', '50%', '75%', 'max'], \n        'time_of_day': ['mean', 'std'],\n        'quarter': ['mean']\n    }\n    stat_features = get_stat(df, stat_config)\n\n    # AutoEncode features\n    drop_list = ['step', 'non-wear_flag', 'battery_voltage', 'relative_date_PCIAT']\n    autoencode_features = get_stat(df.drop(drop_list, axis = 1))\n    autoencode_features = autoencode_features.rename(columns = lambda col: f'AEF_{col}')\n\n    # Manual Feature Selection\n    features_df['non_wear_percentage'] = non_wear_percentage\n\n    features_df = pd.concat([features_df, stat_features, autoencode_features], axis = 1)\n    return  features_df\n\ndef process_file(filename, dirname):\n    df = pd.read_parquet(os.path.join(dirname, filename, 'part-0.parquet'))\n    \n    features_df = actigraphy_feature_selection(df)\n    features_df['id'] = filename.split('=')[1]\n    \n    return features_df\n\n\ndef load_time_series(dirname) -> pd.DataFrame:\n    ids = os.listdir(dirname)\n    \n    with ThreadPoolExecutor() as executor:\n        results = list(tqdm(\n            executor.map(lambda fname: process_file(fname, dirname), ids), \n            total=len(ids)\n        ))\n    \n    return pd.concat(results, axis = 0, ignore_index=True)    \n\ntest_ts = load_time_series(\"/kaggle/input/child-mind-institute-problematic-internet-use/series_test.parquet\")\ntest_ts.filter(like='AEF_', axis=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:23:35.492135Z","iopub.execute_input":"2024-12-31T09:23:35.492391Z","iopub.status.idle":"2024-12-31T09:23:35.694538Z","shell.execute_reply.started":"2024-12-31T09:23:35.492366Z","shell.execute_reply":"2024-12-31T09:23:35.693702Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Fitness Assessments Data","metadata":{}},{"cell_type":"code","source":"# Ref https://cdn.who.int/media/docs/default-source/child-growth/growth-reference-5-19-years/bmi-for-age-(5-19-years)/sft-bmifa-girls-z-5-19years.pdf?sfvrsn=571135b3_4\nWHO_BMI_RANGES = {\n    5: {'-3SD': 11.7, '-2SD': 12.7, '-1SD': 13.9, 'Median': 15.2, '1SD': 16.9, '2SD': 19.0, '3SD': 21.7},\n    6: {'-3SD': 11.7, '-2SD': 12.7, '-1SD': 13.9, 'Median': 15.3, '1SD': 17.1, '2SD': 19.5, '3SD': 22.7},\n    7: {'-3SD': 11.8, '-2SD': 12.8, '-1SD': 14.0, 'Median': 15.5, '1SD': 17.5, '2SD': 20.1, '3SD': 24.0},\n    8: {'-3SD': 12.0, '-2SD': 13.0, '-1SD': 14.3, 'Median': 15.9, '1SD': 18.0, '2SD': 21.0, '3SD': 25.6},\n    9: {'-3SD': 12.2, '-2SD': 13.3, '-1SD': 14.6, 'Median': 16.3, '1SD': 18.7, '2SD': 22.0, '3SD': 27.5},\n    10: {'-3SD': 12.5, '-2SD': 13.7, '-1SD': 15.1, 'Median': 16.9, '1SD': 19.4, '2SD': 23.1, '3SD': 29.3},\n    11: {'-3SD': 12.9, '-2SD': 14.1, '-1SD': 15.6, 'Median': 17.6, '1SD': 20.3, '2SD': 24.3, '3SD': 31.1},\n    12: {'-3SD': 13.4, '-2SD': 14.7, '-1SD': 16.3, 'Median': 18.4, '1SD': 21.3, '2SD': 25.6, '3SD': 32.7},\n    13: {'-3SD': 13.8, '-2SD': 15.2, '-1SD': 16.9, 'Median': 19.2, '1SD': 22.3, '2SD': 26.8, '3SD': 34.1},\n    14: {'-3SD': 14.2, '-2SD': 15.7, '-1SD': 17.5, 'Median': 19.9, '1SD': 23.1, '2SD': 27.8, '3SD': 35.1},\n    15: {'-3SD': 14.5, '-2SD': 16.0, '-1SD': 18.0, 'Median': 20.5, '1SD': 23.8, '2SD': 28.6, '3SD': 35.8},\n    16: {'-3SD': 14.7, '-2SD': 16.3, '-1SD': 18.3, 'Median': 20.9, '1SD': 24.3, '2SD': 29.1, '3SD': 36.2},\n    17: {'-3SD': 14.7, '-2SD': 16.4, '-1SD': 18.5, 'Median': 21.2, '1SD': 24.6, '2SD': 29.4, '3SD': 36.3},\n    18: {'-3SD': 14.7, '-2SD': 16.5, '-1SD': 18.6, 'Median': 21.3, '1SD': 24.9, '2SD': 29.6, '3SD': 36.2},\n    19: {'-3SD': 14.7, '-2SD': 16.5, '-1SD': 18.7, 'Median': 21.4, '1SD': 25.0, '2SD': 29.7, '3SD': 36.2}\n}\n\ndef calculate_bmi_score(age, bmi):\n    ranges = WHO_BMI_RANGES.get(age, WHO_BMI_RANGES[19])\n    if bmi < ranges['-3SD']:\n        return 'Severely Underweight'\n    elif ranges['-3SD'] <= bmi < ranges['-2SD']:\n        return 'Underweight'\n    elif ranges['-2SD'] <= bmi < ranges['-1SD']:\n        return 'Mildly Underweight'\n    elif ranges['-1SD'] <= bmi < ranges['1SD']:\n        return 'Normal weight'\n    elif ranges['1SD'] <= bmi < ranges['2SD']:\n        return 'Overweight'\n    elif ranges['2SD'] <= bmi < ranges['3SD']:\n        return 'Obese'\n    else:\n        return 'Severely Obese'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:23:35.696136Z","iopub.execute_input":"2024-12-31T09:23:35.696423Z","iopub.status.idle":"2024-12-31T09:23:35.707134Z","shell.execute_reply.started":"2024-12-31T09:23:35.696378Z","shell.execute_reply":"2024-12-31T09:23:35.706277Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# def fa_data_normalization(df):\n#     normal_ranges = {\n#         'Physical-BMI': (18.5, 24.9),\n#         'Physical-Height': (100, 193),\n#         'Physical-Weight': (20, 120),\n#         'Physical-Waist_Circumference': (50, 90),\n#         'Physical-Diastolic_BP': (60, 80),\n#         'Physical-HeartRate': (60, 100),\n#         'Physical-Systolic_BP': (90, 120)\n#     }\n\ndef fa_dealing_with_invalid_weight(df):\n    df_processed = df.copy()\n    invalid_weight = df_processed['Physical-Weight'] == 0\n    df_processed.loc[invalid_weight, ['Physical-Weight','Physical-BMI']] = np.nan\n\n    return df_processed\n    \ndef fa_data_preprocessing(df):\n    df_processed = df.copy()\n    df_processed = fa_dealing_with_invalid_weight(df_processed)\n    \n    numeric_col = df_processed.select_dtypes(include=['number']).columns\n    non_numeric_col = df_processed.select_dtypes(exclude=['number']).columns\n    \n    df_processed[non_numeric_col] = df_processed[non_numeric_col].fillna('Missing')\n\n    # Handle age grouping\n    age_bins = [4, 12, 18, 22]\n    age_labels = ['5-12', '13-18', '19-22']\n    df_processed['Age_Group'] = pd.cut(df_processed['Basic_Demos-Age'], bins=age_bins, labels=age_labels, right=True)\n    \n    # Fill missing values for 'PreInt_EduHx-computerinternet_hoursday'\n    for age_group in age_labels:\n        mode_value = df_processed[df_processed['Age_Group'] == age_group]['PreInt_EduHx-computerinternet_hoursday'].dropna().mode()\n        if not mode_value.empty:\n            df_processed.loc[df_processed['Age_Group'] == age_group, 'PreInt_EduHx-computerinternet_hoursday'] = df_processed.loc[df_processed['Age_Group'] == age_group, 'PreInt_EduHx-computerinternet_hoursday'].fillna(mode_value.iloc[0])\n \n    # Fill missing numeric columns based on 'age' and 'PreInt_EduHx-computerinternet_hoursday'\n    for col in numeric_col:\n        overall_median = df_processed[col].dropna().median()\n        df_processed[col] = df_processed.groupby(['Age_Group', 'PreInt_EduHx-computerinternet_hoursday'], observed=True)[col].transform(\n            lambda x: x.fillna(x.dropna().median() if not x.dropna().empty else overall_median))\n    \n    df_processed.drop('Age_Group', axis=1, inplace=True)\n\n    return df_processed\n\n\ndef fa_feature_engineering(df):\n    # Embedding Real-World Domain Knowledge\n    df['BMI_Score'] = df.apply(lambda row: calculate_bmi_score(row['Basic_Demos-Age'], row['Physical-BMI']), axis=1)\n\n    # Feature Creation\n    # season_cols = [col for col in df.columns if 'Season' in col]\n    # df = df.drop(season_cols, axis=1) \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    # df['BMI_PHR'] = df['Physical-BMI'] * df['Physical-HeartRate']\n    \n    return df\n\ndef load_csv(dirname) -> pd.DataFrame:\n    df = pd.read_csv(dirname)\n        \n    y_labels = [\n        'PCIAT-PCIAT_01', 'PCIAT-PCIAT_02', 'PCIAT-PCIAT_03', 'PCIAT-PCIAT_04',\n        'PCIAT-PCIAT_05', 'PCIAT-PCIAT_06', 'PCIAT-PCIAT_07', 'PCIAT-PCIAT_08',\n        'PCIAT-PCIAT_09', 'PCIAT-PCIAT_10', 'PCIAT-PCIAT_11', 'PCIAT-PCIAT_12',\n        'PCIAT-PCIAT_13', 'PCIAT-PCIAT_14', 'PCIAT-PCIAT_15', 'PCIAT-PCIAT_16',\n        'PCIAT-PCIAT_17', 'PCIAT-PCIAT_18', 'PCIAT-PCIAT_19', 'PCIAT-PCIAT_20',\n        'PCIAT-PCIAT_Total', 'PCIAT-Season', 'sii']\n    \n    X = df.drop(columns=y_labels, errors='ignore')\n    y = df.filter(items=y_labels, axis=1)\n\n    y['id'] = X['id']\n    \n    return X, y\n\nX_train, y_train = load_csv('/kaggle/input/child-mind-institute-problematic-internet-use/train.csv')\nX_test, _ = load_csv('/kaggle/input/child-mind-institute-problematic-internet-use/test.csv')\n\nX_train = fa_data_preprocessing(X_train)\nX_test = fa_data_preprocessing(X_train)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:23:35.708480Z","iopub.execute_input":"2024-12-31T09:23:35.709036Z","iopub.status.idle":"2024-12-31T09:23:36.432306Z","shell.execute_reply.started":"2024-12-31T09:23:35.708997Z","shell.execute_reply":"2024-12-31T09:23:36.431635Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Data Preparation","metadata":{}},{"cell_type":"code","source":"# Fitness Assessments features\nX_train, y_train = load_csv('/kaggle/input/child-mind-institute-problematic-internet-use/train.csv')\nX_test, _ = load_csv('/kaggle/input/child-mind-institute-problematic-internet-use/test.csv')\n\n    # feature engineering\ncombined_df = pd.concat([X_train, X_test], ignore_index=True)\nprocessed_df = fa_data_preprocessing(combined_df)\nprocessed_df = fa_feature_engineering(processed_df)\nX_train = processed_df.iloc[:len(X_train)].reset_index(drop=True)\nX_test = processed_df.iloc[len(X_train):].reset_index(drop=True)\n\n# train_aef = X_train.drop('id', axis = 1)\n# test_aef = X_test.drop('id', axis = 1)\n# train_aef, encoders = label_encode(train_aef)\n# test_aef, _ = label_encode(test_aef, encoders)  \n# autoencoder, scaler = perform_autoencoder(train_aef, encoding_dim=60-17, epochs=100, batch_size=32)\n# X_train = pd.concat([X_train, encode_features(train_aef, autoencoder, scaler, prefix='FA_Enc_')], axis = 1)\n# X_test = pd.concat([X_test, encode_features(test_aef, autoencoder, scaler, prefix='FA_Enc_')], axis = 1)\n\n# Actigraphy features\ntrain_ts = load_time_series(\"/kaggle/input/child-mind-institute-problematic-internet-use/series_train.parquet\")\ntest_ts = load_time_series(\"/kaggle/input/child-mind-institute-problematic-internet-use/series_test.parquet\")\n\ntrain_aef = train_ts.filter(like='AEF_', axis=1)\ntest_aef = test_ts.filter(like='AEF_', axis=1)\nautoencoder, scaler = perform_autoencoder(train_aef, encoding_dim=60, epochs=100, batch_size=32)\ntrain_ts = pd.concat([train_ts, encode_features(train_aef, autoencoder, scaler, prefix='Ac_Enc_')], axis = 1)\ntest_ts = pd.concat([test_ts, encode_features(test_aef, autoencoder, scaler, prefix='Ac_Enc_')], axis = 1)\ntrain_ts.drop(train_aef.columns, axis = 1, inplace = True)\ntest_ts.drop(test_aef.columns, axis = 1, inplace = True)\n\n# Merge\nX_train = pd.merge(X_train, train_ts, how=\"left\", on='id')\nX_test = pd.merge(X_test, test_ts, how=\"left\", on='id')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:23:36.434561Z","iopub.execute_input":"2024-12-31T09:23:36.434931Z","iopub.status.idle":"2024-12-31T09:26:13.659165Z","shell.execute_reply.started":"2024-12-31T09:23:36.434890Z","shell.execute_reply":"2024-12-31T09:26:13.658251Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---","metadata":{}},{"cell_type":"markdown","source":"### Model","metadata":{}},{"cell_type":"code","source":"SEED = 42\nn_splits = 5\n  \ndef TrainML(model_class, X, y, X_test):\n    val_pred = pd.DataFrame()\n    test_pred = pd.DataFrame()\n\n    for target in tqdm(y.columns, desc=\"Training models for all labels\"):\n        val_pred[target] = np.zeros(len(y[target]))\n        test_pred[target] = np.zeros(len(X_test))\n\n        SKF = RepeatedStratifiedKFold(n_splits=n_splits, n_repeats=1, random_state=SEED)\n        for fold, (train_idx, val_idx) in enumerate(SKF.split(X, y[target])):\n            X_train, X_val = X.iloc[train_idx], X.iloc[val_idx]\n            y_train, y_val = y.loc[train_idx, target], y.loc[val_idx, target]\n\n            model = clone(model_class)\n            model.fit(X_train, y_train)\n            \n            val_pred.loc[val_idx, target] = model.predict(X_val)\n            test_pred[target] += model.predict(X_test) / n_splits\n\n    return test_pred, val_pred","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:26:13.660509Z","iopub.execute_input":"2024-12-31T09:26:13.661048Z","iopub.status.idle":"2024-12-31T09:26:13.667719Z","shell.execute_reply.started":"2024-12-31T09:26:13.661005Z","shell.execute_reply":"2024-12-31T09:26:13.666854Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Prediction","metadata":{}},{"cell_type":"code","source":"%%time\nPCIAT_score_labels = [\n        'PCIAT-PCIAT_01', 'PCIAT-PCIAT_02', 'PCIAT-PCIAT_03', 'PCIAT-PCIAT_04',\n        'PCIAT-PCIAT_05', 'PCIAT-PCIAT_06', 'PCIAT-PCIAT_07', 'PCIAT-PCIAT_08',\n        'PCIAT-PCIAT_09', 'PCIAT-PCIAT_10', 'PCIAT-PCIAT_11', 'PCIAT-PCIAT_12',\n        'PCIAT-PCIAT_13', 'PCIAT-PCIAT_14', 'PCIAT-PCIAT_15', 'PCIAT-PCIAT_16',\n        'PCIAT-PCIAT_17', 'PCIAT-PCIAT_18', 'PCIAT-PCIAT_19', 'PCIAT-PCIAT_20',]\n\n# ---\nidx = y_train[PCIAT_score_labels].notna().all(axis=1)\nmx = X_train[idx].reset_index(drop=True)\nmy = y_train[idx].reset_index(drop=True)[PCIAT_score_labels]\nmxt = X_test\n\nmx = mx.drop('id', axis=1)\nmxt = mxt.drop('id', axis=1)\n\nmx, encoders = label_encode(mx)\nmxt, _ = label_encode(mxt, encoders)  \n\n# -------\nParams7 = {'learning_rate': 0.03884249148676395, 'max_depth': 12, 'num_leaves': 413, 'min_data_in_leaf': 14,\n           'feature_fraction': 0.7987976913702801, 'bagging_fraction': 0.7602261703576205, 'bagging_freq': 2, \n           'lambda_l1': 4.735462555910575, 'lambda_l2': 4.735028557007343e-06} # CV : 0.4094 | LB : 0.471\n\nLight = lgb.LGBMRegressor(**Params7,random_state=SEED, verbose=-1,n_estimators=200)\n# Submission,model = TrainML(Light,mxt)\npred, val_pred = TrainML(Light, mx, my, mxt)\npred.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:26:13.668890Z","iopub.execute_input":"2024-12-31T09:26:13.669386Z","iopub.status.idle":"2024-12-31T09:28:53.428221Z","shell.execute_reply.started":"2024-12-31T09:26:13.669347Z","shell.execute_reply":"2024-12-31T09:28:53.427309Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Evaluation","metadata":{}},{"cell_type":"code","source":"def quadratic_weighted_kappa(y_true, y_pred):\n    return cohen_kappa_score(y_true, y_pred, weights='quadratic')\n\ndef threshold_rounder(target, thresholds, right=False):\n    thresholds = sorted(thresholds)\n    return np.digitize(target, thresholds, right)\n\ndef evaluate_predictions(thresholds, y_true, y_pred, right=False):\n    rounded_p = threshold_rounder(y_pred, thresholds, right=right)\n    return -quadratic_weighted_kappa(y_true, rounded_p)\n    \ndef QWK_optimize(y_true, y_train_non_rounded, y_test, x0=[i+0.5 for i in range(0, 5)], right=False):\n    KappaOPtimizer = minimize(evaluate_predictions,\n                              x0, args=(y_true, y_train_non_rounded, right), \n                              method='Nelder-Mead') # Nelder-Mead | # Powell\n    assert KappaOPtimizer.success, \"Optimization did not converge.\"\n    \n    y_train_opt = threshold_rounder(y_train_non_rounded, KappaOPtimizer.x)\n    y_test_opt = threshold_rounder(y_test, KappaOPtimizer.x)\n    \n    return y_test_opt, y_train_opt \n\ndef calculate_sii(PCIAT_scores : pd.DataFrame):\n    PCIAT_score_labels = [\n        'PCIAT-PCIAT_01', 'PCIAT-PCIAT_02', 'PCIAT-PCIAT_03', 'PCIAT-PCIAT_04',\n        'PCIAT-PCIAT_05', 'PCIAT-PCIAT_06', 'PCIAT-PCIAT_07', 'PCIAT-PCIAT_08',\n        'PCIAT-PCIAT_09', 'PCIAT-PCIAT_10', 'PCIAT-PCIAT_11', 'PCIAT-PCIAT_12',\n        'PCIAT-PCIAT_13', 'PCIAT-PCIAT_14', 'PCIAT-PCIAT_15', 'PCIAT-PCIAT_16',\n        'PCIAT-PCIAT_17', 'PCIAT-PCIAT_18', 'PCIAT-PCIAT_19', 'PCIAT-PCIAT_20',]\n    \n    # total_scores = PCIAT_scores.filter(items=PCIAT_score_labels, axis=1).sum(axis=1)\n    total_scores = PCIAT_scores[PCIAT_score_labels].sum(axis=1).round(0).astype(int)\n    sii = total_scores.apply(lambda score: \n                           0 if score <= 30 else \n                           1 if 31 <= score <= 49 else \n                           2 if 50 <= score <= 79 else \n                           3)\n    return sii","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:28:53.429643Z","iopub.execute_input":"2024-12-31T09:28:53.430048Z","iopub.status.idle":"2024-12-31T09:28:53.439572Z","shell.execute_reply.started":"2024-12-31T09:28:53.430002Z","shell.execute_reply":"2024-12-31T09:28:53.438639Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# PCIAT separated\ndef method_1():\n    val_pred_opt = val_pred.copy()\n    pred_opt = pred.copy()\n    \n    for col in my.columns:\n        y_test_opt, y_val_opt  = QWK_optimize(my[col], val_pred[col], pred[col])\n        val_pred_opt[col] = y_val_opt\n        pred_opt[col] = y_test_opt\n    \n        qwk = quadratic_weighted_kappa(my[col], val_pred[col].round(0).astype(int))\n        qwk_opt = quadratic_weighted_kappa(my[col], y_val_opt)\n    \n        # print(f\"{col}\\n ----> Optimized QWK SCORE :: {Fore.RED}{Style.BRIGHT} {qwk:.3f}{Style.RESET_ALL} > {Fore.CYAN}{Style.BRIGHT} {qwk_opt:.3f}{Style.RESET_ALL}\")\n    \n    \n    sii_qwk = quadratic_weighted_kappa(calculate_sii(my), calculate_sii(val_pred.round(0).astype(int)))\n    sii_qwk_opt = quadratic_weighted_kappa(calculate_sii(my), calculate_sii(val_pred_opt))\n    \n    print('='*20, '\\nmethod_1 : ')\n    print(f\"'SII' Validation QWK: {Fore.RED}{Style.BRIGHT} {sii_qwk:.3f}{Style.RESET_ALL}\")\n    print(f\"----> || Optimized QWK SCORE :: {Fore.CYAN}{Style.BRIGHT} {sii_qwk_opt:.3f}{Style.RESET_ALL}\")\n    \n    sii = calculate_sii(pred_opt)\n\n    return sii","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:28:53.441765Z","iopub.execute_input":"2024-12-31T09:28:53.442034Z","iopub.status.idle":"2024-12-31T09:28:53.455823Z","shell.execute_reply.started":"2024-12-31T09:28:53.442006Z","shell.execute_reply":"2024-12-31T09:28:53.455036Z"},"scrolled":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# PCIAT total\ndef method_2():\n    sii_val = calculate_sii(my)\n    pciat_total_val_pred = val_pred.sum(axis = 1)\n    pciat_total_pred = pred.sum(axis = 1)\n    \n    sii_pred_opt, sii_val_pred_opt = QWK_optimize(sii_val, pciat_total_val_pred, pciat_total_pred, x0=[30.5,49.5,79.5])\n    \n    sii_qwk = quadratic_weighted_kappa(sii_val, calculate_sii(val_pred.round(0).astype(int)))\n    sii_qwk_opt = quadratic_weighted_kappa(sii_val, sii_val_pred_opt)\n    \n    print('='*20, '\\nmethod_2 : ')\n    print(f\"'SII' Validation QWK: {Fore.RED}{Style.BRIGHT} {sii_qwk:.3f}{Style.RESET_ALL}\")\n    print(f\"----> || Optimized QWK SCORE :: {Fore.CYAN}{Style.BRIGHT} {sii_qwk_opt:.3f}{Style.RESET_ALL}\")\n    \n    sii = sii_pred_opt\n    \n    return sii","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:28:53.456809Z","iopub.execute_input":"2024-12-31T09:28:53.457109Z","iopub.status.idle":"2024-12-31T09:28:53.472104Z","shell.execute_reply.started":"2024-12-31T09:28:53.457082Z","shell.execute_reply":"2024-12-31T09:28:53.471286Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---","metadata":{}},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"sii_1 = method_1()\nsii_2 = method_2()\n\nSubmission = pd.DataFrame()\nSubmission['id'] = X_test['id']\nSubmission['sii'] = sii_1\nSubmission","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:28:53.473076Z","iopub.execute_input":"2024-12-31T09:28:53.473323Z","iopub.status.idle":"2024-12-31T09:29:01.007951Z","shell.execute_reply.started":"2024-12-31T09:28:53.473299Z","shell.execute_reply":"2024-12-31T09:29:01.007117Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Submission.to_csv('submission.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:29:01.009009Z","iopub.execute_input":"2024-12-31T09:29:01.009273Z","iopub.status.idle":"2024-12-31T09:29:01.014090Z","shell.execute_reply.started":"2024-12-31T09:29:01.009246Z","shell.execute_reply":"2024-12-31T09:29:01.013162Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pd.read_csv('submission.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-31T09:29:01.015062Z","iopub.execute_input":"2024-12-31T09:29:01.015336Z","iopub.status.idle":"2024-12-31T09:29:01.032474Z","shell.execute_reply.started":"2024-12-31T09:29:01.015295Z","shell.execute_reply":"2024-12-31T09:29:01.031684Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}