Digamos que você queira dimensionar um intervalo [min,max]
para [a,b]
. Você está procurando uma função (contínua) que satisfaça
f(min) = a
f(max) = b
No seu caso, a
seria 1 e b
30, mas vamos começar com algo mais simples e tentar mapear [min,max]
no intervalo [0,1]
.
Colocar min
em uma função e sair 0 pode ser realizado com
f(x) = x - min ===> f(min) = min - min = 0
Então isso é quase o que queremos. Mas colocar nos max
daria max - min
quando realmente queremos 1. Portanto, teremos que escalá-lo:
x - min max - min
f(x) = --------- ===> f(min) = 0; f(max) = --------- = 1
max - min max - min
que é o que queremos. Então, precisamos fazer uma tradução e um dimensionamento. Agora, se queremos obter valores arbitrários de a
e b
, precisamos de algo um pouco mais complicado:
(b-a)(x - min)
f(x) = -------------- + a
max - min
Você pode verificar se colocando em min
para x
agora dá a
, e colocando em max
dá b
.
Você também pode perceber que (b-a)/(max-min)
é um fator de escala entre o tamanho do novo intervalo e o tamanho do intervalo original. Então, realmente estamos primeira traduzir x
por -min
, dimensioná-lo para o fator correto, e depois traduzi-lo backup para o novo valor mínimo de a
.
Espero que isto ajude.
max != min
outra forma os resultados de função indeterminada :)min
é negativo emax
é positivo ou ambos têm que ser positivos?Aqui está algum JavaScript para facilitar a copiar e colar (esta é a resposta irritante):
Aplicado dessa forma, dimensionando o intervalo de 10 a 50 para um intervalo entre 0 e 100.
Editar:
Eu sei que respondi isso há muito tempo, mas aqui está uma função mais limpa que eu uso agora:
Aplicado assim:
fonte
[1, 1, 1]
,[100, 100, 100]
ou até mesmo[50.5, 50.5, 50.5]
. Você poderia colocar no caso:if (max-min == 0) return this.map(num => (scaledMin+scaledMax)/2);
Por conveniência, aqui está o algoritmo do Irritate em um formato Java. Adicione verificação de erros, manipulação de exceções e ajuste conforme necessário.
Testador:
fonte
Aqui está como eu o entendo:
Qual porcentagem
x
está em um intervaloVamos supor que você tenha um intervalo de
0
até100
. Dado um número arbitrário desse intervalo, em que "porcentagem" desse intervalo ele se encontra? Isso deve ser bem simples,0
seria0%
,50
seria50%
e100
seria100%
.Agora, o que se o intervalo foi
20
de100
? Não podemos aplicar a mesma lógica acima (dividir por 100) porque:não nos dá
0
(20
deveria ser0%
agora). Isso deve ser simples de corrigir, basta criar o numerador0
para o caso de20
. Podemos fazer isso subtraindo:No entanto, isso não funciona
100
mais porque:não nos dá
100%
. Novamente, podemos corrigir isso subtraindo também o denominador:Uma equação mais generalizada para descobrir qual%
x
está em um intervalo seria:Escala de escala para outra escala
Agora que sabemos qual a porcentagem de um número em um intervalo, podemos aplicá-lo para mapear o número para outro intervalo. Vamos passar por um exemplo.
Se tivermos um número no intervalo antigo, qual seria o número no novo intervalo? Digamos que o número seja
400
. Primeiro, descubra qual porcentagem400
está dentro do intervalo antigo. Podemos aplicar nossa equação acima.Então,
400
está na25%
faixa antiga. Só precisamos descobrir qual é o número25%
da nova faixa. Pense sobre o que50%
de[0, 20]
é. Seria10
certo? Como você chegou a essa resposta? Bem, podemos apenas fazer:Mas e daí
[10, 20]
? Precisamos mudar tudo10
agora. por exemplo:uma fórmula mais generalizada seria:
Para o exemplo original do que
25%
de[10, 20]
é:Então,
400
no intervalo[200, 1000]
mapearia12.5
no intervalo[10, 20]
TLDR
Para mapear
x
do intervalo antigo para o novo intervalo:fonte
Me deparei com esta solução, mas isso realmente não se encaixa na minha necessidade. Então eu cavei um pouco no código-fonte d3. Pessoalmente, eu recomendaria fazê-lo como o d3.scale faz.
Então, aqui você dimensiona o domínio para o intervalo. A vantagem é que você pode virar os sinais para o seu alcance-alvo. Isso é útil, uma vez que o eixo y na tela do computador desce de forma que valores grandes têm um y pequeno.
E aqui está o teste onde você pode ver o que quero dizer
fonte
Peguei a resposta de Irritate e a refatorei para minimizar as etapas computacionais para cálculos subsequentes, fatorando-a no menor número de constantes. A motivação é permitir que um escalador seja treinado em um conjunto de dados e, em seguida, executado em novos dados (para um algo de ML). Na verdade, é muito parecido com o pré-processamento do MiniMaxScaler para Python do SciKit em uso.
Assim,
x' = (b-a)(x-min)/(max-min) + a
(onde b! = A) se torna ox' = x(b-a)/(max-min) + min(-b+a)/(max-min) + a
que pode ser reduzido a duas constantes no formuláriox' = x*Part1 + Part2
.Aqui está uma implementação de C # com dois construtores: um para treinar e outro para recarregar uma instância treinada (por exemplo, para dar suporte à persistência).
fonte
Com base na resposta de Charles Clayton, incluí alguns ajustes no JSDoc, ES6 e incorporei sugestões dos comentários na resposta original.
fonte