Digamos que desea escalar un rango [min,max]
a [a,b]
. Estás buscando una función (continua) que satisfaga
f(min) = a
f(max) = b
En su caso, a
sería 1 y b
sería 30, pero comencemos con algo más simple e intentemos mapear [min,max]
en el rango [0,1]
.
Poner min
en una función y sacar 0 podría lograrse con
f(x) = x - min ===> f(min) = min - min = 0
Entonces eso es casi lo que queremos. Pero ponerlo max
nos daría max - min
cuando realmente queremos 1. Así que tendremos que escalarlo:
x - min max - min
f(x) = --------- ===> f(min) = 0; f(max) = --------- = 1
max - min max - min
que es lo que queremos Entonces necesitamos hacer una traducción y una escala. Ahora, si en cambio queremos obtener valores arbitrarios de a
y b
, necesitamos algo un poco más complicado:
(b-a)(x - min)
f(x) = -------------- + a
max - min
Puede verificar que poner min
por x
ahora da a
y poner max
da b
.
También puede notar que (b-a)/(max-min)
es un factor de escala entre el tamaño del nuevo rango y el tamaño del rango original. Así que en realidad estamos traduciendo primero x
por -min
, su reducción al factor correcta, y luego traducirlo una copia de seguridad al nuevo valor mínimo de a
.
Espero que esto ayude.
max != min
contrario, la función resultará indeterminada :)min
es negativo ymax
positivo, o ambos tienen que ser positivos?Aquí hay algunos JavaScript para copiar y pegar fácilmente (esta es la respuesta de irritar):
Aplicado así, escalando el rango 10-50 a un rango entre 0-100.
Editar:
Sé que respondí esto hace mucho tiempo, pero aquí hay una función más limpia que uso ahora:
Aplicado así:
fuente
[1, 1, 1]
,[100, 100, 100]
o incluso[50.5, 50.5, 50.5]
. Podría poner en el caso:if (max-min == 0) return this.map(num => (scaledMin+scaledMax)/2);
Por conveniencia, aquí está el algoritmo de Irritate en forma de Java. Agregue verificación de errores, manejo de excepciones y ajustes según sea necesario.
Ensayador:
fuente
Así es como lo entiendo:
¿Qué porcentaje se
x
encuentra en un rango?Supongamos que tiene un rango de
0
a100
. Dado un número arbitrario de ese rango, ¿en qué "porcentaje" de ese rango se encuentra? Esto debería ser bastante simple,0
sería0%
,50
sería50%
y100
sería100%
.Ahora, lo que si su rango fue
20
de100
? No podemos aplicar la misma lógica que la anterior (dividir por 100) porque:no nos da
0
(20
debería ser0%
ahora). Esto debería ser simple de solucionar, solo necesitamos hacer el numerador0
para el caso de20
. Podemos hacer eso restando:Sin embargo, esto ya no funciona
100
porque:no nos da
100%
. Nuevamente, podemos solucionar esto restando también del denominador:Una ecuación más generalizada para averiguar qué% se
x
encuentra en un rango sería:Rango de escala a otro rango
Ahora que sabemos qué porcentaje de un número se encuentra en un rango, podemos aplicarlo para asignar el número a otro rango. Veamos un ejemplo.
Si tenemos un número en el rango anterior, ¿cuál sería el número en el nuevo rango? Digamos que el número es
400
. Primero, calcule qué porcentaje400
está dentro del rango anterior. Podemos aplicar nuestra ecuación anterior.Por lo tanto, se
400
encuentra en25%
el rango anterior. Solo tenemos que averiguar qué número es25%
del nuevo rango. Pensar en lo que50%
de[0, 20]
es. Estaría10
bien? ¿Cómo llegaste a esa respuesta? Bueno, solo podemos hacer:Pero, ¿qué pasa con
[10, 20]
? Necesitamos cambiar todo por10
ahora. p.ej:una fórmula más generalizada sería:
Para el ejemplo original de lo que
25%
de[10, 20]
es:Entonces,
400
en el rango[200, 1000]
se mapearía12.5
en el rango[10, 20]
TLDR
Para asignar
x
del rango antiguo al nuevo rango:fuente
Encontré esta solución, pero esto realmente no se ajusta a mi necesidad. Así que busqué un poco en el código fuente d3. Yo personalmente recomendaría hacerlo como lo hace d3.scale.
Entonces aquí escalas el dominio al rango. La ventaja es que puede voltear las señales a su rango objetivo. Esto es útil ya que el eje y en la pantalla de una computadora va de arriba hacia abajo, por lo que los valores grandes tienen una y pequeña.
Y aquí está la prueba donde puedes ver a qué me refiero
fuente
Tomé la respuesta de Irritate y la refactoré para minimizar los pasos computacionales para cálculos posteriores factorizándola en la menor cantidad de constantes. La motivación es permitir que un escalador se entrene en un conjunto de datos y luego se ejecute en nuevos datos (para un algoritmo ML). En efecto, es muy similar al preprocesamiento de MinMaxScaler para Python en uso.
Por lo tanto,
x' = (b-a)(x-min)/(max-min) + a
(donde b! = A) se convierte en lox' = x(b-a)/(max-min) + min(-b+a)/(max-min) + a
que se puede reducir a dos constantes en la formax' = x*Part1 + Part2
.Aquí hay una implementación de C # con dos constructores: uno para entrenar y otro para recargar una instancia entrenada (por ejemplo, para soportar la persistencia).
fuente
Basado en la respuesta de Charles Clayton, incluí algunos ajustes de JSDoc, ES6 e incorporé sugerencias de los comentarios en la respuesta original.
fuente