{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Student Performance from Game Play with pyspark\n\n---","metadata":{"id":"iCTA6kl3n2O1"}},{"cell_type":"markdown","source":"# Install and import libraries","metadata":{"id":"zAXHC6-Tn2O5"}},{"cell_type":"code","source":"!pip install pyspark  &> /dev/null","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from pyspark.sql import SparkSession\nfrom pyspark.sql.functions import udf, split, struct\nfrom pyspark.sql.types import *\n\nfrom pyspark.ml.feature import StringIndexer\nfrom pyspark.ml.feature import StandardScaler\n\nfrom pyspark.sql.functions import *\nfrom pyspark.sql.types import *\n\n\nfrom xgboost import XGBClassifier\nimport xgboost as xgb\n\n\nimport gc\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score\nfrom sklearn.preprocessing import MinMaxScaler\nimport pickle\n\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nimport jo_wilder\n\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n","metadata":{"id":"IanlX-Eqn2O5","execution":{"iopub.status.busy":"2023-05-20T13:00:26.293781Z","iopub.execute_input":"2023-05-20T13:00:26.294201Z","iopub.status.idle":"2023-05-20T13:00:27.768955Z","shell.execute_reply.started":"2023-05-20T13:00:26.294133Z","shell.execute_reply":"2023-05-20T13:00:27.767913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#load train file in pyspark\n\nPATH_FOLDER = '/kaggle/input/predict-student-performance-from-game-play/'\n\n# Create a SparkSession\nspark = SparkSession.builder.appName(\"MyApp\").getOrCreate()\n\n# Define schema for train.csv\ntrain_schema = StructType([\n    StructField(\"session_id\", LongType(), True),\n    StructField(\"index\", ShortType(), True),\n    StructField(\"elapsed_time\", IntegerType(), True),\n    StructField(\"event_name\", StringType(), True),\n    StructField(\"name\", StringType(), True),\n    StructField(\"level\", ByteType(), True),\n    StructField(\"page\", IntegerType(), True),\n    StructField(\"room_coor_x\", DoubleType(), True),\n    StructField(\"room_coor_y\", DoubleType(), True),\n    StructField(\"screen_coor_x\", DoubleType(), True),\n    StructField(\"screen_coor_y\", DoubleType(), True),\n    StructField(\"hover_duration\", DoubleType(), True),\n    StructField(\"text\", StringType(), True),\n    StructField(\"fqid\", StringType(), True),\n    StructField(\"room_fqid\", StringType(), True),\n    StructField(\"text_fqid\", StringType(), True),\n    StructField(\"fullscreen\", ByteType(), True),\n    StructField(\"hq\", ByteType(), True),\n    StructField(\"music\", ByteType(), True),\n    StructField(\"level_group\", StringType(), True)\n])\n\n# Load train.csv\ndf_train = spark.read.format(\"csv\").option(\"header\", True).schema(train_schema).load(PATH_FOLDER + \"train.csv\")\nprint ('**** output: df_train ****')","metadata":{"id":"gLpK2yAen2O7","execution":{"iopub.status.busy":"2023-05-20T13:00:27.771492Z","iopub.execute_input":"2023-05-20T13:00:27.771850Z","iopub.status.idle":"2023-05-20T13:00:37.909540Z","shell.execute_reply.started":"2023-05-20T13:00:27.771814Z","shell.execute_reply":"2023-05-20T13:00:37.908320Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## DATA TRANSFORMATION","metadata":{}},{"cell_type":"code","source":"def data_transformation(df):\n    # Select the numeric columns of the dataframe, excluding \"page\"\n    numeric_cols = [c for c, dtype in df.dtypes if dtype == 'double' and c != 'page']\n    \n    # Calculate the mean of the values in each numeric column, except \"page\"\n    means = df.agg(*(mean(c).alias(c) for c in numeric_cols)).first().asDict()\n\n    # Define the fill value for the \"page\" column as zero\n    fill_values = means\n    fill_values['page'] = 0\n\n    # Fill missing values with fill values\n    filled = df.fillna(fill_values)\n\n    # Fill missing data in hover_duration column with 0\n    filled = filled.fillna(0, subset=['hover_duration'])\n\n    # Drop rows with missing values in \"level_group\" column\n    filled = filled.na.drop(subset=[\"level_group\"])\n\n    # Check categorical columns and fill with 0\n    categorical_cols = [c for c, dtype in df.dtypes if dtype == 'string']\n    filled = filled.fillna('0', subset=categorical_cols)\n\n    # Transform categorical data into numerical data using StringIndexer\n    indexer = StringIndexer(inputCols=['event_name', 'name', 'fqid', 'text', 'room_fqid', 'text_fqid'],\n                            outputCols=['event_name_idx', 'name_idx', 'fqid_idx', 'text_idx', 'room_fqid_idx', 'text_fqid_idx'])\n    indexed = indexer.fit(filled).transform(filled)\n\n    categorical_cols = [c for c, dtype in indexed.dtypes if dtype == 'string' and c != 'level_group']\n    all_cols = indexed.columns\n    numeric_cols = [col_name for col_name in all_cols if col_name not in categorical_cols]\n    df_numeric = indexed.select(numeric_cols)\n\n    # Group the data by the specified column combination and calculate the mean of the remaining numeric columns\n    cols_for_group = ['elapsed_time', 'page', 'room_coor_x', 'room_coor_y', 'screen_coor_x', \n                      'screen_coor_y', 'hover_duration', 'fullscreen', 'hq', 'music','event_name_idx', 'name_idx', \n                      'fqid_idx', 'text_idx', 'room_fqid_idx', 'text_fqid_idx']\n    grouped = df_numeric.groupby(['session_id', 'level_group']).agg(*(avg(col(c)).alias(c) for c in cols_for_group))\n\n    # Define a mapping of old column names to new ones\n    column_mapping = {\n        'event_name_idx': 'event_name',\n        'name_idx': 'name',\n        'text_idx': 'text',\n        'fqid_idx': 'fqid',\n        'room_fqid_idx': 'room_fqid',\n        'text_fqid_idx': 'text_fqid',\n        'fullscreen': 'fullscreen',\n    }\n\n    # Rename columns using the mapping defined above\n    grouped = grouped.toDF(*[column_mapping.get(col, col) for col in grouped.columns])\n\n    # Transform pyspark dataframe to pandas datraframe\n    df_pandas = grouped.toPandas()\n    print('************** Done!!! ***************')\n\n    return df_pandas\n\ndftrain = data_transformation(df_train)","metadata":{"id":"-RTRVRiWn2O8","execution":{"iopub.status.busy":"2023-05-20T13:00:37.912390Z","iopub.execute_input":"2023-05-20T13:00:37.912762Z","iopub.status.idle":"2023-05-20T13:05:03.364407Z","shell.execute_reply.started":"2023-05-20T13:00:37.912723Z","shell.execute_reply":"2023-05-20T13:05:03.360658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## TEST.CSV ENGINEER FEATURES","metadata":{}},{"cell_type":"code","source":"from sklearn.impute import SimpleImputer\nfrom sklearn.preprocessing import LabelEncoder\n\n\n\ndef data_transformation_test(df):\n    # Seleciona as colunas numéricas do dataframe, excluindo \"page\"\n    numeric_cols = df.select_dtypes(include=np.number).columns.tolist()\n    numeric_cols = numeric_cols[2:]\n    numeric_cols.remove('page')\n    \n\n    # Preenche os valores faltantes com a média\n    imputer = SimpleImputer(missing_values=np.nan, strategy='mean')\n    df[numeric_cols] = imputer.fit_transform(df[numeric_cols])\n\n    # Preenche os valores faltantes em hover_duration com 0\n    df['hover_duration'] = df['hover_duration'].fillna(0)\n    df['page'] = df['page'].fillna(0)\n\n    # Seleciona as colunas categóricas do dataframe\n    categorical_cols = df.select_dtypes(include=['object']).columns.tolist()\n\n    # Preenche os valores faltantes em cada coluna categórica com \"0\"\n    df[categorical_cols] = df[categorical_cols].fillna('0')\n\n    # Transforma dados categóricos em dados numéricos usando LabelEncoder\n    le = LabelEncoder()\n    for col in categorical_cols:\n        df[col] = le.fit_transform(df[col])\n        \n    df = df.drop(columns=['index'])\n    #df = df.set_index('session_id')\n    \n    \"\"\"\n    Cria uma nova coluna \"level_group\" com base na coluna \"question\" do DataFrame df.\n    \"\"\"\n    # Define as condições para a criação da nova coluna \"level_group\"\n    conditions = [\n        (df[\"level_group\"] == 0),\n        (df[\"level_group\"] == 1),\n        (df[\"level_group\"] == 2)\n    ]\n\n    # Define os valores a serem atribuídos à nova coluna \"level_group\" de acordo com as condições\n    values = [\"0-4\", \"5-12\", \"13-22\"]\n\n    # Cria a nova coluna \"level_group\"\n    df[\"level_group\"] = pd.Series(np.select(conditions, values))\n#     # Criar um dicionário que mapeia os valores de \"level_group\" para seus respectivos valores numéricos\n#     level_group_dict = {'0-4': 0, '5-12': 1, '13-22': 2}\n#     df['level_group'] = df['level_group'].apply(lambda x: level_group_dict.get(x, 0))\n\n    return df\n\ndf_test  = pd.read_csv(PATH_FOLDER +'test.csv')\ntest_df = data_transformation_test(df_test)\nprint ('******* output: test_df ********')","metadata":{"id":"KD4uayl2n2O9","execution":{"iopub.status.busy":"2023-05-20T13:05:03.369256Z","iopub.execute_input":"2023-05-20T13:05:03.369658Z","iopub.status.idle":"2023-05-20T13:05:03.680593Z","shell.execute_reply.started":"2023-05-20T13:05:03.369621Z","shell.execute_reply":"2023-05-20T13:05:03.679259Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## TRAIN_LABEL.CSV ENGINEER FEATURES","metadata":{}},{"cell_type":"code","source":"#Define schema for train_labels.csv\ntrain_labels_schema = {\"session_id\": str, \"target\": int}\n\n#Load train_labels.csv into a Pandas DataFrame\ndf_train_labels = pd.read_csv(PATH_FOLDER + \"train_labels.csv\", dtype=train_labels_schema)\n\n#Extract session and question from session_id\ndf_train_labels[[\"session_id\", \"level\"]] = df_train_labels[\"session_id\"].str.split(\"_\", expand=True)\ndf_train_labels[\"session_id\"] = df_train_labels[\"session_id\"].str.extract('(\\d+)').astype(int)\ndf_train_labels[\"level\"] = df_train_labels[\"level\"].str.extract('(\\d+)').astype(int)","metadata":{"id":"Kva8_Dbqn2O9","execution":{"iopub.status.busy":"2023-05-20T13:05:03.682355Z","iopub.execute_input":"2023-05-20T13:05:03.682832Z","iopub.status.idle":"2023-05-20T13:05:08.965450Z","shell.execute_reply.started":"2023-05-20T13:05:03.682793Z","shell.execute_reply":"2023-05-20T13:05:08.964363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_level_group_column(df):\n    \"\"\"\n    Cria uma nova coluna \"level_group\" com base na coluna \"question\" do DataFrame df.\n    \"\"\"\n    # Define as condições para a criação da nova coluna \"level_group\"\n    conditions = [\n        (df[\"level\"] <= 3),\n        (df[\"level\"] <= 13),\n        (df[\"level\"] <= 22)\n    ]\n\n    # Define os valores a serem atribuídos à nova coluna \"level_group\" de acordo com as condições\n    values = [\"0-4\", \"5-12\", \"13-22\"]\n\n    # Cria a nova coluna \"level_group\"\n    df[\"level_group\"] = pd.Series(np.select(conditions, values))\n    # Criar um dicionário que mapeia os valores de \"level_group\" para seus respectivos valores numéricos\n    level_group_dict = {'0-4': 1, '5-12': 2, '13-22': 3}\n    df['session_level'] = df['level_group'].apply(lambda x: level_group_dict.get(x, 0))\n    \n    # Retorna o DataFrame com a nova coluna \"level_group\"\n    return df\n# Cria a nova coluna \"level_group\"\ntarget = create_level_group_column(df_train_labels)\nprint ('******* output: target ********')","metadata":{"id":"0eD-KZMvn2O-","execution":{"iopub.status.busy":"2023-05-20T13:05:08.966918Z","iopub.execute_input":"2023-05-20T13:05:08.967609Z","iopub.status.idle":"2023-05-20T13:05:09.347035Z","shell.execute_reply.started":"2023-05-20T13:05:08.967565Z","shell.execute_reply":"2023-05-20T13:05:09.346033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## PREPARING DATA","metadata":{"id":"7rQSOYAYqcZ2"}},{"cell_type":"code","source":"# Junte os dois dataframes usando as colunas 'session_id', 'level_group', 'level' e 'question'\njoined_df = pd.merge(target, dftrain, on=['session_id', 'level_group'], how='inner')\n#Drop the original session_id column\n#joined_df = joined_df.drop(\"level_group\", axis=1)\n\n# definir a ordem das colunas desejada\nnew_order = ['session_id', 'elapsed_time', 'event_name', 'name', 'level', 'page', 'room_coor_x', 'room_coor_y', 'screen_coor_x', 'screen_coor_y', 'hover_duration', 'text', 'fqid', 'room_fqid', 'text_fqid', 'fullscreen', 'hq', 'music', 'level_group', 'correct']\n\n# reorganizar as colunas em ordem\ndf_train = joined_df.reindex(columns=new_order)\nprint ('******* output: df_train ********')\n\n","metadata":{"id":"-l9wBCTYn2O_","execution":{"iopub.status.busy":"2023-05-20T13:05:09.348512Z","iopub.execute_input":"2023-05-20T13:05:09.349121Z","iopub.status.idle":"2023-05-20T13:05:09.639831Z","shell.execute_reply.started":"2023-05-20T13:05:09.349081Z","shell.execute_reply":"2023-05-20T13:05:09.638066Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## TRAINING MODEL WITH SVM","metadata":{}},{"cell_type":"code","source":"from sklearn.svm import SVC\n\nf1_scores = []  # List to store individual F1-scores\n\n# Define the feature columns and target column\nFEATURES = [c for c in df_train.columns if c != \"level_group\"]\ntarget_column = \"correct\"\n\n# Iterate over questions from 1 to 18\nfor i in range(1, 19):\n    print(f'Question {i}:')\n    target_column = 'correct'\n\n    # Select the dataset for the current question\n    current_question = df_train[df_train['level'] == i]\n\n    # Split the dataset into training and testing\n    X_train, X_test, y_train, y_test = train_test_split(current_question[FEATURES],\n                                                        current_question[target_column],\n                                                        test_size=0.3,\n                                                        random_state=42)\n\n    # Create and train the SVM model with desired parameters\n    model = SVC(kernel='rbf', C=1.0, random_state=42)\n    model.fit(X_train, y_train)\n\n    # Make predictions\n    y_pred = model.predict(X_test)\n\n    # Calculate the F1-score\n    f1 = f1_score(y_test, y_pred)\n    f1_scores.append(f1)  # Store the F1-score\n\n    print(f'F1-score: {f1}')\n\n# Calculate the average F1-score\naverage_f1 = np.mean(f1_scores)\nprint(f'Average F1-score: {average_f1}')\n\n","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:05:09.641863Z","iopub.execute_input":"2023-05-20T13:05:09.642291Z","iopub.status.idle":"2023-05-20T13:09:10.862235Z","shell.execute_reply.started":"2023-05-20T13:05:09.642241Z","shell.execute_reply":"2023-05-20T13:09:10.860462Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create and train the SVM model\nclf = model\nclf.fit(X_train, y_train)\n\n# Make predictions\ny_pred_scores = clf.decision_function(X_test)\n\n# Find the best threshold\nbest_threshold = None\nbest_f1_score = 0.0\n\nfor threshold in np.arange(-1.0, 1.1, 0.1):\n    y_pred = (y_pred_scores > threshold).astype(int)\n    f1 = f1_score(y_test, y_pred)\n\n    if f1 > best_f1_score:\n        best_f1_score = f1\n        best_threshold = threshold\n\nprint(\"Best Threshold:\", best_threshold)\nprint(\"Best F1-score:\", best_f1_score)","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:09:10.866833Z","iopub.execute_input":"2023-05-20T13:09:10.867284Z","iopub.status.idle":"2023-05-20T13:09:13.185268Z","shell.execute_reply.started":"2023-05-20T13:09:10.867236Z","shell.execute_reply":"2023-05-20T13:09:13.184237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create environment\nenv = jo_wilder.make_env()\niter_test = env.iter_test()","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:09:13.186664Z","iopub.execute_input":"2023-05-20T13:09:13.187288Z","iopub.status.idle":"2023-05-20T13:09:13.193542Z","shell.execute_reply.started":"2023-05-20T13:09:13.187249Z","shell.execute_reply":"2023-05-20T13:09:13.192399Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n\n\n\nlimits = {\"0-4\": (1, 4), \"5-12\": (4, 14), \"13-22\": (14, 19)}\n\n# # Get the list of features excluding the 'level_group' column\n# features = [c for c in test_df.columns if c != 'level_group']\n\n\n\nfor test, sample_submission in iter_test:\n    df = data_transformation_test(test)\n    label_encoder = LabelEncoder()\n    df[\"level_group\"] = label_encoder.fit_transform(df[\"level_group\"])\n\n    features = df.columns\n    for grp in limits:\n        a, b = limits[grp]\n        temp_df = df.copy()  # Criar uma cópia do DataFrame original\n        for t in range(a, b):\n            clf = model\n            temp_df[\"level_group\"] = label_encoder.transform([grp])[0]  # Definir o valor correto de level_group\n            p = clf.predict(temp_df[features].astype(\"float32\"))[0]\n            mask = sample_submission.session_id.str.contains(f\"q{t}\")\n            sample_submission.loc[mask, \"correct\"] = p\n\n    env.predict(sample_submission)\n\n","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:09:13.195176Z","iopub.execute_input":"2023-05-20T13:09:13.195871Z","iopub.status.idle":"2023-05-20T13:09:13.473194Z","shell.execute_reply.started":"2023-05-20T13:09:13.195831Z","shell.execute_reply":"2023-05-20T13:09:13.471622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import GroupKFold","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:09:13.474366Z","iopub.status.idle":"2023-05-20T13:09:13.475624Z","shell.execute_reply.started":"2023-05-20T13:09:13.475370Z","shell.execute_reply":"2023-05-20T13:09:13.475399Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"features = [c for c in df_train.columns if c != \"level_group\"]\nusers = df_train.index.unique()","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:09:13.476892Z","iopub.status.idle":"2023-05-20T13:09:13.477554Z","shell.execute_reply.started":"2023-05-20T13:09:13.477317Z","shell.execute_reply":"2023-05-20T13:09:13.477343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gkf = GroupKFold(n_splits=7)\noof = pd.DataFrame(\n    data=np.zeros((len(users), 18)),\n    index=users,\n)\nmodels = {}","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:09:13.479160Z","iopub.status.idle":"2023-05-20T13:09:13.479689Z","shell.execute_reply.started":"2023-05-20T13:09:13.479466Z","shell.execute_reply":"2023-05-20T13:09:13.479491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"target.head()","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:09:13.481332Z","iopub.status.idle":"2023-05-20T13:09:13.481904Z","shell.execute_reply.started":"2023-05-20T13:09:13.481687Z","shell.execute_reply":"2023-05-20T13:09:13.481710Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import GridSearchCV\nfrom sklearn.svm import SVC\n\n\nlabel_encoder = LabelEncoder()\ndf_train[\"level_group\"] = label_encoder.fit_transform(df_train[\"level_group\"])\nFEATURES = [c for c in df_train.columns if c != \"correct\"]\ny = df_train[\"correct\"]\nX = df_train[FEATURES]\n# Definir os parâmetros a serem ajustados\nparam_grid = {\n    'C': [0.1, 1.0, 10.0],\n    'kernel': ['linear', 'rbf'],\n}\n\n# Criar o modelo SVM\nsvm_model = SVC()\n\n# Realizar a busca em grade com validação cruzada\ngrid_search = GridSearchCV(estimator=svm_model, param_grid=param_grid, cv=5)\ngrid_search.fit(X, y)\n\n# Imprimir os melhores parâmetros encontrados\nprint(\"Melhores parâmetros: \", grid_search.best_params_)\n","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:39:32.772407Z","iopub.execute_input":"2023-05-20T13:39:32.774753Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.svm import SVC\n\nfor i, (train_index, test_index) in enumerate(gkf.split(X=df_train, groups=df_train.session_id)):\n    print(f\"Fold {i + 1} => \", end=\"\")\n\n    svm_params = {\n        \"kernel\": \"rbf\",\n        \"probability\": True,\n        \"C\": 1.0,\n        \"gamma\": \"scale\",\n    }\n\n    for t in range(1, 19):\n        if t <= 3:\n            grp = \"0-4\"\n        elif t <= 13:\n            grp = \"5-12\"\n        elif t <= 22:\n            grp = \"13-22\"\n\n        # Train data\n        train_x = df_train.iloc[train_index]\n        train_x = train_x.loc[train_x.level_group == grp]\n        train_users = train_x.session_id.values\n        train_y = target.loc[target.level == t].set_index(\"session_id\").loc[train_users]\n\n        # Valid data\n        valid_x = df_train.iloc[test_index]\n        valid_x = valid_x.loc[valid_x.level_group == grp]\n        valid_users = valid_x.session_id.values\n        valid_y = target.loc[target.level == t].set_index(\"session_id\").loc[valid_users]\n\n        # Train model\n        clf = SVC(**svm_params)\n        clf.fit(train_x[features].astype(\"float32\"), train_y[\"correct\"])\n\n        print(f\"{t}, \", end=\"\")\n\n        # Save model and predict valid oof\n        models[f\"{grp}_{t}\"] = clf\n        oof.loc[valid_users, t - 1] = clf.predict_proba(valid_x[features].astype(\"float32\"))[:, 1]\n\n    print()","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:09:13.485415Z","iopub.status.idle":"2023-05-20T13:09:13.486382Z","shell.execute_reply.started":"2023-05-20T13:09:13.486122Z","shell.execute_reply":"2023-05-20T13:09:13.486167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"limits = {\"0-4\": (1, 4), \"5-12\": (4, 14), \"13-22\": (14, 19)}\n\nfor test, sample_submission in iter_test:\n    # FEATURE ENGINEER TEST DATA\n    df = feature_engineer(test)\n\n    # INFER TEST DATA\n    grp = test.level_group.values[0]\n    a, b = limits[grp]\n    for t in range(a, b):\n        clf = models[f\"{grp}_{t}\"]\n        p = clf.predict_proba(df[features].astype(\"float32\"))[0, 1]\n        mask = sample_submission.session_id.str.contains(f\"q{t}\")\n        sample_submission.loc[mask, \"correct\"] = int(p > best_threshold)\n\n    env.predict(sample_submission)","metadata":{"execution":{"iopub.status.busy":"2023-05-20T13:09:13.487535Z","iopub.status.idle":"2023-05-20T13:09:13.488527Z","shell.execute_reply.started":"2023-05-20T13:09:13.488289Z","shell.execute_reply":"2023-05-20T13:09:13.488316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}