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, asería 1 y bsería 30, pero comencemos con algo más simple e intentemos mapear [min,max]en el rango [0,1].
Poner minen 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 maxnos daría max - mincuando 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 ay b, necesitamos algo un poco más complicado:
(b-a)(x - min)
f(x) = -------------- + a
max - min
Puede verificar que poner minpor xahora da ay poner maxda 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 xpor -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 != mincontrario, la función resultará indeterminada :)mines negativo ymaxpositivo, 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
xencuentra en un rango?Supongamos que tiene un rango de
0a100. Dado un número arbitrario de ese rango, ¿en qué "porcentaje" de ese rango se encuentra? Esto debería ser bastante simple,0sería0%,50sería50%y100sería100%.Ahora, lo que si su rango fue
20de100? No podemos aplicar la misma lógica que la anterior (dividir por 100) porque:no nos da
0(20debería ser0%ahora). Esto debería ser simple de solucionar, solo necesitamos hacer el numerador0para el caso de20. Podemos hacer eso restando:Sin embargo, esto ya no funciona
100porque:no nos da
100%. Nuevamente, podemos solucionar esto restando también del denominador:Una ecuación más generalizada para averiguar qué% se
xencuentra 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é porcentaje400está dentro del rango anterior. Podemos aplicar nuestra ecuación anterior.Por lo tanto, se
400encuentra en25%el rango anterior. Solo tenemos que averiguar qué número es25%del nuevo rango. Pensar en lo que50%de[0, 20]es. Estaría10bien? ¿Cómo llegaste a esa respuesta? Bueno, solo podemos hacer:Pero, ¿qué pasa con
[10, 20]? Necesitamos cambiar todo por10ahora. p.ej:una fórmula más generalizada sería:
Para el ejemplo original de lo que
25%de[10, 20]es:Entonces,
400en el rango[200, 1000]se mapearía12.5en el rango[10, 20]TLDR
Para asignar
xdel 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) + aque 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