将数字范围转换为另一个范围,保持比例

387 投票
21 回答
360719 浏览
提问于 2025-04-15 11:56

我想把一组数字转换成另一组,同时保持它们之间的比例关系。数学对我来说不是强项。

我有一个图片文件,里面的点值可能在-16000.00到16000.00之间,不过通常情况下这个范围会小很多。我想把这些值压缩到0到100的整数范围内,其中0代表最小的点值,100代表最大的点值。中间的所有点也要保持相对的比例,虽然这样会损失一些精度。我想用Python来实现这个,但如果有一个通用的算法也可以。我希望这个算法能让最小值和最大值都可以调整(比如,第二个范围可以是-50到800,而不是0到100)。

21 个回答

29

其实有些情况下,上面的答案可能会出问题。比如说输入的值不对、输入的范围不对,或者输入/输出的范围是负数。

def remap( x, oMin, oMax, nMin, nMax ):

    #range check
    if oMin == oMax:
        print "Warning: Zero input range"
        return None

    if nMin == nMax:
        print "Warning: Zero output range"
        return None

    #check reversed input range
    reverseInput = False
    oldMin = min( oMin, oMax )
    oldMax = max( oMin, oMax )
    if not oldMin == oMin:
        reverseInput = True

    #check reversed output range
    reverseOutput = False   
    newMin = min( nMin, nMax )
    newMax = max( nMin, nMax )
    if not newMin == nMin :
        reverseOutput = True

    portion = (x-oldMin)*(newMax-newMin)/(oldMax-oldMin)
    if reverseInput:
        portion = (oldMax-x)*(newMax-newMin)/(oldMax-oldMin)

    result = portion + newMin
    if reverseOutput:
        result = newMax - portion

    return result

#test cases
print remap( 25.0, 0.0, 100.0, 1.0, -1.0 ), "==", 0.5
print remap( 25.0, 100.0, -100.0, -1.0, 1.0 ), "==", -0.25
print remap( -125.0, -100.0, -200.0, 1.0, -1.0 ), "==", 0.5
print remap( -125.0, -200.0, -100.0, -1.0, 1.0 ), "==", 0.5
#even when value is out of bound
print remap( -20.0, 0.0, 100.0, 0.0, 1.0 ), "==", -0.2
89

这只是一个简单的线性转换。

new_value = ( (old_value - old_min) / (old_max - old_min) ) * (new_max - new_min) + new_min

所以,把10000从-16000到16000的范围转换到0到100的新范围,结果是:

old_value = 10000
old_min = -16000
old_max = 16000
new_min = 0
new_max = 100

new_value = ( ( 10000 - -16000 ) / (16000 - -16000) ) * (100 - 0) + 0
          = 81.25
751
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

撰写回答