我试图将一个范围的数字转换为另一个,保持比率。数学不是我的强项。
I have an image file where point values may range from -16000.00 to 16000.00 though the typical range may be much less. What I want to do is compress these values into the integer range 0-100, where 0 is the value of the smallest point, and 100 is the value of the largest. All points in between should keep a relative ratio even though some precision is being lost I'd like to do this in python but even a general algorithm should suffice. I'd prefer an algorithm where the min/max or either range can be adjusted (ie, the second range could be -50 to 800 instead of 0 to 100).
下面是一些简单的Python函数,便于复制和粘贴,包括一个扩展整个列表的函数。
def scale_number(unscaled, to_min, to_max, from_min, from_max):
return (to_max-to_min)*(unscaled-from_min)/(from_max-from_min)+to_min
def scale_list(l, to_min, to_max):
return [scale_number(i, to_min, to_max, min(l), max(l)) for i in l]
可以这样使用:
scale_list([1,3,4,5], 0, 100)
[0.0, 50.0, 75.0, 100.0]
在我的例子中,我想缩放一条对数曲线,像这样:
scale_list([math.log(i+1) for i in range(5)], 0, 50)
[0.0, 21.533827903669653, 34.130309724299266, 43.06765580733931, 50.0]
NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
或者更容易读懂:
OldRange = (OldMax - OldMin)
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
或者如果你想保护旧范围为0的情况(OldMin = OldMax):
OldRange = (OldMax - OldMin)
if (OldRange == 0)
NewValue = NewMin
else
{
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
}
注意,在这种情况下,我们被迫任意选择一个可能的新范围值。根据上下文,明智的选择可能是:NewMin(见示例),NewMax或(NewMin + NewMax) / 2
我写了一个函数用R来做这个,方法和上面一样,但是我需要在R中做很多次,所以我想分享一下,以防它对任何人有帮助。
convertRange <- function(
oldValue,
oldRange = c(-16000.00, 16000.00),
newRange = c(0, 100),
returnInt = TRUE # the poster asked for an integer, so this is an option
){
oldMin <- oldRange[1]
oldMax <- oldRange[2]
newMin <- newRange[1]
newMax <- newRange[2]
newValue = (((oldValue - oldMin)* (newMax - newMin)) / (oldMax - oldMin)) + newMin
if(returnInt){
return(round(newValue))
} else {
return(newValue)
}
}
下面是一个Javascript版本,它返回一个函数,对预定的源和目标范围进行重新缩放,最大限度地减少每次必须执行的计算量。
// This function returns a function bound to the
// min/max source & target ranges given.
// oMin, oMax = source
// nMin, nMax = dest.
function makeRangeMapper(oMin, oMax, nMin, nMax ){
//range check
if (oMin == oMax){
console.log("Warning: Zero input range");
return undefined;
};
if (nMin == nMax){
console.log("Warning: Zero output range");
return undefined
}
//check reversed input range
var reverseInput = false;
let oldMin = Math.min( oMin, oMax );
let oldMax = Math.max( oMin, oMax );
if (oldMin != oMin){
reverseInput = true;
}
//check reversed output range
var reverseOutput = false;
let newMin = Math.min( nMin, nMax )
let newMax = Math.max( nMin, nMax )
if (newMin != nMin){
reverseOutput = true;
}
// Hot-rod the most common case.
if (!reverseInput && !reverseOutput) {
let dNew = newMax-newMin;
let dOld = oldMax-oldMin;
return (x)=>{
return ((x-oldMin)* dNew / dOld) + newMin;
}
}
return (x)=>{
let portion;
if (reverseInput){
portion = (oldMax-x)*(newMax-newMin)/(oldMax-oldMin);
} else {
portion = (x-oldMin)*(newMax-newMin)/(oldMax-oldMin)
}
let result;
if (reverseOutput){
result = newMax - portion;
} else {
result = portion + newMin;
}
return result;
}
}
下面是一个使用该函数将0-1缩放到-0x80000000, 0x7FFFFFFF的示例
let normTo32Fn = makeRangeMapper(0, 1, -0x80000000, 0x7FFFFFFF);
let fs = normTo32Fn(0.5);
let fs2 = normTo32Fn(0);