Допустим, вы хотите масштабировать диапазон [min,max]
до [a,b]
. Вы ищете (непрерывную) функцию, которая удовлетворяет
f(min) = a
f(max) = b
В вашем случае a
будет 1 и b
30, но давайте начнем с чего-то более простого и попробуем отобразить [min,max]
диапазон [0,1]
.
Ввод min
в функцию и выход 0 может быть достигнуто с
f(x) = x - min ===> f(min) = min - min = 0
Так что это почти то, что мы хотим. Но вставка max
даст нам, max - min
когда мы на самом деле хотим 1. Так что нам придется масштабировать его:
x - min max - min
f(x) = --------- ===> f(min) = 0; f(max) = --------- = 1
max - min max - min
что мы и хотим Итак, нам нужно сделать перевод и масштабирование. Теперь, если вместо этого мы хотим получить произвольные значения a
и b
, нам нужно нечто более сложное:
(b-a)(x - min)
f(x) = -------------- + a
max - min
Вы можете проверить, что сдача min
на x
данный момент дает a
, а сдача max
дает b
.
Вы также можете заметить, что (b-a)/(max-min)
это масштабный коэффициент между размером нового диапазона и размером исходного диапазона. Так на самом деле мы первый перевод x
на -min
, масштабирование для правильного фактора, а затем переводить его обратно до нового минимального значения a
.
Надеюсь это поможет.
max != min
иначе результаты функции будут неопределенными :)min
он отрицательный иmax
положительный, или они оба должны быть положительными?Вот некоторый JavaScript для простоты копирования и вставки (это раздражает ответ):
Применяется так, масштабирование от 10-50 до 0-100.
Редактировать:
Я знаю, что ответил на это давным-давно, но вот более чистая функция, которую я использую сейчас:
Применяется так:
источник
[1, 1, 1]
,[100, 100, 100]
или даже[50.5, 50.5, 50.5]
. Вы могли бы положить в дело:if (max-min == 0) return this.map(num => (scaledMin+scaledMax)/2);
Для удобства, вот алгоритм Irritate в форме Java. Добавьте проверку ошибок, обработку исключений и настройку при необходимости.
Tester:
источник
Вот как я это понимаю:
Какой процент
x
лежит в диапазонеПредположим, у вас есть диапазон от
0
до100
. Учитывая произвольное число из этого диапазона, в каком «проценте» из этого диапазона он лежит? Это должно быть довольно просто,0
было бы0%
,50
будет50%
и100
будет100%
.Теперь, если ваш диапазон был
20
в100
? Мы не можем применять ту же логику, что и выше (делим на 100), потому что:не дает нам
0
(20
должно быть0%
сейчас). Это должно быть легко исправить, нам просто нужно сделать числитель0
для случая20
. Мы можем сделать это, вычитая:Однако это больше не работает
100
, потому что:не дает нам
100%
. Опять же, мы можем исправить это, вычтя и знаменатель:Более обобщенное уравнение для определения того, что%
x
лежит в диапазоне:Шкала диапазона в другой диапазон
Теперь, когда мы знаем, какой процент находится в диапазоне, мы можем применить его, чтобы отобразить число в другой диапазон. Давайте рассмотрим пример.
Если у нас есть число в старом диапазоне, каким будет число в новом диапазоне? Допустим, номер есть
400
. Сначала выясните, какой процент400
находится в старом диапазоне. Мы можем применить наше уравнение выше.Итак,
400
лежит в25%
старом ассортименте. Нам просто нужно выяснить, какое число25%
из нового ассортимента. Подумайте о том, что50%
в[0, 20]
это. Это было бы10
правильно? Как вы пришли к этому ответу? Ну, мы можем просто сделать:Но как насчет
[10, 20]
? Нам нужно все10
сейчас сдвинуть . например:более обобщенная формула будет:
Для первоначального примера того , что
25%
в[10, 20]
это:Таким образом,
400
в диапазоне[200, 1000]
будет12.5
в диапазоне[10, 20]
TLDR
Чтобы отобразить
x
старый диапазон на новый:источник
Я сталкивался с этим решением, но оно не совсем соответствует моим потребностям. Поэтому я немного покопался в исходном коде d3. Я лично рекомендовал бы делать это так, как это делает d3.scale.
Таким образом, здесь вы масштабируете домен до диапазона. Преимущество заключается в том, что вы можете перевернуть знаки для целевого диапазона. Это полезно, поскольку ось y на экране компьютера опускается сверху вниз, поэтому большие значения имеют маленький y.
И вот тест, где вы можете увидеть, что я имею в виду
источник
Я взял ответ Irritate и реорганизовал его, чтобы свести к минимуму вычислительные шаги для последующих вычислений, разделив его на наименьшее число констант. Мотивация состоит в том, чтобы позволить обучить скейлер на одном наборе данных, а затем запускать на новых данных (для алгоритма ML). По сути, это очень похоже на предварительную обработку SciKit MinMaxScaler для Python.
Таким образом,
x' = (b-a)(x-min)/(max-min) + a
(где b! = A) становится,x' = x(b-a)/(max-min) + min(-b+a)/(max-min) + a
который может быть уменьшен до двух констант в формеx' = x*Part1 + Part2
.Вот реализация C # с двумя конструкторами: один для обучения и один для перезагрузки обученного экземпляра (например, для поддержки постоянства).
источник
Основываясь на ответе Чарльза Клэйтона, я включил некоторые настройки JSDoc, ES6 и включил предложения из комментариев в первоначальный ответ.
источник