I want to create a function for "optimum is better" relationship as shown in the following figure
I could able to create a function for "more is better" and "less is better" like
normalize <- function(x, na.rm=na.rm, relation=relation) {
if (relation == "More is better") {
normalize <- ((x - min(x, na.rm=na.rm))/
(max(x, na.rm=na.rm) - min(x, na.rm=na.rm)))
} else {
normalize <- 1 - ((x - min(x, na.rm=na.rm))/
(max(x, na.rm=na.rm) - min(x, na.rm=na.rm)))
}
return(normalize)
}
Here is a small data
set.seed(123)
value <- runif(50, min=3, max=8.5)
The "optimum is better" should take "more is better" up to a range or point (e.g. 6.5-7.5 for current data), in the optimum range the normalised value should be 1 and beyond the range or point it should be calculated as "less is better". How can I achieve this in R?
CodePudding user response:
Actually you could just transform the subsets.
FUN <- function(x, lower, upper, ...) {
normalize <- function(x, ...) (x - min(x, ...))/(max(x, ...) - min(x, ...))
x[x < lower] <- normalize(x[x < lower], ...)
x[x > upper] <- 1 - normalize(x[x > upper], ...)
x[x >= lower & x <= upper] <- 1
return(x)
}
lower <- 6.5; upper <- 7.5
value.star <- FUN(value, lower, upper, na.rm=TRUE)
plot(value, value.star, pch=20)
abline(v=c(lower, upper), lty=2)
Data
set.seed(123)
value <- runif(2.5e2, min=3, max=8.5)
CodePudding user response:
This function normalizes value
in such a way that its output is always between 0 and 1. It returns exactly 1, iff the value is in the optimum range [a,b]. It returns a min max scaling iff value < a ("higher is better") and 1 - min-max-scaling it is larger than b ("lower is better")
library(tidyverse)
normalize <- function(value, a = 6.5, b = 7.5) {
min_max_scaled <- (value - min(value)) / max(value)
case_when(
# before the range
value < a ~ min_max_scaled,
# within the range
value >= a & value <= b ~ 1,
# beyoned the range
value > b ~ 1 - min_max_scaled
)
}