utils.R 7.84 KB
Newer Older
1
2
3
lgb.is.Booster <- function(x) {
  lgb.check.r6.class(x, "lgb.Booster") # Checking if it is of class lgb.Booster or not
}
4

5
6
7
lgb.is.Dataset <- function(x) {
  lgb.check.r6.class(x, "lgb.Dataset") # Checking if it is of class lgb.Dataset or not
}
8

Guolin Ke's avatar
Guolin Ke committed
9
10
11
12
13
14
15
16
lgb.null.handle <- function() {
  if (.Machine$sizeof.pointer == 8L) {
    return(NA_real_)
  } else {
    return(NA_integer_)
  }
}

17
lgb.is.null.handle <- function(x) {
18
  is.null(x) || is.na(x)
19
}
Guolin Ke's avatar
Guolin Ke committed
20
21

lgb.encode.char <- function(arr, len) {
22
  if (!is.raw(arr)) {
23
    stop("lgb.encode.char: Can only encode from raw type")
Guolin Ke's avatar
Guolin Ke committed
24
  }
25
  return(rawToChar(arr[seq_len(len)]))
Guolin Ke's avatar
Guolin Ke committed
26
27
}

28
29
# [description] Raise an error. Before raising that error, check for any error message
#               stored in a buffer on the C++ side.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
lgb.last_error <- function() {
  # Perform text error buffering
  buf_len <- 200L
  act_len <- 0L
  err_msg <- raw(buf_len)
  err_msg <- .Call(
    "LGBM_GetLastError_R"
    , buf_len
    , act_len
    , err_msg
    , PACKAGE = "lib_lightgbm"
  )

  # Check error buffer
  if (act_len > buf_len) {
    buf_len <- act_len
    err_msg <- raw(buf_len)
    err_msg <- .Call(
      "LGBM_GetLastError_R"
      , buf_len
      , act_len
      , err_msg
      , PACKAGE = "lib_lightgbm"
    )
  }

  # Return error
  stop("api error: ", lgb.encode.char(err_msg, act_len))
}

Guolin Ke's avatar
Guolin Ke committed
60
lgb.call <- function(fun_name, ret, ...) {
61
  # Set call state to a zero value
62
  call_state <- 0L
63

64
  # Check for a ret call
Guolin Ke's avatar
Guolin Ke committed
65
  if (!is.null(ret)) {
66
67
68
69
70
71
72
    call_state <- .Call(
      fun_name
      , ...
      , ret
      , call_state
      , PACKAGE = "lib_lightgbm"
    )
Guolin Ke's avatar
Guolin Ke committed
73
  } else {
74
75
76
77
78
79
    call_state <- .Call(
      fun_name
      , ...
      , call_state
      , PACKAGE = "lib_lightgbm"
    )
Guolin Ke's avatar
Guolin Ke committed
80
  }
Guolin Ke's avatar
Guolin Ke committed
81
  call_state <- as.integer(call_state)
82
  # Check for call state value post call
83
  if (call_state != 0L) {
84
    lgb.last_error()
Guolin Ke's avatar
Guolin Ke committed
85
  }
Guolin Ke's avatar
Guolin Ke committed
86

87
  return(ret)
88

Guolin Ke's avatar
Guolin Ke committed
89
90
91
}

lgb.call.return.str <- function(fun_name, ...) {
92

93
  # Create buffer
94
  buf_len <- as.integer(1024L * 1024L)
95
  act_len <- 0L
Guolin Ke's avatar
Guolin Ke committed
96
  buf <- raw(buf_len)
97

98
  # Call buffer
Guolin Ke's avatar
Guolin Ke committed
99
  buf <- lgb.call(fun_name, ret = buf, ..., buf_len, act_len)
100

101
  # Check for buffer content
Guolin Ke's avatar
Guolin Ke committed
102
103
  if (act_len > buf_len) {
    buf_len <- act_len
104
105
    buf <- raw(buf_len)
    buf <- lgb.call(fun_name, ret = buf, ..., buf_len, act_len)
Guolin Ke's avatar
Guolin Ke committed
106
  }
107

108
109
  # Return encoded character
  return(lgb.encode.char(buf, act_len))
110

Guolin Ke's avatar
Guolin Ke committed
111
112
113
}

