{"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":"# 1. Giới thiệu bài toán\n","metadata":{"_kg_hide-input":false}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Trong bối cảnh sự nóng lên của toàn cầu ảnh hưởng đến khí hậu Trái Đất và sự diễn ra khó lường của các thiên tai, hiện tượng tự nhiên khắc nhiệt, dự báo động đất là một trong những vấn đề quan trọng của khoa học và ngành khí tượng nói chung do những hậu quả, thiệt hại tàn khốc mà chúng gây ra. Những nghiên cứu hiện nay về vấn đề này thường tập trung vào ba yếu tố: diễn ra khi nào, tại khu vực nào và quy mô ra sao. </p>\n<p style=\"font-size:18px\"> Trong bài toán này, mục tiêu của chúng ta dự đoán khi động đất xảy ra. Cụ thể là dự đoán khoảng thời gian còn lại trước khi các trận động đất xảy ra từ dữ liệu địa chấn theo thời gian thực. Nếu dự đoán được càng sớm và càng chính xác thì chúng ta sẽ có được những cảnh báo và đưa ra những biễn pháp để giảm thiểu hậu quả, rủi ro và có thể cứu sống rất nhiều người. </p>\n","metadata":{}},{"cell_type":"markdown","source":"# 2. Mô tả dữ liệu\n","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\">\nDữ liệu được sử dụng cho việc huấn luyện mô hình gồm 2 trường trong file csv: <code>train.csv</code>\n</p>\n\n<p style=\"font-size:18px\">\n    <code>acoustic_data</code>: Đây là dữ liệu địa chấn thu được dựa trên những phương pháp đo thực tế. Là cường độ sóng thu được từ lòng đất với kiểu số nguyên <i>int16</i>.<br>\n    <code>time_to_failure</code>: Đây là thời gian mà trận động đất tiếp theo sẽ xảy ra trên thời gian thực tính bằng giây với kiểu số thực <i>float64</i>.\n</p>\n\n<p style=\"font-size:18px\"> Trong mỗi lần thử nghiệm, dữ liệu địa chấn hay cường độ sóng và khoảng thời gian còn lại trước khi động đất xảy ra được đo trong 0.0375s (được sắp xếp theo thời gian) và tần số 4MHz (thông tin được cung cấp bởi BTC cuộc thi). Từ đó, ta sẽ có 150000 data points cho mỗi một measurement segment. File <code>train.csv</code> bao gồm 629145480 records tương ứng với khoảng 4194 measurement segments.\n</p>\n    \n<p style=\"font-size:18px\">\n<code>test</code>: là một folder bao gồm nhiều file csv, mỗi một file là dữ liệu địa chấn của 1 measurement segment gồm 150000 data points.<br>\nMỗi file test csv ứng với một <code>seg_id</code>, là id của measurement segment tương ứng được thử nghiệm, kết quả của bài toán sẽ là kết quả dự đoán thực hiện trên các <code>seg_id</code> này.\n</p>\n\n<p style=\"font-size:18px\">\n<code>sample_submission.csv</code>: là mẫu submission file của cuộc thi.\n</p>","metadata":{}},{"cell_type":"markdown","source":"## 2.1. Chuẩn bị thư viện và đường dẫn","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Trước tiên, chúng ta cần import các thư viện, package sẽ sử dụng trong notebook. </p>","metadata":{}},{"cell_type":"code","source":"import re\nimport warnings\nimport numpy as np\nimport pandas as pd\nimport lightgbm as lgb\nimport matplotlib.pyplot as plt\n\nfrom tqdm.notebook import tqdm\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.ensemble import AdaBoostRegressor, VotingRegressor\nfrom sklearn.model_selection import KFold, RandomizedSearchCV, train_test_split, cross_val_score\nfrom sklearn.linear_model import Ridge\nfrom sklearn.metrics import mean_absolute_error\n\nwarnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2021-12-22T15:23:10.576972Z","iopub.execute_input":"2021-12-22T15:23:10.577393Z","iopub.status.idle":"2021-12-22T15:23:13.449643Z","shell.execute_reply.started":"2021-12-22T15:23:10.577307Z","shell.execute_reply":"2021-12-22T15:23:13.448804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Cài đặt các đường dẫn: </p>","metadata":{}},{"cell_type":"code","source":"# path config\ntest_folder_path = \"/kaggle/input/LANL-Earthquake-Prediction/test\"\nsample_submission_path = \"/kaggle/input/LANL-Earthquake-Prediction/sample_submission.csv\"\ntrain_path = \"/kaggle/input/LANL-Earthquake-Prediction/train.csv\"","metadata":{"execution":{"iopub.status.busy":"2021-12-22T15:23:21.804969Z","iopub.execute_input":"2021-12-22T15:23:21.80558Z","iopub.status.idle":"2021-12-22T15:23:21.812445Z","shell.execute_reply.started":"2021-12-22T15:23:21.805536Z","shell.execute_reply":"2021-12-22T15:23:21.81175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2.2. File train.csv","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> File train.csv có dung lượng 9.56GB nên thời gian đọc rất lâu và tương đối tốn RAM. Nên chúng ta sử dụng thư viện Pandas để hỗ trợ đọc file CSV thành một dataframe. </p>","metadata":{}},{"cell_type":"code","source":"%%time\n\n# create dataframe from csv file\ndf_train = pd.read_csv(train_path, dtype={\"acoustic_data\": np.int16, \"time_to_failure\": np.float64})\ndf_train.shape","metadata":{"execution":{"iopub.status.busy":"2021-12-22T15:28:07.346415Z","iopub.execute_input":"2021-12-22T15:28:07.347001Z","iopub.status.idle":"2021-12-22T15:31:27.674712Z","shell.execute_reply.started":"2021-12-22T15:28:07.346965Z","shell.execute_reply":"2021-12-22T15:31:27.673999Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\">Data frame df_train có kích thước (629145480, 2)\n. Từ bộ dữ liệu này, chúng ta sẽ cần tạo ra các feature để làm dữ liệu huấn luyện mô hình.<br>\nTrong đó, 5 dòng đầu tiên của df_train:\n</p>","metadata":{}},{"cell_type":"code","source":"df_train.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:45.988238Z","iopub.execute_input":"2021-12-21T02:58:45.988514Z","iopub.status.idle":"2021-12-21T02:58:46.013296Z","shell.execute_reply.started":"2021-12-21T02:58:45.988474Z","shell.execute_reply":"2021-12-21T02:58:46.012553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\">Do pandas không thể hiện thị toàn bộ các chữ số sau dấu phẩy, nên ta sẽ hiển thị 10 chữ số sau dấu phẩy của dữ liệu số để thấy được sự thay đổi của trường <code>time_to_failure</code> (thời gian). </p>","metadata":{}},{"cell_type":"code","source":"# setting 10 digits for float type\npd.options.display.precision = 11\ndf_train.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:46.016938Z","iopub.execute_input":"2021-12-21T02:58:46.017178Z","iopub.status.idle":"2021-12-21T02:58:46.026929Z","shell.execute_reply.started":"2021-12-21T02:58:46.01715Z","shell.execute_reply":"2021-12-21T02:58:46.026125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## df_train\n* <p style=\"font-size:18px\"> Data frame df_train có lượng dữ liệu rất lớn và là dữ liệu thô lấy từ thực nghiệm. </p>\n* <p style=\"font-size:18px\"> Field <code>time_to_failure</code> giảm dần theo mỗi record và mỗi  measurement segment.  </p>\n","metadata":{}},{"cell_type":"markdown","source":"## 2.3. File test","metadata":{}},{"cell_type":"code","source":"%%time\n\n# create dataframe from first csv test file\ndf_test = pd.read_csv(test_folder_path + \"/seg_00030f.csv\", dtype={\"acoustic_data\": np.int16})\ndf_test.shape","metadata":{"execution":{"iopub.status.busy":"2021-12-22T15:23:24.827624Z","iopub.execute_input":"2021-12-22T15:23:24.828422Z","iopub.status.idle":"2021-12-22T15:23:24.875783Z","shell.execute_reply.started":"2021-12-22T15:23:24.828363Z","shell.execute_reply":"2021-12-22T15:23:24.875111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Các file test sẽ có kích thước (150000, 1) tương đương với 1 measurement segment, do đó phải dự đoán 150000 mốc thời gian <code>time_to_failure</code> cho mỗi data points.\n</p>","metadata":{}},{"cell_type":"markdown","source":"## test_train\n* <p style=\"font-size:18px\"> Dataframe test_train có lượng dữ liệu tương đương với một measurement segment và cần dự đoán về khoảng thời gian còn lại trước khi xảy ra động đất . </p>","metadata":{}},{"cell_type":"markdown","source":"# 3. Phân tích dữ liệu ","metadata":{}},{"cell_type":"markdown","source":"## 3.1. Kiểm tra tỉ lệ thiếu giá trị với cả 2 datasets df_train và df_test\n<p style=\"font-size:18px\"> Ta sẽ sử dụng thư viện <code>matplotlib</code> - thư viện hỗ trợ vẽ và biểu diễn các biểu đồ dữ liệu.<br>\nỞ đây chúng ta sẽ tính toán tỉ lệ thiếu giá trị trên mỗi trường của 2 datasets.\n</p>","metadata":{}},{"cell_type":"code","source":"# calculate missing value percentage and plot\ndef plot_null_percentage():\n    # total null value in both datasets\n    null_train_col_1 = df_train[\"acoustic_data\"].isnull().sum()\n    null_train_col_2 = df_train[\"time_to_failure\"].isnull().sum()\n    null_test = df_test[\"acoustic_data\"].isnull().sum()\n    \n    # create figure and subplots\n    figure, axs = plt.subplots(nrows=1, ncols=3, figsize=(15, 5))\n    figure.set_facecolor(\"white\")\n    figure.suptitle(\"Missing value percentage of train and test datasets\")\n\n    # plot in pie\n    axs[0].pie([null_train_col_1, len(df_train) - null_train_col_1], labels=[\"missing\", \"filled\"], explode=(0, 0.01), autopct=\"%1.1f%%\", labeldistance=1.1, startangle=55, colors=[\"red\", \"green\"])\n    axs[0].set_title(\"df_train: acoustic_data\", pad=10)\n    axs[1].pie([null_train_col_2, len(df_train) - null_train_col_2], labels=[\"missing\", \"filled\"], explode=(0, 0.01), autopct=\"%1.1f%%\", labeldistance=1.1, startangle=55, colors=[\"red\", \"green\"])\n    axs[1].set_title(\"df_train: time_to_failure\", pad=10)\n    axs[2].pie([null_test, len(df_test) - null_test], labels=[\"missing\", \"filled\"], explode=(0, 0.01), autopct=\"%1.1f%%\", labeldistance=1.1, startangle=55, colors=[\"red\", \"green\"])\n    axs[2].set_title(\"df_test: acoustic_data\", pad=10)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:46.068348Z","iopub.execute_input":"2021-12-21T02:58:46.068596Z","iopub.status.idle":"2021-12-21T02:58:46.078998Z","shell.execute_reply.started":"2021-12-21T02:58:46.068564Z","shell.execute_reply":"2021-12-21T02:58:46.078009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_null_percentage()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:46.080476Z","iopub.execute_input":"2021-12-21T02:58:46.080786Z","iopub.status.idle":"2021-12-21T02:58:48.219033Z","shell.execute_reply.started":"2021-12-21T02:58:46.080753Z","shell.execute_reply":"2021-12-21T02:58:48.218363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Nhận xét\n<p style=\"font-size:18px\">\nNhư vậy, cả 2 datasets đều không có các giá trị null và ta không cần tiến hành fill các giá trị null.\n</p>","metadata":{}},{"cell_type":"markdown","source":"## 3.2. Sự thay đổi giá trị của acoustic_data và time_to_failure trong 10% dữ liệu\n<p style=\"font-size:18px\"> Ở đây ta sẽ biểu diễn đồng thời 2 fields <code>acoustic_data</code> và <code>time_to_failure</code> trên cùng một đồ thị để thấy được sự tương quan giữa chúng.<br>\nChúng ta sẽ xem sét sự thay đổi về giá trị của các fields trong 10% dữ liệu bằng cách sử dụng các slice với bước nhảy 1000, tạo được sự bao quát toàn bộ tập dữ liệu thay vì phải duyệt toàn bộ 629145480 records. </p>","metadata":{}},{"cell_type":"code","source":"# plot to see trend of value changing\ndef plot_value_changing(slice):\n    figure, axis_1 = plt.subplots(figsize=(20, 8))\n    \n    # plot acoustic_data by slice\n    plt.title(\"acoustic_data and time_to_failure value changing in {}% datapoints\".format(slice // 100))\n    plt.plot(df_train[\"acoustic_data\"].values[::slice], color=\"orange\")\n    axis_1.set_ylabel(\"acoustic_data\")\n    plt.legend([\"acoustic_data\"], loc=\"upper left\")\n\n    # duplicate plot and apply to time_to_failure\n    axis_2 = axis_1.twinx()\n    plt.plot(df_train[\"time_to_failure\"].values[::slice], color=\"green\")\n    axis_2.set_ylabel(\"time_to_failure\")\n    plt.legend([\"time_to_failure\"], loc=\"upper right\")\n\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:48.22033Z","iopub.execute_input":"2021-12-21T02:58:48.220731Z","iopub.status.idle":"2021-12-21T02:58:48.228087Z","shell.execute_reply.started":"2021-12-21T02:58:48.220694Z","shell.execute_reply":"2021-12-21T02:58:48.227353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_value_changing(1000)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:48.229093Z","iopub.execute_input":"2021-12-21T02:58:48.229447Z","iopub.status.idle":"2021-12-21T02:58:48.76248Z","shell.execute_reply.started":"2021-12-21T02:58:48.229412Z","shell.execute_reply":"2021-12-21T02:58:48.761771Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Nhận xét\n<p style=\"font-size:18px\"> Ta có thể thấy mỗi lần <code>time_to_failure</code> có giá trị 0 đồng thời giá trị của <code>acoustic_data</code> cũng có sự thay đổi lớn, tại các mốc này đã xảy ra động đất.<br>\nNgoài ra, ta có thể đặt giả thuyết trong toàn bộ dataset có 16 lần xảy ra động đất. Giả thuyết này cũng đúng với 1% dữ liệu.</p>\n","metadata":{}},{"cell_type":"code","source":"plot_value_changing(100)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:48.763436Z","iopub.execute_input":"2021-12-21T02:58:48.763689Z","iopub.status.idle":"2021-12-21T02:58:50.613653Z","shell.execute_reply.started":"2021-12-21T02:58:48.763654Z","shell.execute_reply":"2021-12-21T02:58:50.612976Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.3. Sự thay đổi giá trị của time_to_failure và acoustic_data trong khoảng 10 triệu data points đầu\n<p style=\"font-size:18px\"> Tiếp theo, chúng ta sẽ xem xét trong 10 triệu dữ liệu đầu tiên sẽ có bao nhiêu lần xảy ra động đất và xu hướng thay đổi giá trị của các field ra sao. </p>","metadata":{}},{"cell_type":"code","source":"# plot to see trend of value changing in first 10 million datapoints\ndef plot_10m_value_changing():\n    figure, axis_1 = plt.subplots(figsize=(20,10))\n    axis_1.plot(df_train.index.values[:10000000], df_train[\"acoustic_data\"].values[:10000000], color=\"orange\")\n    axis_1.set_ylabel(\"acoustic_data\")\n    plt.legend([\"acoustic_data\"], loc=\"upper left\")\n\n    axis_2 = axis_1.twinx()\n    axis_2.plot(df_train.index.values[:10000000], df_train[\"time_to_failure\"].values[:10000000], color=\"green\")\n    axis_2.set_ylabel(\"time_to_failure\")\n    plt.legend([\"time_to_failure\"], loc=\"upper right\")\n\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:50.614813Z","iopub.execute_input":"2021-12-21T02:58:50.615376Z","iopub.status.idle":"2021-12-21T02:58:50.622606Z","shell.execute_reply.started":"2021-12-21T02:58:50.61534Z","shell.execute_reply":"2021-12-21T02:58:50.621804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_10m_value_changing()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:50.623767Z","iopub.execute_input":"2021-12-21T02:58:50.624573Z","iopub.status.idle":"2021-12-21T02:58:55.645517Z","shell.execute_reply.started":"2021-12-21T02:58:50.624534Z","shell.execute_reply":"2021-12-21T02:58:55.64484Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Ngoài ra, ta cũng sẽ tiến hành xem xét một số chi tiết về dữ liệu của dataset. </p>","metadata":{}},{"cell_type":"code","source":"df_train[:10000000].describe()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:55.649452Z","iopub.execute_input":"2021-12-21T02:58:55.649833Z","iopub.status.idle":"2021-12-21T02:58:56.36656Z","shell.execute_reply.started":"2021-12-21T02:58:55.649801Z","shell.execute_reply":"2021-12-21T02:58:56.365848Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Sự phân bố của <code>acoustic_data</code> như sau:\n</p>","metadata":{}},{"cell_type":"code","source":"# acoustic_data distribution in first 10 million datapoints\ndf_train[\"acoustic_data\"][:10000000].hist(bins=30, range=[-15,15], align=\"mid\")\nplt.title(\"acoustic_data distribution\")\nplt.xlabel(\"acoustic data\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:56.367643Z","iopub.execute_input":"2021-12-21T02:58:56.368219Z","iopub.status.idle":"2021-12-21T02:58:56.717227Z","shell.execute_reply.started":"2021-12-21T02:58:56.368181Z","shell.execute_reply":"2021-12-21T02:58:56.716517Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Nhận xét\n\n<p style=\"font-size:18px\"> Như vậy, ta thấy được trong 10 triệu data points ta có duy nhất một lần xảy ra động đất. <br>\nNgoài ra, ta có thể khẳng định được giả thuyết đã nêu ở mục 3.2, trước khi trận động đất xảy ra tức khởi điểm <code>time_to_failure</code> đạt 0 thì biên độ dao động của giá trị địa chấn <code>acoustic_data</code> tăng đột biến.<br>\nSau đó là một khoảng thời gian ít xảy ra thay đổi lớn về giá trị cho tới lần động đất kế tiếp.<br>\nTrong 10 triệu data points, giá trị <code>acoustic_data</code> phần lớn tập trung tại khoảng 0 - 10. Ta có thể dùng dữ kiện này làm cơ sở để loại bỏ các giá trị gây nhiễu. </p>\n</p>\n","metadata":{}},{"cell_type":"markdown","source":"## 3.4. Sự thay đổi của time_to_failure trong measurement segment đầu","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Ta sẽ xem xét sự thay đổi giá trị <code>time_to_failure</code> của 150000 điểm dữ liệu đầu, tương ứng với measurement segment đầu tiên.</p>","metadata":{}},{"cell_type":"code","source":"# plot to see trend of value changing in a specific slice\ndef plot_time_to_failure(slice):\n    plt.plot(df_train.index.values[:slice], df_train[\"time_to_failure\"].values[:slice], color=\"green\")\n    plt.ylabel(\"time_to_failure\")\n    plt.title(\"time_to_failure in {} data points\".format(slice))\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:56.718522Z","iopub.execute_input":"2021-12-21T02:58:56.718917Z","iopub.status.idle":"2021-12-21T02:58:56.724527Z","shell.execute_reply.started":"2021-12-21T02:58:56.71888Z","shell.execute_reply":"2021-12-21T02:58:56.723867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_time_to_failure(150000)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:56.725776Z","iopub.execute_input":"2021-12-21T02:58:56.726213Z","iopub.status.idle":"2021-12-21T02:58:56.92919Z","shell.execute_reply.started":"2021-12-21T02:58:56.72614Z","shell.execute_reply":"2021-12-21T02:58:56.928506Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Ta sẽ khảo sát sự thay đổi trên 1 slice nhỏ hơn.</p>","metadata":{}},{"cell_type":"code","source":"plot_time_to_failure(10000)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:56.93027Z","iopub.execute_input":"2021-12-21T02:58:56.930832Z","iopub.status.idle":"2021-12-21T02:58:57.098844Z","shell.execute_reply.started":"2021-12-21T02:58:56.930785Z","shell.execute_reply":"2021-12-21T02:58:57.098203Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Nhận thấy trên mỗi khoảng 4000 data points, <code>time_to_failure</code> có xu hướng giảm theo một đường tuyến tính.</p>","metadata":{}},{"cell_type":"code","source":"plot_time_to_failure(4000)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:57.100071Z","iopub.execute_input":"2021-12-21T02:58:57.100463Z","iopub.status.idle":"2021-12-21T02:58:57.280536Z","shell.execute_reply.started":"2021-12-21T02:58:57.100427Z","shell.execute_reply":"2021-12-21T02:58:57.279881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Nhận xét\n<p style=\"font-size:18px\"> Qua đây ta có thể thấy, sự thay đổi của <code>time_to_failure</code> là không đều nhau. <br> Đồng thời, giá trị của time_to_failure trên mỗi 4000 data points có xu hướng giảm tuyến tính.</p>\n","metadata":{"execution":{"iopub.status.busy":"2021-06-09T23:24:51.410791Z","iopub.execute_input":"2021-06-09T23:24:51.411321Z","iopub.status.idle":"2021-06-09T23:24:51.417286Z","shell.execute_reply.started":"2021-06-09T23:24:51.411289Z","shell.execute_reply":"2021-06-09T23:24:51.416055Z"}}},{"cell_type":"markdown","source":"## 3.5. Dữ liệu trong các file test","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Tiếp theo, ta sẽ biểu diễn dữ liệu của một số file test để kiểm tra xem <code>seg_id</code> đó có xảy ra động đất hay không. </p>","metadata":{}},{"cell_type":"code","source":"# plot data in csv test files\ndef plot_test_file(test_files):\n    figure, axs = plt.subplots(nrows=1, ncols=3, figsize=(30, 8))\n    for i in range(len(test_files)):\n        segment = pd.read_csv(test_folder_path  + \"/\" + test_files[i])\n        axs[i].plot(segment[\"acoustic_data\"].values, color=\"green\")\n        axs[i].set_ylabel(\"acoustic_data\")\n        axs[i].set_title(\"test: \" + test_files[i])\n    \n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:57.28183Z","iopub.execute_input":"2021-12-21T02:58:57.282085Z","iopub.status.idle":"2021-12-21T02:58:57.290106Z","shell.execute_reply.started":"2021-12-21T02:58:57.282037Z","shell.execute_reply":"2021-12-21T02:58:57.289408Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_test_file([\"seg_00030f.csv\", \"seg_063865.csv\", \"seg_0c12cc.csv\"])","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:57.292188Z","iopub.execute_input":"2021-12-21T02:58:57.292401Z","iopub.status.idle":"2021-12-21T02:58:57.899496Z","shell.execute_reply.started":"2021-12-21T02:58:57.292372Z","shell.execute_reply":"2021-12-21T02:58:57.89882Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Nhận xét:\n<p style=\"font-size:18px\"> Như vậy, mỗi file hay mỗi <code>seg_id</code> là một segment gồm 150000 data points. Như 3 biểu đồ ở trên, ta có thể thấy cả 3 <code>seg_id</code> này đều có xảy ra động đất do biên độ dao động của <code>acoustic_data</code> là rất lớn.</p>","metadata":{}},{"cell_type":"markdown","source":"# 4. Features Generation","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\">Đây là quá trình tạo ra thêm các features mới từ một hoặc các features hiện có, có khả năng sử dụng trong quá trình dự đoán và xây dựng mô hình. Đối với bài toán này, feature được cung cấp chỉ có duy nhất một nên ta sẽ phải tạo thêm các features mới từ field <code>acoustic_data</code>.</p>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Do lượng data rất lớn, lên đến hơn 600 triệu data points, nên chúng ta sẽ chia nhỏ data thành các measurement segments với size là 150000 tương ứng với lượng records của một file test hay một <code>seg_id</code>.</p>","metadata":{}},{"cell_type":"code","source":"rows = df_test.shape[0]                                 # total records of 1 test file/seg_id\nsegments = int(np.floor(df_train.shape[0] / rows))      # total measurement segments in df_train\nprint(\"Number of segments: \", segments)","metadata":{"execution":{"iopub.status.busy":"2021-12-22T15:31:27.676755Z","iopub.execute_input":"2021-12-22T15:31:27.677003Z","iopub.status.idle":"2021-12-22T15:31:27.6837Z","shell.execute_reply.started":"2021-12-22T15:31:27.676967Z","shell.execute_reply":"2021-12-22T15:31:27.681599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Như vậy, dataframe df_train có tất cả 4194 segments. Tiếp theo, ta sẽ khởi tạo giá trị x_train và y_train. Trong đó số lượng index là số lượng segments, y_train có 1 cột field dữ liệu là <code>time_to_failure</code> còn các features của x_train sẽ được khởi tạo từ field <code>acoustic_data</code>.</p>","metadata":{}},{"cell_type":"code","source":"# create x_train and y_train dataframe\nx_train = pd.DataFrame(index=range(segments), dtype=np.float64)\ny_train = pd.DataFrame(index=range(segments), dtype=np.float64, columns=[\"time_to_failure\"])","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:57.910975Z","iopub.execute_input":"2021-12-21T02:58:57.9113Z","iopub.status.idle":"2021-12-21T02:58:57.920283Z","shell.execute_reply.started":"2021-12-21T02:58:57.911261Z","shell.execute_reply":"2021-12-21T02:58:57.919525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Nhận xét\n<p style=\"font-size:18px\"> <code>acoustic_data</code> là dữ liệu thô thu được từ máy đo cường độ sóng địa chất từ lòng đất, như vậy ta không thể sử dụng field này như một feautre để huấn luyện mô hình.<br>\nVì vậy, chúng ta phải tạo ra các features mới từ <code>acoustic_data</code> và lựa chọn features phù hợp để sử dụng cho quá trình huấn luyện mô hình.<br>\nCác features sẽ được khởi tạo bao gồm những features về số liệu cơ bản như mean (trung bình), std (độ lệch chuẩn), quantile (lượng tử/phân vị), skew (tính bất đối xứng của phân phối xác suất), v.v của mỗi segment hoặc của một số slice nhất định. Ngoài ra ta tạo thêm các features bằng cách biến đổi dữ liệu từ miền thời gian về miền tần số với thuật toán FFT (Fast Fourier Transform). <br>\n<br>Sau khi tạo thêm các features, chúng ta sẽ cần phải xem xét các biểu đồ dữ liệu để đánh giá tính phù hợp của các features đó.\n</p>","metadata":{}},{"cell_type":"code","source":"def generate_feature(df, x, seg):\n#     series_x = pd.Series(seg[\"acoustic_data\"].values)\n    \n    df.loc[seg, \"mean\"] = x.mean() \n    df.loc[seg, \"mean_abs\"] = np.abs(x).mean() # normal mean might be around 0 values\n\n    df.loc[seg, \"std\"] = x.std()\n    df.loc[seg, \"std_abs\"] = np.abs(x).std()\n    df.loc[seg, \"std_first_10000\"] = x[:10000].std()\n    df.loc[seg, \"std_last_10000\"]  =  x[-10000:].std()\n    df.loc[seg, \"std_first_50000\"] = x[:50000].std()\n    df.loc[seg, \"std_last_50000\"]  =  x[-50000:].std()\n\n    df.loc[seg, \"max\"] = x.max()\n    df.loc[seg, \"max_abs\"] = np.abs(x).max()\n\n    df.loc[seg, \"min\"] = x.min()\n    df.loc[seg, \"min_abs\"] = np.abs(x).min()\n\n    df.loc[seg, \"sum\"] = x.sum()\n\n    df.loc[seg, \"mad\"] = x.mad() # mean absolute deviation\n    df.loc[seg, \"skew\"] = x.skew()\n        \n    df.loc[seg, \"quant_01\"] = np.quantile(x,0.01)\n    df.loc[seg, \"quant_01_abs\"] = np.quantile(np.abs(x), 0.01)\n    df.loc[seg, \"quant_05\"] = np.quantile(x,0.05)\n    df.loc[seg, \"quant_05_abs\"] = np.quantile(np.abs(x), 0.05)\n    df.loc[seg, \"quant_95\"] = np.quantile(x,0.95)\n    df.loc[seg, \"quant_95_abs\"] = np.quantile(np.abs(x), 0.95)\n    df.loc[seg, \"quant_99\"] = np.quantile(x,0.99)\n    df.loc[seg, \"quant_99_abs\"] = np.quantile(np.abs(x), 0.99)\n    \n    # compute the q-th percentile of the data\n    df.loc[seg, \"q_10\"] = np.percentile(x, 0.10)\n    df.loc[seg, \"q_25\"] = np.percentile(x, 0.25)\n    df.loc[seg, \"q_50\"] = np.percentile(x, 0.50)\n    df.loc[seg, \"q_75\"] = np.percentile(x, 0.75)\n    df.loc[seg, \"q_90\"] = np.percentile(x, 0.90)\n    \n    # fft\n    fft = np.fft.fft(x)\n    real_fft = np.real(fft)\n    imag_fft = np.imag(fft)\n    df.loc[seg, \"real_mean\"] = real_fft.mean()\n    df.loc[seg, \"real_std\"] = real_fft.std()\n    df.loc[seg, \"real_max\"] = real_fft.max()\n    df.loc[seg, \"real_min\"] = real_fft.min()\n    df.loc[seg, \"real_mean_last_5000\"] = real_fft[-5000:].mean()\n    df.loc[seg, \"real_std_last_5000\"] = real_fft[-5000:].std()\n    df.loc[seg, \"real_max_last_5000\"] = real_fft[-5000:].max()\n    df.loc[seg, \"real_min_last_5000\"] = real_fft[-5000:].min()\n    df.loc[seg, \"real_mean_last_15000\"] = real_fft[-15000:].mean()\n    df.loc[seg, \"real_std_last_15000\"] = real_fft[-15000:].std()\n    df.loc[seg, \"real_max_last_15000\"] = real_fft[-15000:].max()\n    df.loc[seg, \"real_min_last_15000\"] = real_fft[-15000:].min()\n\n    df.loc[seg, \"imag_mean\"] = imag_fft.mean()\n    df.loc[seg, \"imga_std\"] = imag_fft.std()\n    df.loc[seg, \"imga_max\"] = imag_fft.max()\n    df.loc[seg, \"imag_min\"] = imag_fft.min()\n    \n    # features generation using rolling\n    for w in [10, 100, 1000, 10000]:\n        x_roll_abs_mean = x.abs().rolling(w).mean().dropna().values\n        x_roll_std = x.rolling(w).std().dropna().values\n        x_roll_min = x.rolling(w).min().dropna().values\n        x_roll_max = x.rolling(w).max().dropna().values\n        x_roll_mean = x.rolling(w).max().dropna().values\n        \n        df.loc[seg, \"mean_roll_std_\" + str(w)] = x_roll_std.mean()\n        df.loc[seg, \"mean_roll_abs_mean_\" + str(w)] = x_roll_abs_mean.mean()\n        df.loc[seg, \"mean_roll_mean_\" + str(w)] = x_roll_mean.mean()\n\n        df.loc[seg, \"std_roll_std_\" + str(w)] = x_roll_std.std()\n        df.loc[seg, \"std_roll_max_\" + str(w)] = x_roll_max.std()\n        df.loc[seg, \"std_roll_mean_\" + str(w)] = x_roll_mean.std()\n        df.loc[seg, \"std_roll_abs_mean_\" + str(w)] = x_roll_abs_mean.std()\n        df.loc[seg, \"std_roll_min_\" + str(w)] = x_roll_min.std()\n\n        df.loc[seg, \"max_roll_std_\" + str(w)] = x_roll_std.max()\n        df.loc[seg, \"max_roll_mean_\" + str(w)] = x_roll_mean.max()\n        df.loc[seg, \"max_roll_min_\" + str(w)] = x_roll_min.max()\n        df.loc[seg, \"min_roll_mean_\" + str(w)] = x_roll_mean.min()\n        df.loc[seg, \"min_roll_std_\" + str(w)] = x_roll_std.min()\n        df.loc[seg, \"min_roll_max_\" + str(w)] = x_roll_max.min()\n\n        df.loc[seg, \"quant_01_roll_std_\" + str(w)] = np.quantile(x_roll_std, 0.01)\n        df.loc[seg, \"quant_05_roll_std_\" + str(w)] = np.quantile(x_roll_std, 0.05)\n        df.loc[seg, \"quant_10_roll_std_\" + str(w)] = np.quantile(x_roll_std, 0.10)\n        df.loc[seg, \"quant_95_roll_std_\" + str(w)] = np.quantile(x_roll_std, 0.95)\n        df.loc[seg, \"quant_99_roll_std_\" + str(w)] = np.quantile(x_roll_std, 0.99)\n        df.loc[seg, \"quant_05_roll_mean_\" + str(w)] = np.quantile(x_roll_mean, 0.05)\n        df.loc[seg, \"quant_95_roll_mean_\" + str(w)] = np.quantile(x_roll_mean, 0.95)\n        df.loc[seg, \"quant_05_roll_abs_mean_\" + str(w)] = np.quantile(x_roll_abs_mean, 0.05)\n        df.loc[seg, \"quant_95_roll_abs_mean_\" + str(w)] = np.quantile(x_roll_abs_mean, 0.95)\n        df.loc[seg, \"quant_05_roll_min_\" + str(w)] = np.quantile(x_roll_min, 0.05)\n        df.loc[seg, \"quant_95_roll_min_\" + str(w)] = np.quantile(x_roll_min, 0.95)\n        df.loc[seg, \"quant_05_roll_max_\" + str(w)] = np.quantile(x_roll_max, 0.05)\n        df.loc[seg, \"quant_95_roll_max_\" + str(w)] = np.quantile(x_roll_max, 0.95)\n    return df","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:57.921885Z","iopub.execute_input":"2021-12-21T02:58:57.922431Z","iopub.status.idle":"2021-12-21T02:58:57.956674Z","shell.execute_reply.started":"2021-12-21T02:58:57.922393Z","shell.execute_reply":"2021-12-21T02:58:57.955887Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Ta sẽ tiến hành khởi tạo các features cho x_train bằng cách khởi tạo features lần lượt trên từng segment bằng func <code>generate_feature</code> ở trên. </p>","metadata":{}},{"cell_type":"code","source":"# generate features for each measurement segments\nfor segment in tqdm(range(segments)):\n    seg = df_train.iloc[segment * rows: segment * rows + rows]\n    x = pd.Series(seg[\"acoustic_data\"].values)\n    y = seg[\"time_to_failure\"].values[-1]\n    y_train.loc[segment, \"time_to_failure\"] = y\n    x_train = generate_feature(x_train, x, segment)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T02:58:57.958985Z","iopub.execute_input":"2021-12-21T02:58:57.959468Z","iopub.status.idle":"2021-12-21T03:14:14.091363Z","shell.execute_reply.started":"2021-12-21T02:58:57.959429Z","shell.execute_reply":"2021-12-21T03:14:14.090504Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> x_train sau khi đã được khởi tạo thêm các features. </p>","metadata":{}},{"cell_type":"code","source":"x_train.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T03:14:14.092903Z","iopub.execute_input":"2021-12-21T03:14:14.093179Z","iopub.status.idle":"2021-12-21T03:14:14.130643Z","shell.execute_reply.started":"2021-12-21T03:14:14.093144Z","shell.execute_reply":"2021-12-21T03:14:14.129929Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Mô tả về x_train. </p>","metadata":{}},{"cell_type":"code","source":"x_train.describe()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T03:14:14.131954Z","iopub.execute_input":"2021-12-21T03:14:14.132208Z","iopub.status.idle":"2021-12-21T03:14:14.408665Z","shell.execute_reply.started":"2021-12-21T03:14:14.132175Z","shell.execute_reply":"2021-12-21T03:14:14.407959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Tiếp theo, chúng ta sẽ biểu diễn sự tương quan giữa 2 tập này. Func <code>plot_feature</code> được sử dụng để mô tả sự tương quan của từng feature của x_train so với y_train. Feature nào không phù hợp hoặc không cần thiết cho các quá trình tiếp theo thì chúng ta sẽ loại bỏ để tránh gây nhiễu mô hình . </p>","metadata":{}},{"cell_type":"code","source":"# plot all generated features\ndef plot_feature(feature, x=x_train):\n    fig, axs = plt.subplots(figsize=(20, 8)) \n    axs.set_xlabel(feature)\n    axs.set_ylabel(\"time_to_failure\")\n    plt.title(\"{} - time_to_falure\".format(feature))\n    plt.scatter(x=x[feature], y=y_train, color=\"green\")\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T03:14:14.409987Z","iopub.execute_input":"2021-12-21T03:14:14.410242Z","iopub.status.idle":"2021-12-21T03:14:14.417103Z","shell.execute_reply.started":"2021-12-21T03:14:14.410208Z","shell.execute_reply":"2021-12-21T03:14:14.414981Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for feature in x_train.columns:\n    plot_feature(feature)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T03:14:14.418516Z","iopub.execute_input":"2021-12-21T03:14:14.418792Z","iopub.status.idle":"2021-12-21T03:14:51.330686Z","shell.execute_reply.started":"2021-12-21T03:14:14.418758Z","shell.execute_reply":"2021-12-21T03:14:51.329916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5. Xử lý dữ liệu cho training và testing data","metadata":{}},{"cell_type":"markdown","source":"## 5.1. Training data","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Trước hết ta sẽ loại bỏ các features có đồ thị chỉ có giá trị 0 như <code>min_abs</code> và <code>quant_01_abs</code>.</p>","metadata":{}},{"cell_type":"code","source":"x_train = x_train.drop(columns=[\"min_abs\", \"quant_01_abs\"])","metadata":{"execution":{"iopub.status.busy":"2021-12-21T03:14:51.331995Z","iopub.execute_input":"2021-12-21T03:14:51.332422Z","iopub.status.idle":"2021-12-21T03:14:51.338437Z","shell.execute_reply.started":"2021-12-21T03:14:51.332383Z","shell.execute_reply":"2021-12-21T03:14:51.337641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Ngoài ra các features có đồ thị không biểu diễn được thông tin gì đặc biệt, không phải dạng linear cũng không phải non-linear nên ta cũng sẽ loại bỏ những features này để không làm nhiễu mô hình dữ liệu. </p>","metadata":{}},{"cell_type":"code","source":"# drop useless features\nx_train = x_train.drop(columns=[\"sum\", \"mean\", \"mean_roll_mean_10\", \n                                \"mean_roll_mean_100\", \"mean_roll_mean_10000\", \n                                \"min_roll_std_100\", \"mean_roll_mean_1000\", \n                                \"quant_05_roll_abs_mean_1000\", \"quant_05_roll_abs_mean_100\", \n                                \"quant_05_roll_mean_10000\", \"quant_95_roll_mean_10000\", \n                                \"quant_05_roll_abs_mean_10000\"])","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-21T03:14:51.33971Z","iopub.execute_input":"2021-12-21T03:14:51.340087Z","iopub.status.idle":"2021-12-21T03:14:51.350644Z","shell.execute_reply.started":"2021-12-21T03:14:51.34003Z","shell.execute_reply":"2021-12-21T03:14:51.34985Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Dataframe x_train sau khi loại bỏ các features gây nhiễu sẽ có size là (4194, 138), trong đó 4194 records tương ứng với 4194 measurement segments và 138 features. </p>","metadata":{}},{"cell_type":"code","source":"x_train","metadata":{"execution":{"iopub.status.busy":"2021-12-21T03:14:51.352205Z","iopub.execute_input":"2021-12-21T03:14:51.352474Z","iopub.status.idle":"2021-12-21T03:14:51.395186Z","shell.execute_reply.started":"2021-12-21T03:14:51.352435Z","shell.execute_reply":"2021-12-21T03:14:51.394564Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Nhận xét\n<p style=\"font-size:18px\"> Các features được tạo ra trên nhiều miền giá trị khác nhau (thời gian, tần số, ...), do đó ta sẽ chuẩn hoá, biến đổi những features này về cùng một miền giá trị. Cũng như loại bỏ các giá trị trung bình và chia tỷ lệ theo phương sai đơn vị. Điều đó sẽ giúp cho các dữ liệu huấn luyện và test thuộc cùng một miền giá trị,có lợi hơn cho mô hình trong quá trình học và dự đoán kết quả.<br\n>\nỞ đây ta sẽ sử dụng <code>StandardScaler</code> để thực hiện việc chuẩn hóa.</p>","metadata":{}},{"cell_type":"code","source":"# standardize\nscaler = StandardScaler()\nscaler.fit(x_train)\nscaled_x_train = pd.DataFrame(scaler.transform(x_train), columns=x_train.columns)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T03:14:51.397615Z","iopub.execute_input":"2021-12-21T03:14:51.398117Z","iopub.status.idle":"2021-12-21T03:14:51.415808Z","shell.execute_reply.started":"2021-12-21T03:14:51.398089Z","shell.execute_reply":"2021-12-21T03:14:51.41519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Dataframe x_train sau khi đã được chuẩn hoá.  </p>","metadata":{}},{"cell_type":"code","source":"scaled_x_train","metadata":{"execution":{"iopub.status.busy":"2021-12-21T03:14:51.416839Z","iopub.execute_input":"2021-12-21T03:14:51.417163Z","iopub.status.idle":"2021-12-21T03:14:51.446078Z","shell.execute_reply.started":"2021-12-21T03:14:51.417127Z","shell.execute_reply":"2021-12-21T03:14:51.445365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 5.2. Testing data","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Các file csv trong folder test từ data của cuộc thi dùng để submit kết quả cho bài toán. <br>\nTa sẽ dọc file <code>sample_submission.csv</code> và từ đó tạo dataframe x_test có cấu trúc, số cột bằng với số cột của x_train, số hàng tương ứng với số file csv trong folder test. <br>\nDữ liệu từ mỗi file test csv sẽ là 1 record/hàng của dataframe x_test và lặp lại quá trình tạo features từ 150000 datapoints như đã làm với x_train trước đó.\n</p>","metadata":{}},{"cell_type":"code","source":"submission = pd.read_csv(sample_submission_path, index_col=\"seg_id\")\nx_test = pd.DataFrame(columns=scaled_x_train.columns, dtype=np.float64, index=submission.index)\n\n# generate feautres for csv test files\nfor i in tqdm(x_test.index):\n    seg = pd.read_csv(test_folder_path + \"/\" + i + \".csv\")\n    x = pd.Series(seg[\"acoustic_data\"].values)\n    x_test = generate_feature(x_test, x, i)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T04:41:38.380559Z","iopub.execute_input":"2021-12-21T04:41:38.380838Z","iopub.status.idle":"2021-12-21T04:51:54.254891Z","shell.execute_reply.started":"2021-12-21T04:41:38.380806Z","shell.execute_reply":"2021-12-21T04:51:54.254125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Ta cũng sẽ tiến hành loại bỏ những features không dùng tới hoặc gây nhiễu như x_train. </p>","metadata":{}},{"cell_type":"code","source":"# drop useless features\nx_test = x_test.drop(columns=[\"sum\", \"mean\", \"mean_roll_mean_10\", \n                              \"mean_roll_mean_100\", \"mean_roll_mean_10000\", \n                              \"min_roll_std_100\", \"mean_roll_mean_1000\", \n                              \"quant_05_roll_abs_mean_1000\", \"quant_05_roll_abs_mean_100\", \n                              \"quant_05_roll_mean_10000\", \"quant_95_roll_mean_10000\", \n                              \"quant_05_roll_abs_mean_10000\", \"min_abs\", \"quant_01_abs\"])","metadata":{"execution":{"iopub.status.busy":"2021-12-21T04:51:54.256643Z","iopub.execute_input":"2021-12-21T04:51:54.257086Z","iopub.status.idle":"2021-12-21T04:51:54.265772Z","shell.execute_reply.started":"2021-12-21T04:51:54.257033Z","shell.execute_reply":"2021-12-21T04:51:54.265017Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Dataframe x_test: </p>","metadata":{}},{"cell_type":"code","source":"x_test","metadata":{"execution":{"iopub.status.busy":"2021-12-21T03:25:17.573085Z","iopub.execute_input":"2021-12-21T03:25:17.573694Z","iopub.status.idle":"2021-12-21T03:25:17.617269Z","shell.execute_reply.started":"2021-12-21T03:25:17.573653Z","shell.execute_reply":"2021-12-21T03:25:17.61639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Như vậy, dataframe x_test sẽ có cùng số lượng features với x_train là 138 và có 2624 records tương ứng với số lượng file test csv. Sau đó, ta sẽ tiến hành chuẩn hóa dữ liệu của về cùng một miền giá trị bằng <code>StandardScaler</code> tương tự như đã làm ở trên.</p>","metadata":{}},{"cell_type":"code","source":"scaled_x_test = pd.DataFrame(scaler.transform(x_test), columns=x_test.columns)","metadata":{"execution":{"iopub.status.busy":"2021-12-21T04:51:54.268186Z","iopub.execute_input":"2021-12-21T04:51:54.268646Z","iopub.status.idle":"2021-12-21T04:51:54.280728Z","shell.execute_reply.started":"2021-12-21T04:51:54.268605Z","shell.execute_reply":"2021-12-21T04:51:54.279932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> x_test sau chuẩn hoá. </p>","metadata":{}},{"cell_type":"code","source":"scaled_x_test","metadata":{"execution":{"iopub.status.busy":"2021-12-21T04:51:54.282422Z","iopub.execute_input":"2021-12-21T04:51:54.28275Z","iopub.status.idle":"2021-12-21T04:51:54.315053Z","shell.execute_reply.started":"2021-12-21T04:51:54.282714Z","shell.execute_reply":"2021-12-21T04:51:54.314361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 6.Huấn luyện \n","metadata":{}},{"cell_type":"markdown","source":"## 6.1. Lựa chọn mô hình","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Để huấn luyện cho mô hình, ta sẽ thử với một số mô hình như AdaBoostRegressor, LightGBM và Ridge. Sau đó so sánh các kết quả và lựa chọn mô hình thích hợp nhất hoặc sử dụng <code>VotingRegressor</code> để tạo ra mô hình cuối cùng.<br>\n<br>\nTa sẽ dùng <code>K-Fold</code> để chia bộ dữ liệu thành các folds (k folds), mỗi fold sẽ được thay phiên sử dụng làm tập test một lần và các folds còn lại sẽ được sử dụng làm tập train.<br> \nNhư vậy, ta sẽ đánh giá được chính xác hơn độ khả dụng của mô hình đối với bài toán. Ở đây, chúng ta sẽ chia thành 5 folds, nhiều hơn có thể gây ra tình trạng tràn RAM và crash session đối với một số mô hình.</p>","metadata":{}},{"cell_type":"code","source":"# create n folds and rename columns with re\nfolds = KFold(n_splits=5, shuffle=True, random_state=42)\nscaled_x_train = scaled_x_train.rename(columns = lambda x:re.sub(\"[^A-Za-z0-9_]+\", \"\", x))","metadata":{"execution":{"iopub.status.busy":"2021-12-21T05:47:42.532382Z","iopub.execute_input":"2021-12-21T05:47:42.532917Z","iopub.status.idle":"2021-12-21T05:47:42.539265Z","shell.execute_reply.started":"2021-12-21T05:47:42.532875Z","shell.execute_reply":"2021-12-21T05:47:42.538567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\">Ngoài ra, cuộc thi còn đưa ra hàm lỗi <code>mean_absoluted_error</code> để tính điểm khi submit kết quả bài toán, có công thức như sau: <br></p>\n<h3><center> $MAE = $$\\sum\\limits_{x=1}^{n} {\\mid y_i - x_i \\mid \\over n} = $$\\sum\\limits_{x=1}^{n} {e_i \\over n}$ </center></h3>\n<p style=\"font-size:18px\">Ở đây chúng ta cũng sẽ sử dụng MAE để so sánh các mô hình. </p>","metadata":{}},{"cell_type":"markdown","source":"## 6.2. Mô hình AdaBoostRegressor","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> AdaBoost (Adaptive Boost) là một thuật toán boosting dùng để xây dựng classifer cho các bài toán phân lớp hoặc regressor cho các bài toán hồi quy. <br>\nBoosting là thuật toán học quần thể bằng cách xây dựng nhiều thuật toán học cùng lúc như cây quyết định và kết hợp chúng lại. Mục đích là tạo ra một cụm hoặc một nhóm các weak learner sau đó kết hợp chúng lại để tạo ra một strong learner duy nhất. <br>\n<br>\nÝ tưởng của AdaBoost xuất phát từ Boosting nhưng nó lại sử dụng toàn bộ dữ liệu để huấn luyện từng mô hình con với trọng số được phân phối lại sau mỗi lần huấn luyện sao cho mô hình sau quan tâm nhiều hơn đến những lỗi sai của mô hình trước đó. <br>\n<br>\nMô hình sẽ gán trọng số cho tất cả các điểm dữ liệu:  $\\sum\\limits_{i}w_i = 1$, $w_i = w_k$ <br>\nVới mỗi lần boosting:<br>\n- Huấn luyện các mô hình con: $C_i = train(x, y, w)$ <br>\n- Dự đoán nhãn: $\\hat y = predict(C_j, x)$ <br>\n- Tổng lỗi sẽ được tính theo công thức: $\\epsilon = \\sum\\limits_{i} w_i.(\\hat y_i! = y_i)$. Tổng lỗi có độ lớn trong khoảng [0, 1], khi tất cả các dự đoán là đúng thì tổng lỗi bằng 0 và ngược lại. <br>\n- Hệ số $a_i = 0.5\\log{1 - \\epsilon \\over \\epsilon}$. Tượng trưng cho ảnh hưởng của mô hình con thứ i lên toàn bộ mô hình lớn. Khi mô hình con đó có ít dự đoán sai, $\\epsilon$ sẽ thấp, do đó mô hình đóng góp nhiều cho dự đoán cuối cùng. <br>\n- Cập nhật trọng số: $w = w * \\exp(-a_i * \\hat y * y)$\n</p>","metadata":{}},{"cell_type":"markdown","source":"### Cài đặt\n<p style=\"font-size:18px\"> Để cài đặt mô hình AdaBoostRegressor, ta sẽ sử dụng thư viện scikit-learn để gọi hàm <code>AdaBoostRegressor()</code>. <br>\nDo lượng dữ liệu tương đối lớn, nên chúng ta sẽ sử dụng <code>RandomizedSearchCV</code> với một số bộ params để điều chỉnh tham số cho quá trình huấn luyện và dự đoán kết quả. Từ đó có được estimator tốt nhất.\n</p>","metadata":{}},{"cell_type":"code","source":"# params\nparams = {\"n_estimators\": [50, 100],\n          \"learning_rate\": [0.01, 0.05, 0.1, 0.2],\n          \"loss\": [\"linear\", \"square\", \"exponential\"]}\n\nrandom_ada = RandomizedSearchCV(AdaBoostRegressor(), param_distributions=params, cv=folds, n_iter=10, n_jobs=-1, scoring=\"neg_mean_absolute_error\", verbose=1)\n\n# get result\nresult = random_ada.fit(scaled_x_train, y_train.values.ravel())\n\nprint(\"Best MAE score: {}\".format(-result.best_score_))\nprint(\"Best params: {}\".format(result.best_params_))","metadata":{"execution":{"iopub.status.busy":"2021-12-21T05:48:09.54609Z","iopub.execute_input":"2021-12-21T05:48:09.546839Z","iopub.status.idle":"2021-12-21T05:51:37.303256Z","shell.execute_reply.started":"2021-12-21T05:48:09.5468Z","shell.execute_reply":"2021-12-21T05:51:37.30234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 6.3. Mô hình LightGBM Regressor","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> LightGBM là một framework để xử lý thuật toán tăng cường độ dốc (Gradient Boosting) do Microsoft phát triển.<br> \n<br>\nGradient Boosting là một thuật toán xuất phát từ cây quyết định (Decision Tree), thuật toán này thực hiện việc xây dựng tuần tự nhiều cây quyết định và tiến hành quá trình học. Ngoài LigtGBM, XGBoost cũng sử dụng thuật toán Gradient Boosting.<br>\n<br>\nLightGBM sử dụng histogram-based algorithms thay thế cho các presort-based algorithms thường được dùng trong các boosting tool khác, để tìm kiếm split point thích hợp trong quá trình xây dựng cây quyết định. LightGBM phát triển cây dựa trên leaf-wise, lựa chọn nút để phát triển cây dựa trên tối ưu toàn bộ cây. LightGBM chỉ thích hợp cho các bộ dữ liệu lớn bởi leaf-wise với các bộ dữ liệu nhỏ thường dẫn đến overfit sớm.<br>\n<br>\nSo với các framework khác như XGBoost, pGBRT, v.v, LightGBM sử dụng hai kĩ thuật mới là Gradient-based One-Side Sampling (GOSS) và Exclusive Feature Bundling (EFB). Hai kỹ thuật này giúp mô hình LightGBRM cải thiện được tốc độ tính toán và độ chính xác khi sử dụng với những bộ dữ liệu lớn.<br>\nGOSS sẽ lựa chọn những data instance có gradient lớn nhất và chọn ngẫu nhiên một số lượng nhất định những data instance có gradient nhỏ để sử dụng làm dữ liệu cho quá trình huấn luyện. Trong đó, những data có gradient lớn, theo định nghĩa về mức tăng thông tin thì những data instance này sẽ mang lại nhiều thông tin hơn. Do đó, GOSS ưu tiên lựa chọn và giữ lại những data có gradient lớn. <br>\nEFB được sử dụng để cải thiện tốc độ của quá trình huấn luyện trong mô hình LightGBM bằng cách downsample dữ liệu, ở đây là giảm số chiều, features của dữ liệu. Những features không đồng thời bằng 0 sẽ được EFB chuẩn hoá về thành một feature duy nhất để giảm số chiều của dữ liệu, từ đó đẩy nhanh tốc độ huấn luyện mô hình. </p>\n\n\n### Cài đặt\n<p style=\"font-size:18px\"> Để cài đặt mô hình này, ta sẽ sử dụng <code>lightgbm</code> để gọi hàm <code>LGBMRegressor()</code>. Ngoài ra, chúng ta cũng sẽ sử dụng <code>RandomizedSearchCV</code> để tuning hyperparamters cho mô hình.<br></p>","metadata":{}},{"cell_type":"code","source":"# params\nparams = {\"num_leaves\": [31, 51], \"min_data_in_leaf\": [10], \n          \"objective\": [\"regression\"], \"max_depth\": [-1],\n          \"learning_rate\": [0.01, 0.1], \"boosting_type\": [\"gbdt\"],\n          \"feature_fraction\": [0.9], \"bagging_freq\": [1],\n          \"bagging_fraction\": [0.9], \"bagging_seed\": [42],\n          \"metric\": [\"mae\"], \"lambda_l1\": [0.1],\n          \"n_estimators\": [1000, 10000]}\n\n# fit and predict with each fold, calculate MAE and get best params\nrandom_light_gbm = RandomizedSearchCV(lgb.LGBMRegressor(), param_distributions=params, cv=folds, n_iter=10, n_jobs=-1, scoring=\"neg_mean_absolute_error\", verbose=1)\nresult = random_light_gbm.fit(scaled_x_train, y_train, callbacks=[lgb.log_evaluation(1000)])\n\nprint(\"Best MAE score: {}\".format(-result.best_score_))\nprint(\"Best params: {}\".format(result.best_params_))","metadata":{"execution":{"iopub.status.busy":"2021-12-21T05:54:34.463227Z","iopub.execute_input":"2021-12-21T05:54:34.463511Z","iopub.status.idle":"2021-12-21T06:20:32.659366Z","shell.execute_reply.started":"2021-12-21T05:54:34.46348Z","shell.execute_reply":"2021-12-21T06:20:32.658527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 6.4. Mô hình hồi qui Ridge","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Hồi qui Ridge là một kỹ thuật để phân tích dữ liệu hồi qui nhiều lần. Khi xảy ra đa cộng tuyến, các ước lượng bình phương nhỏ nhất là không chệch và phương sai lớn, dẫn đến các giá trị dự đoán sai lệch rất lớn với giá trị thực tế. Một mức độ chệch được thêm vào các ước lượng hồi qui và kết quả là hồi qui làm giảm các sai số tiêu chuẩn. <br>\n<br>\nHàm mất mất trong hồi qui Ridge sẽ có sự thay đổi so với hồi qui tuyến tính là thành phần điều chuẩn - regularization term được cộng thêm vào hàm mất mát:\n</p>\n<h2><center> $ L(w) = {1 \\over N} \\begin{Vmatrix} \\bar Xw - y \\end{Vmatrix}_{2}^2 + \\alpha \\begin{Vmatrix} w \\end{Vmatrix}_{2}^2 $ $ = {1 \\over N} \\begin{Vmatrix} \\bar Xw - y \\end{Vmatrix}_{2}^2 +  \\underset{regularization-term}{\\alpha R(w)} $ </center></h2>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Bài toán tối ưu hàm mất mát của hồi qui Ridge về bản chất là tối ưu song song hai thành phần bao gồm tổng bình phương phần dư và thành phần điều chuẩn. Hệ số $ \\alpha $  có tác dụng điều chỉnh độ lớn của thành phần điều chuẩn tác động lên hàm mất mát.<br>\n- $ \\alpha = 0 $, thành phần điều chuẩn bị tiêu giảm và bài toán được quy về hồi qui tuyến tính. <br>\n- $ \\alpha $ nhỏ thì vai trò của thành phần điều chuẩn trở nên ít quan trọng hơn. Mức độ kiểm soát tình trạng overfitting của mô hình sẽ trở nên kém hơn. <br>\n- $ \\alpha $ lớn, gia tăng mức độ kiểm soát lên các hệ số ước lượng và giảm bợt hiện tượng overfitting. <br>\n</p>\n\n### Cài đặt","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Ta cũng sẽ cài đặt mô hình Ridge tương tự như các mô hình trước đó. </p>","metadata":{}},{"cell_type":"code","source":"params = {\"alpha\": [0.01, 0.05, 0.5], \"solver\": [\"auto\"], \"tol\": [1e-5, 1e-3, 0.01]}\n\n# increase number of folds\nfolds_ = KFold(n_splits=50, shuffle=True, random_state=42)\n\nrandom_ridge = RandomizedSearchCV(Ridge(), param_distributions=params, cv=folds_, n_iter=10, n_jobs=-1, scoring=\"neg_mean_absolute_error\", verbose=1)\nresult = random_ridge.fit(scaled_x_train, y_train)\n\nprint(\"Best MAE score: {}\".format(-result.best_score_))\nprint(\"Best params: {}\".format(result.best_params_))","metadata":{"execution":{"iopub.status.busy":"2021-12-21T05:51:37.305001Z","iopub.execute_input":"2021-12-21T05:51:37.305257Z","iopub.status.idle":"2021-12-21T05:51:42.822302Z","shell.execute_reply.started":"2021-12-21T05:51:37.305227Z","shell.execute_reply":"2021-12-21T05:51:42.819052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Nhận xét:\n<p style=\"font-size:18px\"> Ta có thể thấy MAE score của mô hình LightGBMRegressor là thấp nhất trong 3 mô hình đã được thử nghiệm. AdaBoostRegressor có MAE không lớn hơn nhiều so với LightGBM, trong khi đó mô hình Ridge cũng chỉ tăng MAE ttương đối cao so với 2 mô hình còn lại. Việc tăng số lượng fold cho mô hình Ridge cũng không làm thay đổi đáng kể, MAE score chỉ giảm tối đa 0.01.<br>\n<br>\nCuối cùng, chúng ta sẽ sử dụng thư viện <code>sklearn</code> để gọi <code>VotingRegressor</code>, là một công cụ kết hợp các mô hình học máy khác nhau dựa trên toàn bộ tập dữ liệu và trả về giá trị dự đoán trung bình. Từ đó tạo thành dự đoán cuối cùng.\n</p>","metadata":{}},{"cell_type":"code","source":"best_estimators = [(\"AdaBoostRegressor\", random_ada.best_estimator_), (\"LightGBMRegressor\", random_light_gbm.best_estimator_), (\"Ridge\", random_ridge.best_estimator_)]\n\nvoting = VotingRegressor(estimators=best_estimators, n_jobs=-1)\nvoting.fit(scaled_x_train, y_train)\n\n# score of voting model\ncvs_voting = cross_val_score(voting, scaled_x_train, y_train, cv=folds, scoring=\"neg_mean_absolute_error\")\nprint(\"Voting: {}\".format(-cvs_voting.mean()))","metadata":{"execution":{"iopub.status.busy":"2021-12-21T06:21:26.182849Z","iopub.execute_input":"2021-12-21T06:21:26.183147Z","iopub.status.idle":"2021-12-21T06:23:03.51118Z","shell.execute_reply.started":"2021-12-21T06:21:26.183115Z","shell.execute_reply":"2021-12-21T06:23:03.510324Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Ngoài ra, chúng ta cũng sẽ thử submit kết quả dự đoán của mô hình LightGBMRegressor do có điểm MAE thấp nhất và so sánh với kết quả dự đoán sau khi sử dụng VotingRegressor.</p>","metadata":{}},{"cell_type":"code","source":"# predict on scaled_x_test dataframe\nsubmission.time_to_failure = voting.predict(scaled_x_test)\n# submission.time_to_failre = random_light_gbm.predict(scaled_x_test)\n\n# write to csv file for submit\nsubmission.to_csv(\"submission.csv\", index=False)\nsubmission.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-21T06:28:11.926427Z","iopub.execute_input":"2021-12-21T06:28:11.926711Z","iopub.status.idle":"2021-12-21T06:28:12.144672Z","shell.execute_reply.started":"2021-12-21T06:28:11.926681Z","shell.execute_reply":"2021-12-21T06:28:12.143962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 7. Kết quả","metadata":{}},{"cell_type":"markdown","source":"#### Do cuộc thi đã kết thúc nên em không thể lấy được ranking cụ thể của submisson, chỉ có Private/Public Score như dưới đây.\n<p style=\"font-size:18px\"> Kết quả submit với LightGBMRegressor (có MAE score thấp nhất trong 3 mô hình đã thử nghiệm). </p>","metadata":{}},{"cell_type":"markdown","source":"![image.png](attachment:6249d4fc-4962-4089-90e1-154d9f1ec40f.png)","metadata":{},"attachments":{"6249d4fc-4962-4089-90e1-154d9f1ec40f.png":{"image/png":"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IJ4wwFN5BAcLq3H2TAHM59VIveMWJMXIJTvMsP5acL/19NcwF32NzuV34K/WGYL+rQ3tew41/it95DaElIn106fQzx8wR4OFiWpcqszHkc+L5HItO3UefQkb8YOblgTai1xuerjLj+Ljr07ja3MxrL6V+KvbVkMrjUwfr0yG9L0DAn348IZiHPmkDBbbKRTUdGLJrZlIW/DttDfplT7X9QnK9Mzz++Qzn2HhqqkNM1JIVw5xhWmMRh7+ep0KqpHaabfIv/RC7gm9kTtwaT9MJfKpzLkictlNdNsjk/ctTOzbtGQo1Jhpj1duU9w3Z/lvcBDKC9Wlbcy5kn2b5voiIqJrgPLbPoU+w2SPmfL64ggy1rFs7DSneByahv7B98aV9BUm1QecjvYQWD7p/u613h4mUI5yuYzWF5dMsi5GMqWynUlXWm9ymYgYa6zfD2kdjF6us7m92erPXeWglmgahQS1RERERET0vSMFtdfK+QmiSQtTGWG8Vs9EEhERERHRVcErtURERERERDQr8UotERERERERzWoMaomIiIiIiGjWYlBLREREREREsxaDWiIiIiIiIpq1GNQSERERERHRrMWgloiIiIiIiGYtBrVEREREREQ0a13X0tLK99QSERERERHRrONua8N1fYIyTURERERERDRr2OrPcfgxERERERERzV4MaomIiIiIiGjWYlBLREREREREsxaDWiIiIiIiIpq1GNQSERERERHRrMWgloiIiIiIiGYtvtKHiIiIiIhoglrdl1H9tRWdnV3KnMmJiorE6uuTodPGKnPoSvCVPkRERERERJNQb2+YckArkb4rBcU0fXilloiIiIiIaILyjhfJ/8/afKv8/8m60u9TKF6pJSIiIiIiolmNQS0RERERERHNWgxqiYiIiIiIaNZiUEtERERERESzFoNaIiIiIiIimrVmQVDbg842D9xdvcr0NOhtQ9GRCuSc7VBmTF3n2Wq8dqQe7mnMHhEREY3N19oAS00DWtt9ypyx+drb0T70r1NZOIwvsHy0pP0+tJ63wHK+FT6/Mm8EA3kcdTtSvlrRUGNBQ+vE9oMmqFOq42luGxOpd7FOe1MdzHXO0duPpHMC9T6RdYhINgte6VOPPS+cRXlGBg7cqVPmXSFXNR7+rQN5K1bi4vZEZebUmHKOIeOsCgf+/nZs1ysziYiIaGZ0NuDo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"}}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Kết quả submit sau khi sử dụng Voting Regressor. </p>","metadata":{}},{"cell_type":"markdown","source":"![image.png](attachment:5d2c04ba-4d60-4908-ade8-9208c9111c9a.png)","metadata":{},"attachments":{"5d2c04ba-4d60-4908-ade8-9208c9111c9a.png":{"image/png":"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"}}},{"cell_type":"markdown","source":"<p style=\"font-size:18px\"> Như vậy, kết quả submit với Voting Regressor cao hơn một chút so với LightGBM Regressor.</p>","metadata":{}},{"cell_type":"markdown","source":"# 8. Tài liệu tham khảo\n### [K- Fold Cross Validation For Parameter Tuning](https://medium.datadriveninvestor.com/k-fold-cross-validation-for-parameter-tuning-75b6cb3214f)\n### [LightGBM with RandomizedSearchCV](https://www.kaggle.com/binilg/lightgbm-with-randomsearchcv-and-feature-imp)\n### [Boosting](https://www.kaggle.com/fengdanye/machine-learning-7-boosting)\n### [GradientBoosting](https://viblo.asia/p/gradient-boosting-tat-tan-tat-ve-thuat-toan-manh-me-nhat-trong-machine-learning-YWOZrN7vZQ0)\n### [Hồi qui Ridge](https://phamdinhkhanh.github.io/deepai-book/ch_ml/RidgedRegression.html)","metadata":{}}]}