var unscaledNums = [10, 13, 25, 28, 43, 50];
var maxRange = Math.max.apply(Math, unscaledNums);
var minRange = Math.min.apply(Math, unscaledNums);
for (var i = 0; i < unscaledNums.length; i++) {
var unscaled = unscaledNums[i];
var scaled = scaleBetween(unscaled, 0, 100, minRange, maxRange);
console.log(scaled.toFixed(2));
}
0.00,18.37,48.98,55.10,85.71,100.00
Edit:
我知道我很久以前就回答了这个问题,但是我现在使用的是一个更清洁的功能:
Array.prototype.scaleBetween = function(scaledMin, scaledMax) {
var max = Math.max.apply(Math, this);
var min = Math.min.apply(Math, this);
return this.map(num => (scaledMax-scaledMin)*(num-min)/(max-min)+scaledMin);
}
public class MinMaxColumnSpec
{
/// <summary>
/// To reduce repetitive computations, the min-max formula has been refactored so that the portions that remain constant are just computed once.
/// This transforms the forumula from
/// x' = (b-a)(x-min)/(max-min) + a
/// into x' = x(b-a)/(max-min) + min(-b+a)/(max-min) + a
/// which can be further factored into
/// x' = x*Part1 + Part2
/// </summary>
public readonly double Part1, Part2;
/// <summary>
/// Use this ctor to train a new scaler.
/// </summary>
public MinMaxColumnSpec(double[] columnValues, int newMin = 0, int newMax = 1)
{
if (newMax <= newMin)
throw new ArgumentOutOfRangeException("newMax", "newMax must be greater than newMin");
var oldMax = columnValues.Max();
var oldMin = columnValues.Min();
Part1 = (newMax - newMin) / (oldMax - oldMin);
Part2 = newMin + (oldMin * (newMin - newMax) / (oldMax - oldMin));
}
/// <summary>
/// Use this ctor for previously-trained scalers with known constants.
/// </summary>
public MinMaxColumnSpec(double part1, double part2)
{
Part1 = part1;
Part2 = part2;
}
public double Scale(double x) => (x * Part1) + Part2;
}
6 回答
假设您要将范围
[min,max]
缩放为[a,b]
. 您正在寻找满足的(连续)功能在你的情况下,
a
将是1,b
将是30,但让我们从更简单的东西开始,并尝试将[min,max]
映射到范围[0,1]
.将
min
放入函数中并且输出0可以完成这几乎就是我们想要的 . 但是当我们真正想要时,输入
max
会给我们max - min
所以我们必须扩展它:这就是我们想要的 . 所以我们需要进行翻译和缩放 . 现在,如果我们想获得
a
和b
的任意值,我们需要更复杂的东西:您可以验证为
x
输入min
现在给出a
,并且输入max
给出b
.您可能还注意到
(b-a)/(max-min)
是新范围大小与原始范围大小之间的缩放系数 . 所以我们首先将x
翻译为-min
,将其缩放到正确的因子,然后将其转换回新的最小值a
.希望这可以帮助 .
这里有一些用于复制粘贴的JavaScript(这是烦人的答案):
像这样应用,将范围10-50缩放到0-100之间的范围 .
Edit:
我知道我很久以前就回答了这个问题,但是我现在使用的是一个更清洁的功能:
应用如下:
为方便起见,这里是Java形式的Irritate算法 . 根据需要添加错误检查,异常处理和调整 .
测试:
这是我理解的方式:
x在一个范围内的百分比是多少
假设您的范围从
0
到100
. 给定该范围内的任意数字,该范围内的"percent"是什么?这应该很简单,0
将0%
,50
将50%
和100
将100%
.现在,如果你的范围是
20
到100
怎么办?我们不能应用与上面相同的逻辑(除以100),因为:不给我们
0
(20
现在应该0%
) . 这应该很容易修复,我们只需要为20
的情况制作分子0
. 我们可以通过减去:但是,这不再适用于
100
,因为:不给我们
100%
. 同样,我们也可以通过从分母中减去它来解决这个问题:找出%
x
在一个范围内的更通用的等式将是:将范围扩展到另一个范围
现在我们知道数字在一个范围内的百分比,我们可以应用它来将数字映射到另一个范围 . 我们来看一个例子吧 .
如果我们在旧范围内有一个数字,那么这个数字在新范围内会是多少?假设这个数字是
400
. 首先,找出400
在旧范围内的百分比 . 我们可以应用上面的等式 .所以,
400
位于旧范围的25%
. 我们只需要确定新范围的25%
是多少 . 想想[0, 20]
的50%
是什么 . 那会是10
对吗?你是怎么得到答案的?好吧,我们可以这样做:但是,从
[10, 20]
怎么样?我们现在需要通过_1716039改变一切 . 例如:一个更通用的公式是:
对于
[10, 20]
的25%
的原始示例是:因此,
[200, 1000]
范围内的400
将映射到[10, 20]
范围内的12.5
TLDR
要将
x
从旧范围映射到新范围:我遇到了这个解决方案,但这并不适合我的需要 . 所以我挖了d3源代码中的一点 . 我个人会建议像d3.scale那样做 .
所以在这里你将域缩放到范围 . 优点是您可以将标志翻转到目标范围 . 这很有用,因为计算机屏幕上的y轴自上而下,因此较大的值具有较小的y .
这是测试,你可以看到我的意思
我采用了Irritate的答案并重构了它,以便通过将其分解为最少的常数来最小化后续计算的计算步骤 . 动机是允许在一组数据上训练定标器,然后在新数据上运行(对于ML算法) . 实际上,它与SciKit的Python预处理MinMaxScaler非常相似 .
因此,
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#实现:一个用于训练,一个用于重新加载训练过的实例(例如,支持持久性) .