Basics {#basics}

Chương này sẽ hướng dẫn những blocks cơ bản, R6 classes, và hoạt động của r mlr_pkg("mlr3") với machine learning.

Một quy trình machine learning điển hình trông như thế này:

knitr::include_graphics("images/ml_abstraction.png")

Dữ liệu, cái mà r mlr_pkg("mlr3") gói gọn trong tasks, được chia thành tập training và tập test một cách riêng rẽ

Chúng ta thường thích những mô hình mà tổng quát cho dữ liệu mới hơn là những mô hình chỉ tốt với tập dữ liệu training, và việc phân chia dữ liệu test cho phép đánh giá mô hình một cách khách quan. Dữ liệu training được cung cấp cho 1 thuật toán ML, cái mà chúng ta gọi là một learner in r mlr_pkg("mlr3").

Learner sử dụng dữ liệu training để xây dựng mô hình dựa trên mối quan hệ giữa thuộc tính đầu vào (input feature) để dự báo đầu ra.

Mô hình này sau đó cung cấp predictions cho dữ liệu test, cái mà so sánh với dữ liệu thực tế để đánh giá chất lượng mô hình

r mlr_pkg("mlr3") cung cấp 1 số measures khác nhau để lượng hóa thế nào là một mô hình tốt dựa trên sự khác biệt giữa giá trị dự vào và giá trị thực tế. Thông thường, measures này là một numeric score.

Quá trình chia dữ liệu thành tập training và test, xây dựng mô hình, đánh giá nó có thể lặp lại nhiều lần, mỗi lần như vậy gọi là resampling. Trong đó, mẫu training và test được thay đổi khác nhau dựa trên dữ liệu gốc ban đầu. Nhiều lần lặp lại resampling iterations như vậy cho phép chúng ta đánh giá 1 cách tổng quát về loại mô hình cụ thể vì nó được test trên các điều kiện khác nhau và ít có khả năng gặp may hoặc không may với 1 mẫu cá biệt.

Trong nhiều trường hợp, quy trình đơn giản này không đủ để giải quyết với dữ liệu thực tế, bởi còn nhiều bước như chuẩn hóa (normalization), xử lý missing, hay feature selection. Chúng tôi sẽ đề cập những công việc phức tạp hơn này ở phần sau của sách.

Chương này gồm 1 số topics nhỏ sau:

Tasks

Tasks đóng gói dữ liệu với thông tin meta, như biến mục tiêu là.

Chúng tôi hướng dẫn cách thức thực hiện

Learners

Learners gói gọn các thuật toán ML để train mô hình và đưa ra dự đoán cho một r ref("mlr3::Task").

Chúng được cung cấp bởi R và nhiều packages khác.

Chúng tôi sẽ hướng dẫn:

Cách chỉnh sửa và mở rộng learners được đề cập trong phần advanced technical section.

Train and predict

Phân này minh họa cách sử dụng taskslearners để huấn luyện một mô hình và đưa ra dự báo predictions với tập dữ liệu mới

Các bước bao gồm

Resampling

Resampling là phương pháp chia training và test.

Các bước như:

Thông tin thêm về resampling có thể tìm trong phần nested resampling trong chương model optimization.

Benchmarking

Benchmarking được sử dụng để so sánh performance của những mô hình khác nhau, ví dụ mô hình đã được huấn luyện và những learners khác, tasks khác, resampling schemes khác.

Các bước như:

Binary classification

Binary classification là 1 trường hợp đặc biệt của bài toán phân loại với biến mục tiêu chỉ có 2 giá trị

Trong phần này, xem xét áp dụng bổ sung

Trước khi chúng ta đi vào chi tiết cách sử dụng r mlr_pkg("mlr3") cho ML, chúng tôi giới thiệu ngắn gọn về R6 vì đây là 1 phần mới của R

r mlr_pkg("mlr3") dựa rất nhiều vào R6 và tất cả các blocks cơ bản được tạo bởi R6 classes

Quick R6 Intro for Beginners {#r6}

R6 is one of R's more recent dialects for object-oriented programming (OO). It addresses shortcomings of earlier OO implementations in R, such as S3, which we used in r mlr_pkg("mlr"). If you have done any object-oriented programming before, R6 should feel familiar. We focus on the parts of R6 that you need to know to use r mlr_pkg("mlr3") here.

For more details on R6, have a look at the R6 vignettes.

Tasks {#tasks}

Tasks là đối tượng của dữ liệu và thông tin meta bổ sung cho bài toán ML. Meta-data có thể là tên của biến mục tiêu với bài toán supervised ML, hay loại dữ liệu (e.g. a spatial or survival). Thông tin này được sử dụng cho các hoạt động cụ thể để thực hiện một task

Task Types {#tasks-types}

Để tạo 1 task từ 1 đối tượng r ref("data.frame()") or r ref("data.table()"), loại task cần phải được chỉ định:

Classification Task: The target is a label (stored as character()orfactor()) with only few distinct values.
r ref("mlr3::TaskClassif")

Regression Task: The target is a numeric quantity (stored as integer() or double()).
r ref("mlr3::TaskRegr")

Survival Task: The target is the (right-censored) time to an event.
r ref("mlr3proba::TaskSurv") in add-on package r mlr_pkg("mlr3proba")

Ordinal Regression Task: The target is ordinal.
r ref("mlr3ordinal::TaskOrdinal") in add-on package r mlr_pkg("mlr3ordinal")

Cluster Task: An unsupervised task type; there is no target and the aim is to identify similar groups within the feature space.
→ Not yet implemented

Spatial Task: Observations in the task have spatio-temporal information (e.g. coordinates).
→ Not yet implemented, but started in add-on package r mlr_pkg("mlr3spatiotemporal")

Task Creation {#tasks-creation}

Như một ví dụ, chúng ta sẽ tạo 1 regression task sử dụng dữ liệu mtcars từ package datasets và dự báo cho biến mục tiêu "mpg" (miles per gallon). Chúng ta chỉ dùng 2 features đầu tiên của dữ liệu cho ngắn gọn.

Đầu tiên, load và chuẩn bị dữ liệu.

data("mtcars", package = "datasets")
data = mtcars[, 1:3]
str(data)

Tiếp theo, tạo task sử dụng hàm (TaskRegr$new) và nạp thông tin cho task:

  1. id: một định danh tùy ý cho task, cái này sẽ hữu ích trong plots và summaries.
  2. backend: Tham số này cho phép kiểm soát chi tiết cách tiếp cận dữ liệu. Trong phần này, chúng ta chỉ đơn giản là cung cấp dữ liệu cái mà sẽ được tự động chuyển thành r ref("DataBackendDataTable"). Chúng ta cũng có thể xây dựng r ref("DataBackend") bằng tay.
  3. target: tên của biến mục tiêu
library(mlr3)

task_mtcars = TaskRegr$new(id = "cars", backend = data, target = "mpg")
print(task_mtcars)

Hàm print() đưa ra thông tin khái quát ngắn gọn cho task như: Nó có r task_mtcars$nrow quan sát và r task_mtcars$ncol cột với r length(task_mtcars$feature_names) features

Chúng ta cũng có thể vẽ biểu đồ của task sử dụng r mlr_pkg("mlr3viz") package, cái mà cung cấp thông tin cơ bản về biểu đồ và thuộc tính của nó

library(mlr3viz)
autoplot(task_mtcars, type = "pairs")

Predefined tasks {#tasks-predefined}

r mlr_pkg("mlr3") lưu một số ML tasks được định nghĩa trước (là những ví dụ do mlr3 team đính kèm vào package). Tất cả tasks được lưu trong R6 r ref("Dictionary") với một định danh trước (a key-value store) r ref("mlr_tasks"). Dưới đây là tên các keys (ở đây là tên của datasets):

mlr_tasks

Chúng ta cũng có thể lấy thêm thông tin từ tasks đã được định nghĩa trước bằng cách chuyển đổi dictionary sang data.table() object:

library(data.table)
as.data.table(mlr_tasks)

Để lấy 1 task từ dictionary, có thể sử dụng phương thức $get() từ mlr_tasks class và lưu vào một object mới. Ví dụ, sử dụng iris data set với task loại classif đã được định nghĩa sẵn:

task_iris = mlr_tasks$get("iris")
print(task_iris)

Cách khác, bạn cũng có thể sử dụng hàm tiện ích r ref("tsk()"), để tạo 1 task từ dictionary.

tsk("iris")

Task API {#tasks-api}

Tất cả thuộc tính và đặc điểm của task có thể được truy vấn sử dụng task's public fields và phương thức (see r ref("Task")). Phương thức cũng được sử dụng để thay đổi hành vi của task

Retrieving Data {#tasks-retrieving}

Dữ liệu đã lưu của một task có thể lấy trực tiếp từ fields, ví dụ:

task_iris$nrow
task_iris$ncol

Thông tin thêm có thể có được từ phương thức của object, ví dụ:

task_iris$data()

Trong r mlr_pkg("mlr3") mỗi hàng (observation) có 1 định danh duy nhất. Định danh này có thể là một integer or character. Nó có thể được truyền như arguments của phương thức $data() để chọn những dòng cụ thể.

iris task sử dụng integer row_ids:

# iris uses integer row_ids
head(task_iris$row_ids)

# retrieve data for rows with ids 1, 51, and 101
task_iris$data(rows = c(1, 51, 101))

mtcars task theo cách khác, sử dụng names cho row_ids, encoded as character:

task_mtcars = tsk("mtcars")
head(task_mtcars$row_ids)

# retrieve data for rows with id "Datsun 710"
task_mtcars$data(rows = "Datsun 710")

Chú ý: method $data() chỉ cho phép đọc dữ liệu, không cho phép chỉnh sửa nó.

Tương tự, mỗi cột cũng có 1 định danh hoặc tên. Những tên này được lưu trong public slots feature_namestarget_names. Ở đây "target" là biến mà chúng ta muốn dự báo và "feature" là biến predictors.

task_iris$feature_names
task_iris$target_names

row_ids và tên column có thể kết hợp khi lựa chọn tập con của dữ liệu:

# retrieve data for rows 1, 51, and 101 and only select column "Species"
task_iris$data(rows = c(1, 51, 101), cols = "Species")

Để xuất toàn bộ dữ liệu từ task, đơn giản chỉ cần convert nó thành một data.table:

summary(as.data.table(task_iris))

Roles (Rows and Columns) {#tasks-roles}

Có thể gán vai trò (roles) cho rows và columns. Những roles ảnh hưởng tới hành vi của task với các hoạt động khác nhau. Hơn nữa những roles này cũng cấp meta-data bổ sung cho nó.

Ví dụ, xem column roles của mtcars task đã được xây từ trước:

print(task_mtcars$col_roles)

Để thêm row names của mtcars như một feature bổ sung, chúng ta thêm chúng vào cột đầu tiên của bảng dữ liệu và tạo lại task.

# with `keep.rownames`, data.table stores the row names in an extra column "rn"
data = as.data.table(mtcars[, 1:3], keep.rownames = TRUE)
task = TaskRegr$new(id = "cars", backend = data, target = "mpg")

# we now have integer row_ids
task$row_ids

# there is a new feature called "rn"
task$feature_names

Row names bây giờ thành một feature có chứa giá trị được lưu trong cột "rn". Chúng ta thêm cột này vào đây chỉ với mục đích luyện tập. Nói chung, không có feature nào mà lại có giá trị duy nhất tại mỗi dòng. Hơn nữa, loại dữ liệu cũng có vấn đề với nhiều thuật toán ML. Mã định danh có thể hữu ích khi gán nhãn với plots hoặc xác định outliers. Vì sử dụng cột mới chỉ cho mục đích này, chúng ta sẽ thay đổi role của cột "rn" thành tên và loại nó ra khỏi active features.

task$feature_names

# working with a list of column vectors
task$col_roles$name = "rn"
task$col_roles$feature = setdiff(task$col_roles$feature, "rn")

# "rn" not listed as feature anymore
task$feature_names

# does also not appear when we access the data anymore
task$data(rows = 1:2)
task$head(2)

Thay đổi role không làm thay đổi dữ liệu gốc. Thay đổi chỉ làm thay đổi view on it. Dữ liệu không được copy khi dùng code bên trên. View chỉ được thay đổi tại chỗ, tức là task object bản thân nó được sửa đổi.

Giống như cột, cũng có thể gán role khác nhau cho các hàng. Hàng có thể có 2 loại roles:

  1. Role use Rows thông thường dùng cho việc model fitting (mặc dù chúng cũng có thể sử dụng như tập test khi resampling). Role này được mặc định với hàng.

  2. Role validation Rows mà không được sử dụng cho việc huấn luyện mô hình. Rows mà có missing values với biến mục tiêu, khi tạo 1 task được tự động gán thành validation role.

Có vài lý do để giữ vài quan sát để xử lý 1 cách khác biệt:

  1. Thông thường để xác nhận 1 mô hình cuối cùng là tốt, phải dựa trên mẫu bên ngoài để đánh giá để tránh hiện tượng overfitting.
  2. Một vài quan sát có thể không được gán nhãn, ví dụ trong cuộc thi trên Kaggle. Những quan sát này có thể không sử dụng cho việc huấn luyện mô hình nhưng có thể sử dụng để có được dự báo.

Task Mutators {#tasks-mutators}

Như đã nói ở trên, chỉnh sửa $col_roles or $row_roles chỉ làm thay đổi view on the data. Phương thức tiện dụng $filter() lấy tập con dựa trên row ids và $select() lấy tập con dựa trên feature names.

task = tsk("iris")
task$select(c("Sepal.Width", "Sepal.Length")) # keep only these features
task$filter(1:3) # keep only these rows
task$head()

Trong khi phương thức đã thảo luận ở trên cho phép trích xuất tập con thì phương pháp $rbind()$cbind() cho phép thêm dòng hoặc cột vào một task. Đương nhiên dữ liệu gốc không thay đổi. Dòng và cột được thêm chỉ ảnh hưởng tới view of the data.

task$cbind(data.table(foo = letters[1:3])) # add column foo
task$head()

Plotting Tasks {#autoplot-task}

Package r mlr_pkg("mlr3viz") cung cấp nhiều phương tiện biểu đồ để thực hiện r mlr_pkg("mlr3"). Loại biểu đồ phụ thuộc vào inherited class, nhưng tất cả biểu đồ được trả vể dưới dạng r cran_pkg("ggplot2") objects nên sẽ dễ dàng hiệu chỉnh.

Để hiểu thêm về cách thức vẽ biểu đồ cho classification tasks (inheriting from r ref("TaskClassif")), xem thêm tài liệu r ref("mlr3viz::autoplot.TaskClassif"). Dưới đây là một vài ví dụ có ấn tượng:

library(mlr3viz)

# get the pima indians task
task = tsk("pima")

# subset task to only use the 3 first features
task$select(head(task$feature_names, 3))

# default plot: class frequencies
autoplot(task)

# pairs plot (requires package GGally)
autoplot(task, type = "pairs")

# duo plot (requires package GGally)
autoplot(task, type = "duo")

Đương nhiên, bạn có thể làm tương tự với regression tasks (inheriting from r ref("TaskRegr")) như tài liệu r ref("mlr3viz::autoplot.TaskRegr"):

library(mlr3viz)

# get the boston housing task
task = tsk("mtcars")

# subset task to only use the 3 first features
task$select(head(task$feature_names, 3))

# default plot: boxplot of target variable
autoplot(task)

# pairs plot (requires package GGally)
autoplot(task, type = "pairs")

Learners {#learners}

Đối tượng của lớp r ref("mlr3::Learner") cung cấp giao diện đồng nhất cho nhiều thuật toán ML phổ biến trong R. Chúng bao gồm các phương pháp để huấn luyện và dự báo một mô hình cho một r ref("mlr3::Task") và cung cấp thông tin meta về learners, như là hyperparameters mà bạn đặt.

Package này chứa tối thiểu thông tin của classification and regression learners để tránh phụ thuộc quá nhiều:

Dưới đây là một vài learners phổ biến được kết nối thông qua r mlr_pkg("mlr3learners") package:

Các learners khác được sưu tập trên GitHub mlr3learners organization, và wiki của mlr3learners repository.

Cơ sở của mỗi learner là r ref("Learner"), cho regression như r ref("LearnerRegr") classification là r ref("LearnerClassif"). Ngược lại với r ref("Task"), việc tùy chỉnh Learner thường không cần thiết và không cần advanced topic. Vì vậy, chúng tôi giới thiệu độc giả tới phần \@ref(ext-learner) và tiến hành với tổng quan giao diện đã được thực hiện learners.

Predefined Learners {#learners-predefined}

Tương tự r ref("mlr_tasks"), r ref("Dictionary") r ref("mlr_learners") có thể được truy vấn với những learners có sẵn:

library(mlr3learners)
mlr_learners

Mỗi learner có thông tin đi kèm như:

Tổng quan về các thuộc tính của learners xem \@ref(list-learners).

Để sử dụng learner cụ thể cần sử dụng id của nó, được liệt kê dưới key trong dictionary:

learner = mlr_learners$get("classif.rpart")
print(learner)

Trường param_set chứa các mô tả về hyperparameters mà learner có, bao gồm khoảng giá trị, giá trị mặc định, và giá trị đang được sử dụng.

learner$param_set

Tập giá trị hyperparameter được lưu trong cột value của trường param_set. Bạn có thể thay đổi giá trị này bằng việc gán một danh sách các tên cho trường này:

learner$param_set$values = list(cp = 0.01, xval = 0)
learner

Chú ý rằng, hoạt động này chỉ viết đè lên các tham số đã có trước đó. Nếu bạn muốn thêm hay cập nhật hypeparameters, bạn có thể sử dụng r ref("mlr3misc::insert_named()"):

learner$param_set$values = mlr3misc::insert_named(
  learner$param_set$values,
  list(cp = 0.02, minsplit = 2)
)
learner

Sau cập nhật này cp thành 0.02, minsplit thành 2 và giữ nguyên tham số xval.

Cách viết khác ngắn gọn hơn mlr_learners$get() sử dụng hàm tiện ích r ref("lrn()"). Hàm này cho phép chỉ rõ hyperparameters và những cài đặt định danh khác khi xây dựng learners

lrn("classif.rpart", id = "rp", cp = 0.001)

Nếu bạn bỏ qua hypeparameters ở đây, tham số mặc định sẽ được thêm vào và thêm tham số sử dụng hàm r ref("mlr3misc::insert_named()", text = "insert_named()") như trên.

Thông tin chi tiết hơn về cách tùy chỉnh learners sử dụng mlr3, xem trong phần extending learners.

Train and Predict {#train-predict}

Trong phần này, chúng tôi giải thích cách mà taskslearners được sử dụng để huấn luyện mô hình và dự báo với dữ liệu mới. Khái niệm này được minh họa trên suppervised classification sử dụng dữ liệu iris và rpart learner (classification tree).

Huấn luyện một learner có nghĩa là fitting một mô hình với dữ liệu đã có. Sau đó, chúng ta sẽ predict cho quan sát mới. Những predictions này sau đó được so sánh với giá trị thực tế để đánh giá chất lượng mô hình. Tóm lại, mục tiêu của huấn luyện và dự báo là để đánh giá khả năng dự báo của các mô hình khác nhau.

Creating Task and Learner Objects {#train-predict-objects}

Đầu tiên, tạo các r mlr_pkg("mlr3") object từ task dictionarylearner dictionary tương ứng:

  1. The classification task:
task = tsk("sonar")
  1. A learner for the classification tree:
learner = lrn("classif.rpart")

Setting up the train/test splits of the data {#split-data}

Thông thường việc huấn luyện sẽ thực hiện trên phần lớn quan sát của dữ liệu. Ở đây sử dụng 80% quan sát để huấn luyện và 20% quan sát còn lại để dự báo. Để làm như vậy, chúng ta tạo 2 index vectors:

train_set = sample(task$nrow, 0.8 * task$nrow)
test_set = setdiff(seq_len(task$nrow), train_set)

Training the learner {#training}

Trường model lưu mô hình được tạo ở bước huấn luyện. Trước khi train method được gọi trên learner object, trường này bằng NULL:

learner$model

Tiếp theo, classification tree được huấn luyện sử dụng tập train của iris task, áp dụng $train() của r ref("Learner"):

learner$train(task, row_ids = train_set)

Hoạt động này chỉnh sửa learner tại chỗ. Chúng ta bây giờ có thể tiếp cận mô hình đã được lưu qua trường $model:

print(learner$model)

Predicting {#predicting}

Sau khi mô hình đã được huấn luyện, chúng ta sử dụng phần còn lại của dữ liệu để dự báo. Nhớ rằng, chúng ta đã chia dữ liệu initially split the data thành train_settest_set.

prediction = learner$predict(task, row_ids = test_set)
print(prediction)

Phương pháp dự báo $predict() của r ref("Learner") trả về một r ref("Prediction") object. Chính xác hơn, là learner classification, một r ref("LearnerClassif") trả về một r ref("PredictionClassif") object.

Một prediction objects cố định row ids của tập test, nhãn tương ứng của giá trị thật và của giá trị dự báo. Cách đơn giản nhất để xuất thông tin này là chuyển sang một data.table():

head(as.data.table(prediction))

Với bài toán phân loại, bạn cũng có thể xuất confusion matrix:

prediction$confusion

Changing the Predict Type {#predict-type}

Classification learners mặc định dự báo các class label. Tuy nhiên, nhiều thuật toán cũng cung cấp dự báo label bằng xác suất. Để chuyển sang phần dự báo bằng xác suất, trường predict_type của r ref("LearnerClassif") phải chuyển từ "response" sang "prob":

learner$predict_type = "prob"

# re-fit the model
learner$train(task, row_ids = train_set)

# rebuild prediction object
prediction = learner$predict(task, row_ids = test_set)

Prediction object bây giờ có chứa đồng thời cả xác suất và response của tất cả class labels:

# data.table conversion
head(as.data.table(prediction))

# directly access the predicted labels:
head(prediction$response)

# directly access the matrix of probabilities:
head(prediction$prob)

Tương tự dự báo xác suất, nhiều r ref("LearnerRegr", text = "regression learners") hỗ trợ xuất sai số chuẩn bằng việc đặt predict type thành "se".

Plotting Predictions {#autoplot-prediction}

Tương tự plotting tasks, r mlr_pkg("mlr3viz") cung cấp một r ref("ggplot2::autoplot()", text = "autoplot()") phương pháp.

Tất cả các loại được liệt kê trong page hướng dẫn sử dụng r ref("autoplot.PredictionClassif()") hoặc r ref("autoplot.PredictionClassif()") tương ứng.

library(mlr3viz)

task = tsk("sonar")
learner = lrn("classif.rpart", predict_type = "prob")
learner$train(task)
prediction = learner$predict(task)
autoplot(prediction)
autoplot(prediction, type = "roc")
library(mlr3viz)
library(mlr3learners)
local({ # we do this locally to not overwrite the objects from previous chunks
    task = tsk("mtcars")
    learner = lrn("regr.lm")
    learner$train(task)
    prediction = learner$predict(task)
    autoplot(prediction)
})

Performance assessment {#measure}

Bước cuối cùng của việc mô hình thông thường là đánh giá hiệu quả. Chất lượng dự báo của một mô hình trong mlr3 có thể được đánh giá dựa trên các tiêu chí khác nhau. Khi đánh giá, chúng tôi chọn một thước đo cụ thể để định lượng dự báo. Việc này thực hiện bằng cách so sánh nhãn dự báo với nhãn thực tế. Những thước đo có sẵn được lưu trong r ref("mlr_measures") hoặc với hàm tiện ích r ref("msr()"):

mlr_measures

Chúng tôi chọn accuracy (r ref("mlr_measures_classif.acc", text = "classif.acc")) và gọi phương thức $score() của r ref("Prediction") object.

measure = msr("classif.acc")
prediction$score(measure)

Chú ý rằng, nếu không có measure nào được chỉ ra, classification mặc định là classification error (r ref("mlr_measures_classif.ce", text = "classif.ce")) và regression mặc định là mean squared error (r ref("mlr_measures_regr.mse", text = "regr.mse")).

Resampling {#resampling}

Chiến lược resampling thường được sử dụng để đánh giá hiệu quả của một thuật toán ML. mlr3 có sẵn 6 chiến lược resampling: Cross-validation, Leave-one-out cross validation, Repeated cross-validation, Out-of-bag bootstrap and other variants (e.g. b632), Monte-Carlo cross-validation and Holdout. Các mục sau đây sẽ cung cấp hướng dẫn cách thiết lập và lựa chọn chiến lược resampling và cách khởi tạo quy trình resampling.

Dưới đây là minh họa biểu đồ của quá trình resampling:

knitr::include_graphics("images/ml_abstraction.png")

Settings {#resamp-settings}

Trong phần ví dụ này, chúng tôi sử dụng iris task và classification tree (package r cran_pkg("rpart")).

task = tsk("iris")
learner = lrn("classif.rpart")

Để thực hiện resampling với một tập dữ liệu, đầu tiên, chúng ta cần định nghĩa cách tiếp cận sẽ sử dụng. Chiến lược resampling của mlr3 có thể được truy vấn sử dụng .$keys() là một phương thức của r ref("mlr_resamplings") dictionary

mlr_resamplings

Phương pháp resampling bổ sung trong trường hợp đặc biệt sử dụng packages mở rộng như r gh_pkg("mlr-org/mlr3spatiotemporal") cho spatial data (still in development).

Độ phù hợp của mô hình được thực hiện trong chương train/predict/score bằng với 1 "holdout", trước tiên hãy xem xét nó. Chúng ta có thể truy vấn các phần tử từ dictionary r ref("mlr_resamplings") via $get() hoặc hàm tiện ích (r ref("rsmp()")):

resampling = rsmp("holdout")
print(resampling)

chú ý rằng, trường Instantiated được đặt bằng FALSE. Có nhĩa là chúng ta không thực sự áp dụng chiến lược này cho tập dữ liệu, nhưng vẫn chạy chay (dry-run). Áp dụng chiến lược cho dữ liệu được thực hiện trong phần tiếp theo Instantiation.

Mặc định tỷ lệ phân chia quan sát là .66 / .33. Có 2 cách để thay đổi tỷ lệ:

  1. Ghi đè lên giá trị .$param_set$values đang dùng trong danh sách tên:
resampling$param_set$values = list(ratio = 0.8)
  1. Chỉ rõ tham số resampling trong quá trình xây dựng:
rsmp("holdout", ratio = 0.8)

Instantiation {#resampling-inst}

Cho đến nay, chúng ta mới chỉ thiết lập giai đoạn và chọn kịch bản resampling. Để thực sự thực hiện phân chia dữ liệu, resampling cần một r ref("Task"). Bằng việc gọi phương thức instantiate(), dữ liệu được chia thành tập training và test và được lưu vào r ref("Resampling") object:

resampling = rsmp("cv", folds = 3L)
resampling$instantiate(task)
resampling$iters
str(resampling$train_set(1))
str(resampling$test_set(1))

Execution {#resampling-exec}

Với một r ref("Task"), một r ref("Learner")r ref("Resampling") object chúng ta có thể gọi r ref("resample()") và tạo một r ref("ResampleResult") object.

Trước khi đi vào chi tiết, chúng ta thay đổi resampling thành "3-fold cross-validation" để minh họa tốt hơn những hoạt động nào có thể xảy ra với một r ref("ResampleResult"). Ngoài ra, chúng ta sẽ nói với r ref("resample()") để giữ mô hình đã được fitted thông qua đánh dấu store_models:

task = tsk("pima")
learner = lrn("classif.rpart", maxdepth = 3, predict_type = "prob")
resampling = rsmp("cv", folds = 3L)

rr = resample(task, learner, resampling, store_models = TRUE)
print(rr)

Các hoạt động tiếp theo được hỗ trợ với r ref("ResampleResult") objects:

Chú ý rằng, nếu bạn muốn so sánh nhiều learners, bạn nên chắc chắn rằng, mỗi learner hoạt động trên cùng mẫu resampling giống nhau. Điều này làm giảm khác biệt của hiệu quả ước lượng.

Nếu mục đích của bạn để so sánh sự khác biệt r ref("Task"), r ref("Learner") hay r ref("Resampling"), tốt hơn, bạn nên sử dụng hàm r ref("benchmark()"), được đề cập trong phần tiếp theo next section. Về cơ bản r ref("resample()") làm đơn giản hóa việc xử lý nhiều cài đặt. Nếu bạn phát hiện ra điều này chỉ sau khi bạn chạy nhiều r ref("resample()"), đừng lo lắng. Bạn có thể kết hợp nhiều r ref("ResampleResult") object vào một r ref("BenchmarkResult") (cũng được giải thích trong phần next section)

Custom resampling {#resamp-custom}

Thỉnh thoảng, cần phải thực hiện resampling với mẫu tùy chỉnh. Bạn làm như vậy vì bạn cần một mô hình cụ thể, đầu tiên xem mở rộng của mlr3 packages. Điều quan trọng là phương pháp lấy mẫu kiểu này chưa được thực hiện.

Nếu phương pháp resampling tùy chỉnh này được rộng rãi trong lĩnh vực của bạn, bạn nên tích hợp nó vào một trong các phần mở rộng của mlr3 packages.

Bạn cũng có thể tạo phần mở rộng package của bạn.

Một ví dụ resampling có thể được tạo sử dụng "custom" template.

resampling = rsmp("custom")
resampling$instantiate(task,
  train = list(c(1:10, 51:60, 101:110)),
  test = list(c(11:20, 61:70, 111:120))
)
resampling$iters
resampling$train_set(1)
resampling$test_set(1)

Plotting Resample Results {#autoplot-resampleresult}

Một lần nữa, r mlr_pkg("mlr3viz") cung cấp một phương pháp r ref("ggplot2::autoplot()", text = "autoplot()").

library(mlr3viz)

autoplot(rr)
autoplot(rr, type = "roc")

Tất cả loại plot được liệt kê trong phần hướng dẫn r ref("autoplot.ResampleResult()").

Benchmarking {#benchmarking}

So sánh performance của các learners khác nhau dựa trên nhiều task và/hoặc nhiều sơ đồ resampling khác nhau là công việc thường xuyên. Hoạt động này thường gọi là "benchmarking" trong lĩnh vực ML. r mlr_pkg("mlr3") package cung cấp hàm tiện ích r ref("benchmark()").

Design Creation {#bm-design}

Trong mlr3 yêu cầu chúng ta cung cấp một "design" của thử nghiệm benchmark. Theo "design" chúng ta cơ bản tạo một ma trận các cài đặt bạn muốn thực hiện. Một "design" bao gồm r ref("Task"), r ref("Learner")r ref("Resampling").

Ở đây, chúng ta gọi r ref("benchmark()") để thực hiện một thử nghiệm đơn giản với holdout split, một task đơn giản và 2 learners. Chúng ta sử dụng hàm r ref("benchmark_grid()") để tạo một thiết kế toàn diện và khởi tạo chính xác việc resampling:

library(data.table)
design = benchmark_grid(
  tasks = tsk("iris"),
  learners = list(lrn("classif.rpart"), lrn("classif.featureless")),
  resamplings = rsmp("holdout")
)
print(design)
bmr = benchmark(design)

Chú ý rằng, holdout splits được tự động khởi tạo cho mỗi dòng của design. Như kết quả, rpart learner sử dụng tập training khác so với featureless learner. Tuy nhiên, để so sánh learners bạn thường muốn learners sử dụng cùng một tập train và tập test. Để khắc phục vấn đề này, chiến lược resampling cần phải thực hiện thủ công manually instantiated trước khi tạo design.

Giao diện của r ref("benchmark()") rất linh hoạt. Mặc dù, việc tạo ra các bảng design này rất tẻ nhạt. Qua đó, r mlr_pkg("mlr3") cung cấp một hàm tiện ích để nhanh chóng tạo bảng design và khởi tạo chiến lược resampling trong toàn bộ lưới : r ref("benchmark_grid()").

# get some example tasks
tasks = lapply(c("german_credit", "sonar"), tsk)

# get some learners and for all learners ...
# * predict probabilities
# * predict also on the training set
library(mlr3learners)
learners = c("classif.featureless", "classif.rpart", "classif.ranger", "classif.kknn")
learners = lapply(learners, lrn,
  predict_type = "prob", predict_sets = c("train", "test"))

# compare via 3-fold cross validation
resamplings = rsmp("cv", folds = 3)

# create a BenchmarkDesign object
design = benchmark_grid(tasks, learners, resamplings)
print(design)

Execution and Aggregation of Results {#bm-exec}

Sau khi benchmark design đã sẵn sàng, chúng ta có thể gọi trực tiếp r ref("benchmark()"):

# execute the benchmark
bmr = benchmark(design)

Chú ý rằng, chúng tôi không thực hiện ví dụ resampling. r ref("benchmark_grid()") sẽ hướng dẫn đầy đủ công việc đó: Việc thêm các chiến lược resampling sẽ tạo được một lưới đầy đủ.

Sau benchmark, có thể tính toán và tổng hợp performance với phương thức .$aggregate():

# measures:
# * area under the curve (auc) on training
# * area under the curve (auc) on test
measures = list(
  msr("classif.auc", id = "auc_train", predict_sets = "train"),
  msr("classif.auc", id = "auc_test")
)
bmr$aggregate(measures)

Sau đó, chúng ta có thể có bước tổng hợp kết quả xa hơn. Ví dụ, chúng ta có thể quan tâm learner nào có thể thực hiện tốt nhất các tasks trong cùng 1 lúc. Tổng hợp các performances đơn giản với trung bình thường không phải là phương pháp thống kê tốt. Thay vào đó, chúng ta tính hạng thống kê (rank statistic) cho mỗi learner theo nhóm task. Sau đó tính ranks nhóm theo learner để có được tổng hợp. Vì AUC phải tính theo giá trị lớn nhất, chúng ta nhân với $-1$ để có được learner tốt nhất với rank = 1.

tab = bmr$aggregate(measures)
ranks = tab[, .(learner_id, rank_train = rank(-auc_train), 
                rank_test = rank(-auc_test)), 
            by = task_id]

print(ranks)

ranks[, .(mrank_train = mean(rank_train), 
          mrank_test = mean(rank_test)), 
      by = learner_id][order(mrank_test)]

Không ngạc nhiên khi learner featureless hiệu quả kém nhất.

Plotting Benchmark Results {#autoplot-benchmarkresult}

Tương tự để plot tasks, predictions hay resample results, r mlr_pkg("mlr3viz") cũng cung cấp một phương phápr ref("ggplot2::autoplot()", text = "autoplot()") cho kết quả benchmark.

library(mlr3viz)
library(ggplot2)

autoplot(bmr) + theme(axis.text.x = element_text(angle = 45, hjust = 1))

Chúng ta cũng có thể plot ROC curves. Để làm vậy, chúng ta cần filter r ref("BenchmarkResult") để chỉ chứa một r ref("Task"):

autoplot(bmr$clone()$filter(task_id = "german_credit"), type = "roc")

Tất cả các loại plot được liệt kê trong trang r ref("autoplot.BenchmarkResult()").

Extracting ResampleResults {#bm-resamp}

Một r ref("BenchmarkResult") object về cơ bản là một tập hợp nhiều r ref("ResampleResult") objects. Vì chúng được lưu trong 1 cột data.table(), chúng ta có thể dễ dàng trích xuất chúng:

tab = bmr$aggregate(measures)
rr = tab[task_id == "sonar" & learner_id == "classif.ranger"]$resample_result[[1]]
print(rr)

Chúng ta có bây giờ có thể kiểm tra việc resampling này và thậm chí lặp lại lấy mẫu resampling bằng việc sử dụng 1 trong các cách tiếp cận của phần trước the previous section:

measure = msr("classif.auc")
rr$aggregate(measure)

# get the iteration with worst AUC
perf = rr$score(measure)
i = which.min(perf$classif.auc)

# get the corresponding learner and train set
print(rr$learners[[i]])
head(rr$resampling$train_set(i))

Converting and Merging ResampleResults

Cũng có thể chuyển một r ref("ResampleResult") thành một r ref("BenchmarkResult") sử dụng chuyển đổi r ref("as_benchmark_result()").

task = tsk("iris")
resampling = rsmp("holdout")$instantiate(task)

rr1 = resample(task, lrn("classif.rpart"), resampling)
rr2 = resample(task, lrn("classif.featureless"), resampling)

# Cast both ResampleResults to BenchmarkResults
bmr1 = as_benchmark_result(rr1)
bmr2 = as_benchmark_result(rr2)

# Merge 2nd BMR into the first BMR
bmr1$combine(bmr2)

bmr1

Binary classification {#binary}

Các bài toán phân loại mà biến mục tiêu chỉ có 2 nhóm được gọi là "binary". Với biến mục tiêu nhị phân như vậy, bạn có thể chỉ định positive class bên trong r ref("TaskClassif", text = "classification task") object trong khi tạo task. Nếu không chỉ định, positive class mặc định là level đầu tiên của biến mục tiêu.

# during construction
data("Sonar", package = "mlbench")
task = TaskClassif$new(id = "Sonar", Sonar, target = "Class", positive = "R")

# switch positive class to level 'M'
task$positive = "M"

ROC Curve and Thresholds {#binary-roc}

Phân tích ROC, dựa trên "receiver operating characteristics", là một lĩnh vực nhỏ của ML, nghiên cứu đánh giá hệ thống dự báo nhị phân. Chúng ta đã thấy trước đó là người ta có thể truy xuất ma trận nhầm lẫn (confusion matrix) của một r ref("Prediction") bằng sử dụng trường $confusion:

learner = lrn("classif.rpart", predict_type = "prob")
pred = learner$train(task)$predict(task)
C = pred$confusion
print(C)

Confusion matrix có chứa số lượng các nhãn được gán đúng và sai, nhóm theo các nhãn. Các cột minh họa the true (observed) labels và các dòng hiển thị predicted labels. Giá trị dương (positive) luôn là dòng hoặc cột đầu tiên trong confusion matrix. Vì vậy, phần tử $C_{11}$ là số lần mô hình dự báo đúng positive class. Tương tự, phần tử $C_{22}$ là số lần mô hình dự báo đúng negative class. Hai phần tử trên đường chéo này được gọi là TRUE POSITIVES (TP) và TRUE NEGATIVES (TN). Phần tử $C_{12}$ là số lần dự báo sai positive label và được gọi là FALSE POSITIVES. Phần tử còn lại $C_{21}$ được gọi là FALSE NEGATIVES (FN).

Bây giờ, chúng ta chuẩn hóa các dòng và cột của confusion matrix để rút ra một số informative metrics:

knitr::include_graphics("images/confusion_matrix(wikipedia).png")

Source: Wikipedia

Rất khó để đạt được TPR cao và FPR thấp cùng một lúc, vì vậy, người ta dùng chúng để xây dựng đường cong ROC. Chúng ta mô tả một classifier bằng việc vẽ các giá trị của chúng trên cùng hệ trục tọa độ. Giá trị classifier tốt nhất nằm ở góc trên bên trái. Giá trị classifier kém nhất nằm trên đường chéo.

Những điểm của biểu đồ nằm trên đường chéo là những nhãn ngẫu nhiên (với tỷ lệ khác nhau). Nếu mỗi giá trị dương $x$ được phân loại 1 cách ngẫu nhiên là 25\% dương, chúng ta được TPR là 0.25. Nếu chúng ta gán mỗi giá trị âm $x$ một cách ngẫu nhiên là "dương" chúng ta có được FPR là 0.25. Trong thực tế, chúng ta sẽ không bao giờ có được đường đồ thị nằm dưới đường chéo, vì đảo ngược lại các nhãn dự báo sẽ có được kết quả ngược lại trên đường chéo.

Phân loại chấm điểm (scoring classifier) là một mô hình mà cho ra điểm số hoặc xác suất thay vì các nhãn rời rạc. Gần như tất cả các thuật toán phân loại hiện đại có thể làm được việc đó. Từ ngưỡng theo xác suất sẽ được chuyển đổi thành các nhãn. Dự báo $1$ (positive class) nếu $\hat{f}(x) > \tau$ ngược lại dự báo $0$. Thông thường, người ta sử dụng $\tau = 0.5$ để chuyển đổi xác suất thành các nhãn, nhưng với trường hợp imbalanced hay cost-sensitive ngưỡng có thể thay đổi cho phù hợp. Sau khi chọn ngưỡng, có thể sử dụng bất kỳ thang đo nào để đánh giá performance.

Với mlr3 prediction objects, đường ROC có thể dễ dàng được tạo với r mlr_pkg("mlr3viz") dựa trên r cran_pkg("precrec") để tính toán và plot các đường ROC:

# TPR vs FPR / Sensitivity vs (1 - Specificity)
ggplot2::autoplot(pred, type = "roc")

# Precision vs Recall
ggplot2::autoplot(pred, type = "prc")

Threshold Tuning



nguyenngocbinh/mlr3_book_vi documentation built on Jan. 23, 2020, 12:28 p.m.