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

Spl*_*iFF 236 python math

我正在尝试将一个数字范围转换为另一个数字,保持比率.数学不是我的强项.

我有一个图像文件,其中点值可能在-16000.00到16000.00之间,尽管典型范围可能要小得多.我想要做的是将这些值压缩到整数范围0-100,其中0是最小点的值,100是最大值的值.中间的所有点都应该保持相对比率,即使丢失了一些精度我想在python中这样做,但即使是一般算法也应该足够.我宁愿一个算法,其中最小/最大或任一范围可被调整(即,在第二范围可以是-50℃至800,而不是0到100).

jer*_*jvl 476

NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
Run Code Online (Sandbox Code Playgroud)

或者更具可读性:

OldRange = (OldMax - OldMin)  
NewRange = (NewMax - NewMin)  
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
Run Code Online (Sandbox Code Playgroud)

或者,如果要保护旧范围为0(OldMin = OldMax)的情况:

OldRange = (OldMax - OldMin)
if (OldRange == 0)
    NewValue = NewMin
else
{
    NewRange = (NewMax - NewMin)  
    NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
}
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,我们不得不随意选择一个可能的新范围值.根据上下文,明智的选择可能是:NewMin(见样本),NewMax(NewMin + NewMax) / 2

  • 这太棒了。这种转换有数学名称吗? (7认同)
  • 你可以把它任何你想要的......记住,你可能会得到奇怪的结果,如果范围中的一个相对于另外一个(不完全肯定非常小的,但如果有比大小之间的百万因素的差异更范围,确保它实际上表现得像你期望的......或了解浮点不准确) (5认同)
  • 这称为线性转换,@Tarik (4认同)
  • 考虑到这个答案的流行,对于更一般的情况,你应该考虑OldMax == OldMin的可能性,这可能导致除以零. (2认同)
  • @buffer @jerryjvl `OldMax == OldMin` 应被视为异常(`raise Exception("OldRange is Zero"`)而不是 `NewValue = NewMin`。执行原始工作的代码的(主要)目的是模糊的。 (2认同)

cle*_*tus 59

这是一个简单的线性转换.

new_value = ( (old_value - old_min) / (old_max - old_min) ) * (new_max - new_min) + new_min
Run Code Online (Sandbox Code Playgroud)

因此,在-16000到16000的范围内将10000转换为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
Run Code Online (Sandbox Code Playgroud)

  • 这是错的.您需要在除法之前从Old Value中减去Old Min. (2认同)

小智 20

实际上有些情况下上面的答案会破裂.如错误的输入值,错误的输入范围,负输入/输出范围.

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
Run Code Online (Sandbox Code Playgroud)


Ted*_*and 9

有一个条件,当您检查的所有值都相同时,@ jerryjvl的代码将返回NaN.

if (OldMin != OldMax && NewMin != NewMax):
    return (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
else:
    return (NewMax + NewMin) / 2
Run Code Online (Sandbox Code Playgroud)


dra*_*788 7

我没有为此挖掘BNF,但是 Arduino 文档有一个很好的功能示例,并且它是细分的。我可以通过简单地添加一个 def 重命名来重新映射(因为 map 是内置的)并删除类型转换和花括号(即只删除所有的“long”),从而在 Python 中使用它。

原来的

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
Run Code Online (Sandbox Code Playgroud)

Python

def remap(x, in_min, in_max, out_min, out_max):
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
Run Code Online (Sandbox Code Playgroud)

https://www.arduino.cc/en/reference/map


Cha*_*ton 6

这里有一些简短的 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]
Run Code Online (Sandbox Code Playgroud)

可以这样使用:

scale_list([1,3,4,5], 0, 100)
Run Code Online (Sandbox Code Playgroud)

[0.0, 50.0, 75.0, 100.0]

就我而言,我想缩放对数曲线,如下所示:

scale_list([math.log(i+1) for i in range(5)], 0, 50)
Run Code Online (Sandbox Code Playgroud)

[0.0, 21.533827903669653, 34.130309724299266, 43.06765580733931, 50.0]


Tab*_*aei 6

使用Numpyinterp功能,您可以将值从旧范围转换为新范围

>>> import numpy as np
>>> np.interp(0, [-16000,16000], [0,100])
50.0
Run Code Online (Sandbox Code Playgroud)

您还可以尝试它来映射值列表

>>> np.interp([-16000,0,12000] ,[-16000,16000], [0,100])
array([ 0. , 50. , 87.5])
Run Code Online (Sandbox Code Playgroud)


Hit*_*ahu 5

添加了带有数学解释的 KOTLIN 版本

考虑我们的范围在(OMin, Omax)之间,并且我们有一个在此范围内的值X

我们想将其转换为比例 (NMin,NMax)

我们知道 X,我们需要找到 Y,比率必须相同:

 => (Y-NMin)/(NMax-NMin) = (X-OMin)/(OMax-OMin)  
      
 =>  (Y-NMin)/NewRange = (X-OMin)/OldRange 

 =>   Y = ((X-OMin)*NewRange)/oldRange)+NMin  Answer
   
Run Code Online (Sandbox Code Playgroud)

实际上我们可以这样写这个方程:

 private fun  convertScale(oldValueToConvert:Int): Float {
       // Old Scale 50-100
       val oldScaleMin = 50
       val oldScaleMax = 100
       val oldScaleRange= (oldScaleMax - oldScaleMin)

       //new Scale 0-1
       val newScaleMin = 0.0f
       val newScaleMax = 1.0f
       val newScaleRange=  (newScaleMax - newScaleMin)
     
       return ((oldValueToConvert - oldScaleMin)* newScaleRange/ oldScaleRange) + newScaleMin
    }
Run Code Online (Sandbox Code Playgroud)

爪哇

/**
     * 
     * @param x
     * @param inMin
     * @param inMax
     * @param outMin
     * @param outMax
     * @return
     */
        private long normalize(long x, long inMin, long inMax, long outMin, long outMax) {
          long outRange = outMax - outMin;
          long inRange  = inMax - inMin;
          return (x - inMin) *outRange / inRange + outMin;
        }
Run Code Online (Sandbox Code Playgroud)

用法:

float brightness = normalize(progress, 0, 10, 0,255);
Run Code Online (Sandbox Code Playgroud)