我试图将一个范围的数字转换为另一个,保持比率。数学不是我的强项。
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).
我在一个用js解决的问题中使用了这个解决方案,所以我想我将分享翻译。谢谢你的解释和解决方案。
function remap( x, oMin, oMax, nMin, nMax ){
//range check
if (oMin == oMax){
console.log("Warning: Zero input range");
return None;
};
if (nMin == nMax){
console.log("Warning: Zero output range");
return None
}
//check reversed input range
var reverseInput = false;
oldMin = Math.min( oMin, oMax );
oldMax = Math.max( oMin, oMax );
if (oldMin != oMin){
reverseInput = true;
}
//check reversed output range
var reverseOutput = false;
newMin = Math.min( nMin, nMax )
newMax = Math.max( nMin, nMax )
if (newMin != nMin){
reverseOutput = true;
};
var portion = (x-oldMin)*(newMax-newMin)/(oldMax-oldMin)
if (reverseInput){
portion = (oldMax-x)*(newMax-newMin)/(oldMax-oldMin);
};
var result = portion + newMin
if (reverseOutput){
result = newMax - portion;
}
return result;
}
这个例子将歌曲的当前位置转换为20 - 40的角度范围。
/// <summary>
/// This test converts Current songtime to an angle in a range.
/// </summary>
[Fact]
public void ConvertRangeTests()
{
//Convert a songs time to an angle of a range 20 - 40
var result = ConvertAndGetCurrentValueOfRange(
TimeSpan.Zero, TimeSpan.FromMinutes(5.4),
20, 40,
2.7
);
Assert.True(result == 30);
}
/// <summary>
/// Gets the current value from the mixValue maxValue range.
/// </summary>
/// <param name="startTime">Start of the song</param>
/// <param name="duration"></param>
/// <param name="minValue"></param>
/// <param name="maxValue"></param>
/// <param name="value">Current time</param>
/// <returns></returns>
public double ConvertAndGetCurrentValueOfRange(
TimeSpan startTime,
TimeSpan duration,
double minValue,
double maxValue,
double value)
{
var timeRange = duration - startTime;
var newRange = maxValue - minValue;
var ratio = newRange / timeRange.TotalMinutes;
var newValue = value * ratio;
var currentValue= newValue + minValue;
return currentValue;
}
我写了一个函数用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)
}
}
下面是一些简单的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]