#529 Task converters

Merged Michel Lang mllg Pseudo commit used to compare (e48d36e...29090a4)
Missing base report.

Unable to compare commits because the base of the pull request did not upload a coverage report.

Changes found in between e48d36e...29090a4 (pseudo...base) which prevent comparing this pull request.

Showing 5 of 15 files from the diff.
Newly tracked file
R/TaskClassif.R changed.
Newly tracked file
R/TaskRegr.R changed.
Newly tracked file
R/TaskSupervised.R changed.
Newly tracked file
R/Task.R changed.
Newly tracked file
R/task_converters.R created.

@@ -46,13 +46,17 @@
Loading
46 46
    #'   Only for binary classification: Name of the positive class.
47 47
    #'   The levels of the target columns are reordered accordingly, so that the first element of `$class_names` is the
48 48
    #'   positive class, and the second element is the negative class.
49 -
    initialize = function(id, backend, target, positive = NULL) {
49 +
    #' @template param_extra_args
50 +
    initialize = function(id, backend, target, positive = NULL, extra_args = list()) {
50 51
      assert_string(target)
51 -
      super$initialize(id = id, task_type = "classif", backend = backend, target = target)
52 +
      super$initialize(
53 +
        id = id, task_type = "classif", backend = backend,
54 +
        target = target, extra_args = extra_args)
52 55
53 56
      private$.update_class_property()
54 57
55 58
      if (!is.null(positive)) {
59 +
        # NB: this also sets `extra_args$positive`
56 60
        self$positive = positive
57 61
      }
58 62
    },
@@ -117,6 +121,7 @@
Loading
117 121
      }
118 122
      positive = assert_choice(rhs, lvls)
119 123
      negative = setdiff(lvls, rhs)
124 +
      self$extra_args$positive = positive
120 125
      self$col_info[list(self$target_names), levels := list(list(c(positive, negative))), on = "id"][]
121 126
    },
122 127

@@ -31,9 +31,12 @@
Loading
31 31
    #'
32 32
    #' @param target (`character(1)`)\cr
33 33
    #'   Name of the target column.
