lgb.prepare2.R 3.9 KB
Newer Older
Laurae's avatar
Laurae committed
1
2
3
4
5
6
7
8
9
10
#' Data preparator for LightGBM datasets (integer)
#'
#' Attempts to prepare a clean dataset to prepare to put in a lgb.Dataset. Factors and characters are converted to numeric (specifically: integer). Please use \code{lgb.prepare_rules2} if you want to apply this transformation to other datasets. This is useful if you have a specific need for integer dataset instead of numeric dataset. Note that there are programs which do not support integer-only input. Consider this as a half memory technique which is dangerous, especially for LightGBM.
#' 
#' @param data A data.frame or data.table to prepare.
#' 
#' @return The cleaned dataset. It must be converted to a matrix format (\code{as.matrix}) for input in lgb.Dataset.
#' 
#' @examples
#' \dontrun{
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#' library(lightgbm)
#' data(iris)
#' 
#' str(iris)
#' # 'data.frame':	150 obs. of  5 variables:
#' # $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#' # $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#' # $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#' # $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#' # $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 ...
#' 
#' str(lgb.prepare2(data = iris)) # Convert all factors/chars to integer
#' # 'data.frame':	150 obs. of  5 variables:
#' # $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#' # $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#' # $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#' # $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#' # $ Species     : int  1 1 1 1 1 1 1 1 1 1 ...
#' 
#' # When lightgbm package is installed, and you do not want to load it
#' # You can still use the function!
#' lgb.unloader()
#' str(lightgbm::lgb.prepare2(data = iris))
#' # 'data.frame':	150 obs. of  5 variables:
#' # $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#' # $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#' # $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#' # $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#' # $ Species     : int  1 1 1 1 1 1 1 1 1 1 ...
#' 
Laurae's avatar
Laurae committed
41
42
43
44
45
46
#' }
#' 
#' @export
lgb.prepare2 <- function(data) {
  
  # data.table not behaving like data.frame
47
  if (inherits(data, "data.table")) {
Laurae's avatar
Laurae committed
48
49
    
    # Get data classes
50
    list_classes <- vapply(data, class, character(1))
Laurae's avatar
Laurae committed
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
    
    # Convert characters to factors only (we can change them to numeric after)
    is_char <- which(list_classes == "character")
    if (length(is_char) > 0) {
      data[, (is_char) := lapply(.SD, function(x) {as.integer(as.factor(x))}), .SDcols = is_char]
    }
    
    # Convert factors to numeric (integer is more efficient actually)
    is_fact <- c(which(list_classes == "factor"), is_char)
    if (length(is_fact) > 0) {
      data[, (is_fact) := lapply(.SD, function(x) {as.integer(x)}), .SDcols = is_fact]
    }
    
  } else {
    
    # Default routine (data.frame)
67
    if (inherits(data, "data.frame")) {
Laurae's avatar
Laurae committed
68
69
      
      # Get data classes
70
      list_classes <- vapply(data, class, character(1))
Laurae's avatar
Laurae committed
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
      
      # Convert characters to factors to numeric (integer is more efficient actually)
      is_char <- which(list_classes == "character")
      if (length(is_char) > 0) {
        data[is_char] <- lapply(data[is_char], function(x) {as.integer(as.factor(x))})
      }
      
      # Convert factors to numeric (integer is more efficient actually)
      is_fact <- which(list_classes == "factor")
      if (length(is_fact) > 0) {
        data[is_fact] <- lapply(data[is_fact], function(x) {as.integer(x)})
      }
      
    } else {
      
      # What do you think you are doing here? Throw error.
      stop("lgb.prepare: you provided ", paste(class(data), collapse = " & "), " but data should have class data.frame")
      
    }
    
  }
  
  return(data)
  
}