{"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.10.14"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":45533,"databundleVersionId":5748852,"sourceType":"competition"}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Predict Student Performance from Game Play","metadata":{}},{"cell_type":"markdown","source":"Tập dữ liệu cung cấp thông tin chi tiết về các sự kiện diễn ra trong các phiên chơi trò chơi giáo dục. Mỗi hàng đại diện cho một sự kiện cụ thể, bao gồm thời gian, vị trí, loại sự kiện, và các thuộc tính liên quan khác. Dữ liệu được thiết kế để hỗ trợ việc phân tích hành vi người chơi và dự đoán hiệu suất học tập.\n\n\n- session_id: ID của phiên chơi nơi sự kiện diễn ra.\n- index: Thứ tự của sự kiện trong một phiên chơi.\n- elapsed_time: Thời gian đã trôi qua (tính bằng mili-giây) kể từ khi bắt đầu phiên chơi đến khi sự kiện được ghi nhận.\n- event_name: Tên loại sự kiện (ví dụ: click, hover, mở/đóng một tài liệu).\n- name: Chi tiết cụ thể về sự kiện (ví dụ: mở hay đóng sổ ghi chép).\n- level: Cấp độ trò chơi mà sự kiện diễn ra (từ 0 đến 22).\n- page: Số trang liên quan đến sự kiện (chỉ áp dụng cho các sự kiện liên quan đến sổ ghi chép).\n- room_coor_x, room_coor_y: Tọa độ nhấp chuột trong không gian trò chơi (chỉ áp dụng cho sự kiện click).\n- screen_coor_x, screen_coor_y: Tọa độ nhấp chuột trên màn hình người chơi (chỉ áp dụng cho sự kiện click).\n- hover_duration: Thời gian người chơi di chuột (tính bằng mili-giây) (chỉ áp dụng cho sự kiện hover).\n- text: Nội dung văn bản mà người chơi thấy trong sự kiện.\n- fqid: ID đầy đủ của sự kiện.\n- room_fqid: ID đầy đủ của phòng nơi sự kiện diễn ra.\n- text_fqid: ID đầy đủ của văn bản trong sự kiện.\n- fullscreen: Trạng thái toàn màn hình (1: bật, 0: tắt).\n- hq: Trạng thái chất lượng cao (1: bật, 0: tắt).\n- music: Trạng thái âm nhạc (1: bật, 0: tắt).\n- level_group: Nhóm cấp độ và câu hỏi mà sự kiện thuộc về:\n    - 0-4: Cấp độ từ 0 đến 4.\n    - 5-12: Cấp độ từ 5 đến 12.\n    - 13-22: Cấp độ từ 13 đến 22.","metadata":{}},{"cell_type":"markdown","source":"# Gọi Các Thư Viện Cần Dùng","metadata":{}},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\nfrom matplotlib import colormaps\nfrom sklearn.preprocessing import MinMaxScaler\nfrom keras.models import Sequential\nfrom keras.layers import Dense\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:47:41.872912Z","iopub.status.busy":"2024-12-07T22:47:41.872534Z","iopub.status.idle":"2024-12-07T22:47:58.311946Z","shell.execute_reply":"2024-12-07T22:47:58.310794Z","shell.execute_reply.started":"2024-12-07T22:47:41.872864Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Đọc File Train.csv\n\n- Định nghĩa kiểu dữ liệu (dtypes): Giảm dung lượng bộ nhớ bằng cách chỉ định kiểu dữ liệu cho các cột trong tệp CSV.\n- Đọc dữ liệu theo từng phần (chunksize): Tải tệp lớn thành từng phần nhỏ (100.000 dòng mỗi phần) để tránh quá tải bộ nhớ.\n- Ghép dữ liệu: Sử dụng pd.concat() để gộp tất cả các phần đã đọc thành một DataFrame duy nhất.\n- Kiểm tra dữ liệu: Hiển thị kích thước và một số dòng đầu tiên để kiểm tra","metadata":{}},{"cell_type":"code","source":"# Reference: https://www.kaggle.com/code/cdeotte/random-forest-baseline-0-664/notebook\ndtypes={\n    'elapsed_time':np.int32,\n    'event_name':'category',\n    'name':'category',\n    'level':np.uint8,\n    'room_coor_x':np.float32,\n    'room_coor_y':np.float32,\n    'screen_coor_x':np.float32,\n    'screen_coor_y':np.float32,\n    'hover_duration':np.float32,\n    'text':'category',\n    'fqid':'category',\n    'room_fqid':'category',\n    'text_fqid':'category',\n    'fullscreen':'category',\n    'hq':'category',\n    'music':'category',\n    'level_group':'category'}\n\n# Kích thước mỗi phần\nchunk_size = 100000  \nchunk_list = []  # Danh sách lưu các phần\n\n# Đọc tệp CSV theo từng phần\nfor chunk in pd.read_csv('/kaggle/input/predict-student-performance-from-game-play/train.csv', \n                         dtype=dtypes, chunksize=chunk_size):\n    chunk_list.append(chunk)  # Thêm từng phần vào danh sách\n\n# Ghép tất cả các phần lại nếu cần\ntrain_df = pd.concat(chunk_list, axis=0)\n\n\n# # Đọc 100,000 dòng đầu tiên từ tệp CSV\n# file_path = 'predict-student-performance-from-game-play/train.csv'\n# train_df = pd.read_csv(file_path, dtype=dtypes, nrows=1000000)\n\n# Kiểm tra kích thước và hiển thị dữ liệu\nprint(\"Train dataset shape is: \", train_df.shape)\ntrain_df.head()","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:47:58.314121Z","iopub.status.busy":"2024-12-07T22:47:58.313525Z","iopub.status.idle":"2024-12-07T22:50:31.603842Z","shell.execute_reply":"2024-12-07T22:50:31.602619Z","shell.execute_reply.started":"2024-12-07T22:47:58.314085Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Tiền Xử Lý Dữ Liệu","metadata":{}},{"cell_type":"markdown","source":"- Xác định giá trị thiếu trong DataFrame\n- Trực quan hóa giá trị thiếu","metadata":{}},{"cell_type":"code","source":"def get_missing_values(data_frame, stat=\"count\"):\n    missing_values = data_frame.isnull().sum()\n    \n    if stat == \"percentage\":\n        num_samples = len(data_frame)\n        missing_values = (missing_values / num_samples) * 100\n    \n    columns = missing_values.index.tolist()\n    values = missing_values.values\n    \n    missing_values_data_frame = pd.DataFrame({\n        \"column\": columns,\n        \"missing_values\": values,\n    })\n    \n    return missing_values_data_frame\n\nmissing_values = get_missing_values(train_df, stat=\"percentage\")\n\n# Ví dụ dữ liệu\ncolumns = missing_values['column']\nmissing_values_percentage = missing_values['missing_values']\n\n# Tạo danh sách màu tự động dựa trên số lượng giá trị\nnum_colors = len(columns)  # Số lượng giá trị trong biểu đồ\ncolors = colormaps['tab20'](range(num_colors))  # Sử dụng bảng màu 'tab10'\n# print(colors)\n\n# Tạo biểu đồ\nfigure = plt.figure(figsize=(20, 7))\naxis = figure.add_subplot()\naxis.grid(axis=\"y\", zorder=0)\n\n# Vẽ biểu đồ thanh\naxis.bar(columns, missing_values_percentage, color=colors, alpha=1.0, zorder=2)\n\n# Định dạng biểu đồ\naxis.set_xlabel(\"Column\", fontsize=17)\naxis.set_ylabel(\"Missing Values (%)\", fontsize=14)\naxis.set_xticks(range(len(columns)))  # Đánh dấu các cột\naxis.set_xticklabels(columns, fontsize=14, rotation=40)  # Nhãn x\naxis.yaxis.set_tick_params(labelsize=12)\naxis.set_yticks(range(0, 110, 10))  # Tùy chỉnh mức y\naxis.set_title(\"Missing Values per Column\", fontsize=18)\n\n# Hiển thị biểu đồ\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:50:31.605737Z","iopub.status.busy":"2024-12-07T22:50:31.605184Z","iopub.status.idle":"2024-12-07T22:50:37.206926Z","shell.execute_reply":"2024-12-07T22:50:37.206128Z","shell.execute_reply.started":"2024-12-07T22:50:31.605699Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Xóa các cột bị miss trên 70%","metadata":{}},{"cell_type":"code","source":"# Xóa các cột bị miss trên 70%\nmissed_columns = [\"page\", \"hover_duration\"]\ntrain_df = train_df.drop(missed_columns, axis=1)","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:50:37.210272Z","iopub.status.busy":"2024-12-07T22:50:37.208564Z","iopub.status.idle":"2024-12-07T22:50:39.551901Z","shell.execute_reply":"2024-12-07T22:50:39.550299Z","shell.execute_reply.started":"2024-12-07T22:50:37.210236Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Đọc file train_labels.csv","metadata":{}},{"cell_type":"code","source":"labels = pd.read_csv('/kaggle/input/predict-student-performance-from-game-play/train_labels.csv')\nlabels['session'] = labels.session_id.apply(lambda x: int(x.split('_')[0]) )\nlabels['q'] = labels.session_id.apply(lambda x: int(x.split('_')[-1][1:]) )\n# Display the first 5 examples\nlabels.head(5)","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:50:39.555620Z","iopub.status.busy":"2024-12-07T22:50:39.555094Z","iopub.status.idle":"2024-12-07T22:50:40.685870Z","shell.execute_reply":"2024-12-07T22:50:40.684579Z","shell.execute_reply.started":"2024-12-07T22:50:39.555562Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Trực quan hóa phân phối của file train_labels.csv","metadata":{}},{"cell_type":"code","source":"plot_df = labels.correct.value_counts()\n\n# Tạo danh sách màu tự động dựa trên số lượng giá trị\nnum_colors = len(plot_df)  # Số lượng giá trị trong biểu đồ\ncolors = colormaps['tab10'](range(num_colors))  # Sử dụng bảng màu 'tab10'\n\nplot_df.plot(kind=\"bar\", color=colors, figsize=(2, 3))\n\n\n# Thêm tiêu đề và nhãn trục\nplt.title(\"Phân phối giá trị cột 'correct'\", fontsize=14)\nplt.xlabel(\"Giá trị (Correct: 1/0)\", fontsize=12)\nplt.ylabel(\"Tần số\", fontsize=12)\nplt.xticks(rotation=0)\nplt.show()","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:50:40.687706Z","iopub.status.busy":"2024-12-07T22:50:40.687353Z","iopub.status.idle":"2024-12-07T22:50:40.903055Z","shell.execute_reply":"2024-12-07T22:50:40.901691Z","shell.execute_reply.started":"2024-12-07T22:50:40.687674Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Reference: https://www.kaggle.com/code/cdeotte/random-forest-baseline-0-664/notebook\n\nplt.figure(figsize=(10, 20))\nplt.subplots_adjust(hspace=0.5, wspace=0.5)\nplt.suptitle(\"\\\"Correct\\\" column values for each question\", fontsize=14, y=0.94)\n\n# Tạo danh sách màu tự động dựa trên số lượng giá trị\nnum_colors = len(plot_df)  # Số lượng giá trị trong biểu đồ\ncolors = colormaps['tab10'](range(num_colors))  # Sử dụng bảng màu 'tab10'\n\n# Lấy các giá trị duy nhất trong cột 'q'\nunique_q_values = labels[\"q\"].unique()\n\n# Lặp qua từng câu hỏi\nfor n in unique_q_values:\n    ax = plt.subplot(10, 4, n)\n    \n    # Lọc dữ liệu cho câu hỏi n\n    plot_df = labels.loc[labels.q == n]\n    if not plot_df.empty:  # Kiểm tra nếu có dữ liệu\n        plot_df = plot_df.correct.value_counts()\n        \n        # Vẽ biểu đồ\n        plot_df.plot(ax=ax, kind=\"bar\", color=colors, edgecolor='black')\n        \n        # Định dạng biểu đồ\n        ax.set_title(f\"Question {n}\", fontsize=10)\n        ax.set_xlabel(\"\")\n        ax.tick_params(axis='x', labelrotation=0)\n\n    else:\n        ax.set_title(f\"Question {n} (No Data)\", fontsize=10)\n        ax.axis(\"off\")  # Ẩn trục nếu không có dữ liệu\n\nplt.tight_layout(rect=[0, 0, 1, 0.94])\nplt.show()","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:50:40.904519Z","iopub.status.busy":"2024-12-07T22:50:40.904222Z","iopub.status.idle":"2024-12-07T22:50:43.759073Z","shell.execute_reply":"2024-12-07T22:50:43.757251Z","shell.execute_reply.started":"2024-12-07T22:50:40.904492Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Tạo Đặc Trưng (Feature engineering process)","metadata":{}},{"cell_type":"markdown","source":"- Các cột CATEGORICAL đếm số lượng giá trị duy nhất trong từng nhóm\n- Các cột NUMERICAL: Tính trung bình (mean) và độ lệch chuẩn (std) cho mỗi nhóm.\n- Chuẩn hóa (0 ,1)","metadata":{}},{"cell_type":"code","source":"# Reference: https://www.kaggle.com/code/cdeotte/random-forest-baseline-0-664/notebook\n# Danh sách cột\nCATEGORICAL = ['event_name', 'name', 'fqid', 'room_fqid', 'text_fqid']\nNUMERICAL = ['elapsed_time', 'level', 'room_coor_x', 'room_coor_y', \n             'screen_coor_x', 'screen_coor_y']\n\ndef feature_engineer(dataset_df):\n    dfs = []\n    for c in CATEGORICAL:\n        tmp = dataset_df.groupby(['session_id','level_group'], observed=False)[c].agg('nunique')\n        tmp.name = tmp.name + '_nunique'\n        dfs.append(tmp)\n    for c in NUMERICAL:\n        tmp = dataset_df.groupby(['session_id','level_group'], observed=False)[c].agg('mean')\n        dfs.append(tmp)\n    for c in NUMERICAL:\n        tmp = dataset_df.groupby(['session_id','level_group'], observed=False)[c].agg('std')\n        tmp.name = tmp.name + '_std'\n        dfs.append(tmp)\n    dataset_df = pd.concat(dfs,axis=1)\n    dataset_df = dataset_df.fillna(-1)\n    dataset_df = dataset_df.reset_index()\n    cols = dataset_df.columns.tolist()\n    cols.remove('session_id')\n    cols.remove('level_group')\n    \n    \n    # Chuẩn hóa các cột số\n    scaler = MinMaxScaler(feature_range=(0, 1))\n    dataset_df[cols] = scaler.fit_transform(dataset_df[cols])\n\n    return dataset_df\n\n\ntrain_df = feature_engineer(train_df)\ntrain_df.head()\n","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:50:43.761318Z","iopub.status.busy":"2024-12-07T22:50:43.760982Z","iopub.status.idle":"2024-12-07T22:51:22.304497Z","shell.execute_reply":"2024-12-07T22:51:22.303068Z","shell.execute_reply.started":"2024-12-07T22:50:43.761285Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.shape","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:51:22.307076Z","iopub.status.busy":"2024-12-07T22:51:22.306639Z","iopub.status.idle":"2024-12-07T22:51:22.314454Z","shell.execute_reply":"2024-12-07T22:51:22.313642Z","shell.execute_reply.started":"2024-12-07T22:51:22.307040Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"- Xác định level_group cho cho từng lable\n- Đổi tên cột 'session': 'session_id' để lát nữa gắn nhẵn","metadata":{}},{"cell_type":"code","source":"# Hàm để xác định level_group dựa trên giá trị của q\ndef get_level_group(q_no):\n    if q_no <= 3:\n        return '0-4'\n    elif q_no <= 13:\n        return '5-12'\n    elif q_no <= 22:\n        return '13-22'\n    else:\n        return 'Above 22'\n\nlabels['level_group'] = labels['q'].apply(get_level_group)  \nnew_col = ['session', 'level_group', 'correct','q']\nlabels_df = labels[new_col].rename(columns={'session': 'session_id'})\nlabels_df.head()","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:51:22.318524Z","iopub.status.busy":"2024-12-07T22:51:22.318210Z","iopub.status.idle":"2024-12-07T22:51:22.447225Z","shell.execute_reply":"2024-12-07T22:51:22.446449Z","shell.execute_reply.started":"2024-12-07T22:51:22.318496Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":" # Gắn Nhãn ","metadata":{}},{"cell_type":"markdown","source":"Gắn nhãn cho tập train bằng merge dựa trên 2 cột 'session_id', 'level_group'","metadata":{}},{"cell_type":"code","source":"\ntrain_df = pd.merge(train_df, labels_df, on=['session_id', 'level_group'], how='inner')\ntrain_df.head()","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:51:22.448392Z","iopub.status.busy":"2024-12-07T22:51:22.448097Z","iopub.status.idle":"2024-12-07T22:51:22.619983Z","shell.execute_reply":"2024-12-07T22:51:22.619018Z","shell.execute_reply.started":"2024-12-07T22:51:22.448364Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":" # Huấn Luyện Mô Hình logistic regression","metadata":{}},{"cell_type":"markdown","source":"- với  mỗi câu hỏi, tạo 1 model để huấn luyện riêng\n- Chia tập train thành 2 tập train(80%) và valid(20%)\n- Framework sử dụng là Keras. \n- Mô hình là Mạng nơ-ron 1 lớp ẩn\n    - hàm kích hoạt của lớp ẩn: relu\n    - hàm kích hoạt của output : sigmoid (để phân loại nhị phân)\n    - Tối ưu: adam\n    - hàm mất mát: binary crossentropy\n    - độ lỗi: accuracy","metadata":{}},{"cell_type":"code","source":"models = {}\n\nfor q_no in range(1,19):\n    \n    # Select level group for the question based on the q_no.\n    if q_no<=3: grp = '0-4'\n    elif q_no<=13: grp = '5-12'\n    elif q_no<=22: grp = '13-22'\n    print(\"### q_no\", q_no, \"grp\", grp)\n    df = train_df.loc[train_df.level_group == grp].loc[train_df.q == q_no]\n\n    # Tách các cột features và labels\n    X = df.drop(columns=['correct', 'level_group','session_id','q'])  # Các đặc trưng\n    y = df['correct']  # Nhãn\n\n    # Chia tập dữ liệu thành train và valid (80% train, 20% valid)\n    X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=42)\n\n    # Xây dựng mô hình Keras\n    model = Sequential()\n    model.add(Dense(20, input_dim=X_train.shape[1], activation='relu'))  # Lớp ẩn với 20 nút\n    model.add(Dense(1, activation='sigmoid'))  # Lớp đầu ra với kích thước 1 và hàm kích hoạt sigmoid\n\n    # Biên dịch mô hình\n    model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n\n    # Huấn luyện mô hình\n    model.fit(X_train, y_train, epochs=3, batch_size=32, validation_data=(X_valid, y_valid), verbose=1)\n\n    # Dự đoán trên tập valid\n    y_pred = model.predict(X_valid)\n    y_pred = (y_pred > 0.5).astype(int)  # Chuyển dự đoán thành 0 hoặc 1\n\n    # Tính độ chính xác (accuracy)\n    accuracy = accuracy_score(y_valid, y_pred)\n    print(f\"Accuracy for q_no {q_no} (Group {grp}): {accuracy:.4f}\")\n    models[q_no] = model\n\nmodels","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:51:22.621527Z","iopub.status.busy":"2024-12-07T22:51:22.621212Z","iopub.status.idle":"2024-12-07T22:52:53.340090Z","shell.execute_reply":"2024-12-07T22:52:53.338375Z","shell.execute_reply.started":"2024-12-07T22:51:22.621492Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# TEST","metadata":{}},{"cell_type":"code","source":"import jo_wilder_310\nenv = jo_wilder_310.make_env()\niter_test = env.iter_test() ","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:54:22.017423Z","iopub.status.busy":"2024-12-07T22:54:22.017014Z","iopub.status.idle":"2024-12-07T22:54:22.050672Z","shell.execute_reply":"2024-12-07T22:54:22.049238Z","shell.execute_reply.started":"2024-12-07T22:54:22.017393Z"},"trusted":true},"outputs":[],"execution_count":null},{"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    test_df = feature_engineer(test)\n    \n    grp = test_df.level_group.values[0]\n    # Chuyển dictionary sang pandas DataFrame\n    test_df = test_df.loc[:, ~test_df.columns.isin(['level_group', 'session_id'])]\n    test_ds = pd.DataFrame(test_df)\n    \n    a,b = limits[grp]\n    for t in range(a,b):\n        \n        gbtm = models[t]\n        predictions = gbtm.predict(test_ds)\n        mask = sample_submission.session_id.str.contains(f'q{t}')\n        n_predictions = (predictions > 0.5).astype(int)\n        sample_submission.loc[mask,'correct'] = n_predictions.flatten()\n    \n    env.predict(sample_submission)","metadata":{"execution":{"iopub.execute_input":"2024-12-07T22:56:16.643991Z","iopub.status.busy":"2024-12-07T22:56:16.643266Z","iopub.status.idle":"2024-12-07T22:56:19.996231Z","shell.execute_reply":"2024-12-07T22:56:19.994797Z","shell.execute_reply.started":"2024-12-07T22:56:16.643910Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sub = pd.read_csv('submission.csv')\nsub","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}