34 -
    initialize = function(id, backend, target) {
34 +
    #' @template param_extra_args
35 +
    initialize = function(id, backend, target, extra_args = list()) {
35 36
      assert_string(target)
36 -
      super$initialize(id = id, task_type = "regr", backend = backend, target = target)
37 +
      super$initialize(
38 +
        id = id, task_type = "regr", backend = backend,
39 +
        target = target, extra_args = extra_args)
37 40
38 41
      type = self$col_info[id == target]$type
39 42
      if (type %nin% c("integer", "numeric")) {

@@ -10,6 +10,7 @@
Loading
10 10
#' @template param_task_type
11 11
#' @template param_backend
12 12
#' @template param_rows
13 +
#' @template param_extra_args
13 14
#'
14 15
#' @family Task
15 16
#' @keywords internal
@@ -24,8 +25,8 @@
Loading
24 25
    #'
25 26
    #' @param target (`character(1)`)\cr
26 27
    #'   Name of the target column.
27 -
    initialize = function(id, task_type, backend, target) {
28 -
      super$initialize(id = id, task_type = task_type, backend = backend)
28 +
    initialize = function(id, task_type, backend, target, extra_args = list()) {
29 +
      super$initialize(id = id, task_type = task_type, backend = backend, extra_args = extra_args)
29 30
      assert_subset(target, self$col_roles$feature)
30 31
      self$col_roles$target = target
31 32
      self$col_roles$feature = setdiff(self$col_roles$feature, target)

@@ -20,6 +20,7 @@
Loading
20 20
#' @template param_rows
21 21
#' @template param_cols
22 22
#' @template param_data_format
23 +
#' @template param_extra_args
23 24
#'
24 25
#' @section S3 methods:
25 26
#' * `as.data.table(t)`\cr
@@ -80,11 +81,16 @@
Loading
80 81
    #' @template field_man
81 82
    man = NA_character_,
82 83
84 +
    #' @field extra_args (named `list()`)\cr
85 +
    #' Additional arguments set during construction.
86 +
    #' Required for [convert_task()].
87 +
    extra_args = NULL,
88 +
83 89
    #' @description
84 90
    #' Creates a new instance of this [R6][R6::R6Class] class.
85 91
    #'
86 92
    #' Note that this object is typically constructed via a derived classes, e.g. [TaskClassif] or [TaskRegr].
87 -
    initialize = function(id, task_type, backend) {
93 +
    initialize = function(id, task_type, backend, extra_args = list()) {
88 94
      self$id = assert_string(id, min.chars = 1L)
89 95
      self$task_type = assert_choice(task_type, mlr_reflections$task_types$type)
90 96
      if (!inherits(backend, "DataBackend")) {
@@ -108,6 +114,7 @@
Loading
108 114
      private$.row_roles = list(use = rn, validation = integer())
109 115
      private$.col_roles = named_list(mlr_reflections$task_col_roles[[task_type]], character())
110 116
      private$.col_roles$feature = setdiff(cn, self$backend$primary_key)
117 +
      self$extra_args = assert_list(extra_args, names = "unique")
111 118
    },
112 119
113 120
    #' @description

@@ -0,0 +1,100 @@
Loading
1 +
#' Convert a Task from One Type to Another
2 +
#'
3 +
#' @description
4 +
#' The task's target is replaced by a different column from the data.
5 +
#'
6 +
#' @param intask ([Task])\cr
7 +
#'   A [Task] to be converted.
8 +
#' @param target (`character(1)`)\cr
9 +
#'   New target to be set, must be a column in the `intask` data.
10 +
#'   If `NULL`, no new target is set, and task is converted as-is.
11 +
#' @param new_type (`character(1)`)\cr
12 +
#'   The new task type. Must be in [`mlr_reflections$task_types`][mlr_reflections]].
13 +
#'   If `NULL` (default), a new task with the same task_type is created.
14 +
#' @param drop_original_target (`logical(1)`)\cr
15 +
#'   If `FALSE` (default), the original target is added as a feature.
16 +
#'   Otherwise the original target is dropped.
17 +
#' @param drop_levels (`logical(1)`)\cr
18 +
#'   If `TRUE` (default), unused levels of the new target variable are dropped.
19 +
#'
20 +
#' @return [Task] of requested type.
21 +
#' @export
22 +
convert_task = function(intask, target = NULL, new_type = NULL, drop_original_target = FALSE, drop_levels = TRUE) {
23 +
  assert_task(intask)
24 +
  target = assert_subset(target, choices = intask$col_info$id) %??% intask$target_names
25 +
  new_type = assert_choice(new_type, choices = mlr_reflections$task_types$type, null.ok = TRUE) %??% intask$task_type
26 +
  assert_logical(drop_original_target, any.missing = FALSE, len = 1L)
27 +
28 +
  # get task_type from mlr_reflections and call constructor
29 +
  constructor = get(mlr_reflections$task_types[list(new_type), "task", on = "type"][[1L]])
30 +
  common_args = intersect(names(intask$extra_args), names(formals(constructor$public_methods$initialize)))
31 +
  newtask = invoke(constructor$new, id = intask$id, backend = intask$backend, target = target, .args = intask$extra_args[common_args])
32 +
  newtask$extra_args = intask$extra_args
33 +
34 +
  # copy row_roles / col_roles / properties
35 +
  newtask$row_roles = intask$row_roles
36 +
  props = intersect(mlr_reflections$task_col_roles[[intask$task_type]], mlr_reflections$task_col_roles[[new_type]])
37 +
  newtask$col_roles[props] = intask$col_roles[props]
38 +
  newtask$set_col_role(target, "target")
39 +
40 +
  # Add the original target(s) as features, only keeping 'new_target'.
41 +
  if (!all(intask$target_names == target)) {
42 +
    newtask$set_col_role(setdiff(intask$col_roles$target, target),  "feature")
43 +
  }
44 +
45 +
  # during prediction, when target is NA, we do not call droplevels
46 +
  if (assert_flag(drop_levels)) {
47 +
    newtask$droplevels()
48 +
  }
49 +
50 +
  # if drop_original_target, remove the original target from the features
51 +
  if (drop_original_target) {
52 +
    newtask$col_roles$feature = setdiff(newtask$col_roles$feature, intask$col_roles$target)
53 +
  }
54 +
55 +
  newtask
56 +
}
57 +
58 +
#' @rdname convert_task
59 +
#' @param x (`any`)\cr
60 +
#'   Object to convert.
61 +
#' @param ... (`any`)\cr
62 +
#'   Additional arguments, currently ignored.
63 +
#' @export
64 +
as_task_classif = function(x, target = NULL, ...) {
65 +
  UseMethod("as_task_classif")
66 +
}
67 +
68 +
#' @rdname convert_task
69 +
#' @export
70 +
as_task_classif.TaskRegr = function(x, target = NULL, drop_original_target = FALSE, drop_levels = TRUE, ...) {
71 +
  convert_task(intask = x, target = target, new_type = "classif", drop_original_target = FALSE, drop_levels = TRUE)
72 +
}
73 +
74 +
#' @rdname convert_task
75 +
#' @param id (`character(1)`)\cr
76 +
#'   Id for the new task.
77 +
#' @param positive (`character(1)`)\cr
78 +
#'   Level of the positive class. See [TaskClassif].
79 +
#' @export
80 +
as_task_classif.data.frame = function(x, target = NULL, id = deparse(substitute(x)), positive = NULL, ...) {
81 +
  TaskClassif$new(id = id, backend = x, target = target, positive = positive)
82 +
}
83 +
84 +
#' @rdname convert_task
85 +
#' @export
86 +
as_task_regr = function(x, target = NULL, ...) {
87 +
  UseMethod("as_task_regr")
88 +
}
89 +
90 +
#' @export
91 +
#' @rdname convert_task
92 +
as_task_regr.TaskClassif = function(x, target = NULL, drop_original_target = FALSE, drop_levels = TRUE, ...) {
93 +
  convert_task(intask = x, target = target, new_type = "regr", drop_original_target = FALSE, drop_levels = TRUE)
94 +
}
95 +
96 +
#' @export
97 +
#' @rdname convert_task
98 +
as_task_regr.data.frame = function(x, target = NULL, id = deparse(substitute(x)), positive = NULL, ...) {
99 +
  TaskRegr$new(id = id, backend = x, target = target)
100 +
}

Unable to process changes.

No base report to compare against.

Files Coverage
R 92.14%
Project Totals (83 files) 92.14%
Loading