Supposons que vous souhaitiez mettre une plage [min,max]
à l' échelle [a,b]
. Vous recherchez une fonction (continue) qui satisfait
f(min) = a
f(max) = b
Dans votre cas, a
serait 1 et b
serait 30, mais commençons par quelque chose de plus simple et essayons de mapper [min,max]
dans la plage [0,1]
.
Mettre min
dans une fonction et sortir 0 pourrait être accompli avec
f(x) = x - min ===> f(min) = min - min = 0
C'est donc presque ce que nous voulons. Mais la mise en place max
nous donnerait max - min
quand nous en aurions réellement besoin 1. Il nous faudra donc la mettre à l'échelle:
x - min max - min
f(x) = --------- ===> f(min) = 0; f(max) = --------- = 1
max - min max - min
c'est ce que nous voulons. Nous devons donc faire une traduction et une mise à l'échelle. Maintenant, si au contraire nous voulons obtenir des valeurs arbitraires de a
et b
, nous avons besoin de quelque chose d'un peu plus compliqué:
(b-a)(x - min)
f(x) = -------------- + a
max - min
Vous pouvez vérifier que la mise min
pour l' x
instant donne a
et la mise max
donne b
.
Vous pouvez également remarquer qu'il (b-a)/(max-min)
s'agit d'un facteur d'échelle entre la taille de la nouvelle plage et la taille de la plage d'origine. Donc, vraiment, nous traduisons d'abord x
par -min
, le mettons à l'échelle au facteur correct, puis le traduisons à la nouvelle valeur minimale de a
.
J'espère que cela t'aides.
max != min
sinon les résultats de la fonctionmin
est négatif etmax
positif, ou les deux doivent-ils être positifs?Voici un peu de JavaScript pour faciliter le copier-coller (c'est la réponse de irritate):
Appliqué comme tel, la mise à l'échelle de la plage 10-50 à une plage entre 0-100.
Éditer:
Je sais que j'ai répondu à cela il y a longtemps, mais voici une fonction plus propre que j'utilise maintenant:
Appliqué comme ça:
la source
[1, 1, 1]
,[100, 100, 100]
ou même[50.5, 50.5, 50.5]
. Vous pourriez mettre dans le cas:if (max-min == 0) return this.map(num => (scaledMin+scaledMax)/2);
Pour plus de commodité, voici l'algorithme d'Irritate sous une forme Java. Ajoutez la vérification des erreurs, la gestion des exceptions et ajustez si nécessaire.
Testeur:
la source
Voici comment je le comprends:
Quel pourcentage
x
se situe dans une fourchetteSupposons que vous ayez une plage de
0
à100
. Étant donné un nombre arbitraire de cette plage, dans quel "pourcentage" de cette plage se situe-t-il? Cela devrait être assez simple,0
serait0%
,50
serait50%
et100
serait100%
.Maintenant, si votre gamme était
20
à100
? Nous ne pouvons pas appliquer la même logique que ci-dessus (diviser par 100) car:ne nous donne pas
0
(20
devrait être0%
maintenant). Cela devrait être simple à corriger, il suffit de faire le numérateur0
pour le cas de20
. Nous pouvons le faire en soustrayant:Cependant, cela ne fonctionne
100
plus car:ne nous donne pas
100%
. Encore une fois, nous pouvons résoudre ce problème en soustrayant également le dénominateur:Une équation plus généralisée pour découvrir ce que%
x
se situe dans une fourchette serait:Ajuster la plage à une autre plage
Maintenant que nous savons quel pourcentage se trouve un nombre dans une plage, nous pouvons l'appliquer pour mapper le nombre à une autre plage. Voyons un exemple.
Si nous avons un nombre dans l'ancienne plage, quel serait le nombre dans la nouvelle plage? Disons que le nombre est
400
. Tout d'abord, déterminez quel pourcentage se400
situe dans l'ancienne fourchette. Nous pouvons appliquer notre équation ci-dessus.Donc,
400
se situe dans25%
l'ancienne gamme. Nous avons juste besoin de déterminer le numéro25%
de la nouvelle gamme. Pensez à ce que50%
de[0, 20]
est. Ce serait10
bien? Comment êtes-vous arrivé à cette réponse? Eh bien, nous pouvons simplement faire:Mais qu'en est-il de
[10, 20]
? Nous devons tout changer10
maintenant. par exemple:une formule plus généralisée serait:
Pour l'exemple original de ce
25%
de[10, 20]
est:Ainsi,
400
dans la plage[200, 1000]
correspondrait à12.5
la plage[10, 20]
TLDR
Pour mapper
x
de l'ancienne plage vers la nouvelle plage:la source
Je suis tombé sur cette solution mais cela ne correspond pas vraiment à mon besoin. J'ai donc creusé un peu dans le code source d3. Personnellement, je recommanderais de le faire comme le fait d3.scale.
Alors ici, vous mettez le domaine à l'échelle. L'avantage est que vous pouvez retourner les signes dans votre plage cible. Cela est utile car l'axe y sur un écran d'ordinateur descend de façon à ce que les grandes valeurs aient un petit y.
Et voici le test où vous pouvez voir ce que je veux dire
la source
J'ai pris la réponse d'Irritate et l'ai refactorisée afin de minimiser les étapes de calcul pour les calculs ultérieurs en la factorisant dans le moins de constantes. La motivation est de permettre à un mesureur d'être formé sur un ensemble de données, puis d'être exécuté sur de nouvelles données (pour un algo ML). En effet, il ressemble beaucoup au prétraitement MinMaxScaler de Python pour SciKit.
Ainsi,
x' = (b-a)(x-min)/(max-min) + a
(où b! = A) devientx' = x(b-a)/(max-min) + min(-b+a)/(max-min) + a
ce qui peut être réduit à deux constantes dans le formulairex' = x*Part1 + Part2
.Voici une implémentation C # avec deux constructeurs: un pour former et un pour recharger une instance formée (par exemple, pour prendre en charge la persistance).
la source
Sur la base de la réponse de Charles Clayton, j'ai inclus quelques ajustements JSDoc, ES6 et incorporé des suggestions des commentaires dans la réponse originale.
la source