lgb.params2str <- function(params, ...) {
114

115
  # Check for a list as input
116
  if (!identical(class(params), "list")) {
117
118
    stop("params must be a list")
  }
119

120
  # Split parameter names
Guolin Ke's avatar
Guolin Ke committed
121
  names(params) <- gsub("\\.", "_", names(params))
122

123
  # Merge parameters from the params and the dots-expansion
Guolin Ke's avatar
Guolin Ke committed
124
125
  dot_params <- list(...)
  names(dot_params) <- gsub("\\.", "_", names(dot_params))
126

127
  # Check for identical parameters
128
  if (length(intersect(names(params), names(dot_params))) > 0L) {
129
130
131
132
133
134
135
    stop(
      "Same parameters in "
      , sQuote("params")
      , " and in the call are not allowed. Please check your "
      , sQuote("params")
      , " list"
    )
136
  }
137

138
  # Merge parameters
Guolin Ke's avatar
Guolin Ke committed
139
  params <- c(params, dot_params)
140

141
142
  # Setup temporary variable
  ret <- list()
143

144
  # Perform key value join
Guolin Ke's avatar
Guolin Ke committed
145
  for (key in names(params)) {
146

147
148
149
150
151
152
153
154
155
156
157
    # If a parameter has multiple values, join those values together with commas.
    # trimws() is necessary because format() will pad to make strings the same width
    val <- paste0(
      trimws(
        format(
          x = params[[key]]
          , scientific = FALSE
        )
      )
      , collapse = ","
    )
158
    if (nchar(val) <= 0L) next # Skip join
159

160
    # Join key value
Guolin Ke's avatar
Guolin Ke committed
161
    pair <- paste0(c(key, val), collapse = "=")
162
    ret <- c(ret, pair)
163

Guolin Ke's avatar
Guolin Ke committed
164
  }
165

166
  # Check ret length
167
  if (length(ret) == 0L) {
168
    return(lgb.c_str(""))
Guolin Ke's avatar
Guolin Ke committed
169
  }
170

171
172
173
  # Return string separated by a space per element
  return(lgb.c_str(paste0(ret, collapse = " ")))

Guolin Ke's avatar
Guolin Ke committed
174
175
}

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
lgb.check_interaction_constraints <- function(params, column_names) {

  # Convert interaction constraints to feature numbers
  string_constraints <- list()

  if (!is.null(params[["interaction_constraints"]])) {

    # validation
    if (!methods::is(params[["interaction_constraints"]], "list")) {
        stop("interaction_constraints must be a list")
    }
    if (!all(sapply(params[["interaction_constraints"]], function(x) {is.character(x) || is.numeric(x)}))) {
        stop("every element in interaction_constraints must be a character vector or numeric vector")
    }

    for (constraint in params[["interaction_constraints"]]) {

      # Check for character name
      if (is.character(constraint)) {

          constraint_indices <- as.integer(match(constraint, column_names) - 1L)

          # Provided indices, but some indices are not existing?
          if (sum(is.na(constraint_indices)) > 0L) {
            stop(
              "supplied an unknown feature in interaction_constraints "
              , sQuote(constraint[is.na(constraint_indices)])
            )
          }

        } else {

          # Check that constraint indices are at most number of features
          if (max(constraint) > length(column_names)) {
            stop(
              "supplied a too large value in interaction_constraints: "
              , max(constraint)
              , " but only "
              , length(column_names)
              , " features"
            )
          }

          # Store indices as [0, n-1] indexed instead of [1, n] indexed
          constraint_indices <- as.integer(constraint - 1L)

        }

        # Convert constraint to string
        constraint_string <- paste0("[", paste0(constraint_indices, collapse = ","), "]")
        string_constraints <- append(string_constraints, constraint_string)
    }

  }

  return(string_constraints)

}

Guolin Ke's avatar
Guolin Ke committed
235
lgb.c_str <- function(x) {
236

237
  # Perform character to raw conversion
Guolin Ke's avatar
Guolin Ke committed
238
  ret <- charToRaw(as.character(x))
239
  ret <- c(ret, as.raw(0L))
240
  ret
241

Guolin Ke's avatar
Guolin Ke committed
242
243
244
}

lgb.check.r6.class <- function(object, name) {
245

246
247
  # Check for non-existence of R6 class or named class
  all(c("R6", name) %in% class(object))
248

Guolin Ke's avatar
Guolin Ke committed
249
250
251
}

lgb.check.obj <- function(params, obj) {
252

253
  # List known objectives in a vector
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  OBJECTIVES <- c(
    "regression"
    , "regression_l1"
    , "regression_l2"
    , "mean_squared_error"
    , "mse"
    , "l2_root"
    , "root_mean_squared_error"
    , "rmse"
    , "mean_absolute_error"
    , "mae"
    , "quantile"
    , "huber"
    , "fair"
    , "poisson"
    , "binary"
    , "lambdarank"
    , "multiclass"
    , "softmax"
    , "multiclassova"
    , "multiclass_ova"
    , "ova"
    , "ovr"
    , "xentropy"
    , "cross_entropy"
    , "xentlambda"
    , "cross_entropy_lambda"
    , "mean_absolute_percentage_error"
    , "mape"
    , "gamma"
    , "tweedie"
285
286
287
288
289
    , "rank_xendcg"
    , "xendcg"
    , "xe_ndcg"
    , "xe_ndcg_mart"
    , "xendcg_mart"
290
  )
291

292
  # Check whether the objective is empty or not, and take it from params if needed
293
294
295
  if (!is.null(obj)) {
    params$objective <- obj
  }
296

297
  # Check whether the objective is a character
298
  if (is.character(params$objective)) {
299

300
    # If the objective is a character, check if it is a known objective
301
    if (!(params$objective %in% OBJECTIVES)) {
302

303
      # Interrupt on unknown objective name
304
      stop("lgb.check.obj: objective name error should be one of (", paste0(OBJECTIVES, collapse = ", "), ")")
305

Guolin Ke's avatar
Guolin Ke committed
306
    }
307

308
  } else if (!is.function(params$objective)) {
309

310
    # If objective is not a character nor a function, then stop
311
    stop("lgb.check.obj: objective should be a character or a function")
312

Guolin Ke's avatar
Guolin Ke committed
313
  }
314

315
316
  # Return parameters
  return(params)
317

Guolin Ke's avatar
Guolin Ke committed
318
319
}

320
321
# [description]
#     make sure that "metric" is populated on params,
322
#     and add any eval values to it
323
324
# [return]
#     params, where "metric" is a list
Guolin Ke's avatar
Guolin Ke committed
325
lgb.check.eval <- function(params, eval) {
326

327
328
  if (is.null(params$metric)) {
    params$metric <- list()
329
330
  } else if (is.character(params$metric)) {
    params$metric <- as.list(params$metric)
331
  }
332

333
  if (is.character(eval)) {
334
    params$metric <- append(params$metric, eval)
335
  }
336

337
338
339
340
  if (identical(class(eval), "list")) {
    params$metric <- append(params$metric, unlist(eval))
  }

341
  return(params)
Guolin Ke's avatar
Guolin Ke committed
342
}