1
1
# ' Rescale Variables to a New Range
2
2
# '
3
- # ' Rescale variables to a new range.
4
- # ' Can also be used to reverse-score variables (change the keying/scoring direction).
3
+ # ' Rescale variables to a new range. Can also be used to reverse-score variables
4
+ # ' (change the keying/scoring direction), or to expand a range .
5
5
# '
6
6
# ' @inheritParams categorize
7
7
# ' @inheritParams find_columns
8
8
# ' @inheritParams standardize.data.frame
9
9
# '
10
- # ' @param to Numeric vector of length 2 giving the new range that the variable will have after rescaling.
11
- # ' To reverse-score a variable, the range should be given with the maximum value first.
12
- # ' See examples.
10
+ # ' @param to Numeric vector of length 2 giving the new range that the variable
11
+ # ' will have after rescaling. To reverse-score a variable, the range should
12
+ # ' be given with the maximum value first. See examples.
13
+ # ' @param multiply If not `NULL`, `to` is ignored and `multiply` will be used,
14
+ # ' giving the factor by which the actual range of `x` should be expanded.
15
+ # ' For example, if a vector ranges from 5 to 15 and `multiply = 1.1`, the current
16
+ # ' range of 10 will be expanded by the factor of 1.1, giving a new range of
17
+ # ' 11. Thus, the rescaled vector would range from 4.5 to 15.5.
18
+ # ' @param add A vector of length 1 or 2. If not `NULL`, `to` is ignored and `add`
19
+ # ' will be used, giving the amount by which the minimum and maximum of the
20
+ # ' actual range of `x` should be expanded. For example, if a vector ranges from
21
+ # ' 5 to 15 and `add = 1`, the range will be expanded from 4 to 16. If `add` is
22
+ # ' of length 2, then the first value is used for the lower bound and the second
23
+ # ' value for the upper bound.
13
24
# ' @param range Initial (old) range of values. If `NULL`, will take the range of
14
25
# ' the input vector (`range(x)`).
15
26
# ' @param ... Arguments passed to or from other methods.
37
48
# ' "Sepal.Length" = c(0, 1),
38
49
# ' "Petal.Length" = c(-1, 0)
39
50
# ' )))
51
+ # '
52
+ # ' # "expand" ranges by a factor or a given value
53
+ # ' x <- 5:15
54
+ # ' x
55
+ # ' # both will expand the range by 10%
56
+ # ' rescale(x, multiply = 1.1)
57
+ # ' rescale(x, add = 0.5)
58
+ # '
59
+ # ' # expand range by different values
60
+ # ' rescale(x, add = c(1, 3))
61
+ # '
62
+ # ' # Specify list of multipliers
63
+ # ' d <- data.frame(x = 5:15, y = 5:15)
64
+ # ' rescale(d, multiply = list(x = 1.1, y = 0.5))
65
+ # '
40
66
# ' @inherit data_rename
41
67
# '
42
68
# ' @return A rescaled object.
@@ -75,6 +101,8 @@ rescale.default <- function(x, verbose = TRUE, ...) {
75
101
# ' @export
76
102
rescale.numeric <- function (x ,
77
103
to = c(0 , 100 ),
104
+ multiply = NULL ,
105
+ add = NULL ,
78
106
range = NULL ,
79
107
verbose = TRUE ,
80
108
... ) {
@@ -91,6 +119,9 @@ rescale.numeric <- function(x,
91
119
range <- c(min(x , na.rm = TRUE ), max(x , na.rm = TRUE ))
92
120
}
93
121
122
+ # check if user specified "multiply" or "add", and then update "to"
123
+ to <- .update_to(x , to , multiply , add )
124
+
94
125
# called from "makepredictcal()"? Then we have additional arguments
95
126
dot_args <- list (... )
96
127
required_dot_args <- c(" min_value" , " max_value" , " new_min" , " new_max" )
@@ -144,6 +175,8 @@ rescale.grouped_df <- function(x,
144
175
select = NULL ,
145
176
exclude = NULL ,
146
177
to = c(0 , 100 ),
178
+ multiply = NULL ,
179
+ add = NULL ,
147
180
range = NULL ,
148
181
append = FALSE ,
149
182
ignore_case = FALSE ,
@@ -188,6 +221,8 @@ rescale.grouped_df <- function(x,
188
221
select = select ,
189
222
exclude = exclude ,
190
223
to = to ,
224
+ multiply = multiply ,
225
+ add = add ,
191
226
range = range ,
192
227
append = FALSE , # need to set to FALSE here, else variable will be doubled
193
228
add_transform_class = FALSE ,
@@ -207,6 +242,8 @@ rescale.data.frame <- function(x,
207
242
select = NULL ,
208
243
exclude = NULL ,
209
244
to = c(0 , 100 ),
245
+ multiply = NULL ,
246
+ add = NULL ,
210
247
range = NULL ,
211
248
append = FALSE ,
212
249
ignore_case = FALSE ,
@@ -245,9 +282,61 @@ rescale.data.frame <- function(x,
245
282
if (! is.list(to )) {
246
283
to <- stats :: setNames(rep(list (to ), length(select )), select )
247
284
}
285
+ # Transform the 'multiply' so that it is a list now
286
+ if (! is.null(multiply ) && ! is.list(multiply )) {
287
+ multiply <- stats :: setNames(rep(list (multiply ), length(select )), select )
288
+ }
289
+ # Transform the 'add' so that it is a list now
290
+ if (! is.null(add ) && ! is.list(add )) {
291
+ add <- stats :: setNames(rep(list (add ), length(select )), select )
292
+ }
293
+ # update "to" if user specified "multiply" or "add"
294
+ to [] <- lapply(names(to ), function (i ) {
295
+ .update_to(x [[i ]], to [[i ]], multiply [[i ]], add [[i ]])
296
+ })
248
297
249
298
x [select ] <- as.data.frame(sapply(select , function (n ) {
250
299
rescale(x [[n ]], to = to [[n ]], range = range [[n ]], add_transform_class = FALSE )
251
300
}, simplify = FALSE ))
252
301
x
253
302
}
303
+
304
+
305
+ # helper ----------------------------------------------------------------------
306
+
307
+ # expand the new target range by multiplying or adding
308
+ .update_to <- function (x , to , multiply , add ) {
309
+ # check if user specified "multiply" or "add", and if not, return "to"
310
+ if (is.null(multiply ) && is.null(add )) {
311
+ return (to )
312
+ }
313
+ # only one of "multiply" or "add" can be specified
314
+ if (! is.null(multiply ) && ! is.null(add )) {
315
+ insight :: format_error(" Only one of `multiply` or `add` can be specified." )
316
+ }
317
+ # multiply? If yes, calculate the "add" value
318
+ if (! is.null(multiply )) {
319
+ # check for correct length
320
+ if (length(multiply ) > 1 ) {
321
+ insight :: format_error(" The length of `multiply` must be 1." )
322
+ }
323
+ add <- (diff(range(x , na.rm = TRUE )) * (multiply - 1 )) / 2
324
+ }
325
+ # add?
326
+ if (! is.null(add )) {
327
+ # add must be of length 1 or 2
328
+ if (length(add ) > 2 ) {
329
+ insight :: format_error(" The length of `add` must be 1 or 2." )
330
+ }
331
+ # if add is of length 2, then the first value is used for the lower bound
332
+ # and the second value for the upper bound
333
+ if (length(add ) == 2 ) {
334
+ add_low <- add [1 ]
335
+ add_high <- add [2 ]
336
+ } else {
337
+ add_low <- add_high <- add
338
+ }
339
+ to <- c(min(x , na.rm = TRUE ) - add_low , max(x , na.rm = TRUE ) + add_high )
340
+ }
341
+ to
342
+ }
0 commit comments