Konvertieren eines Nummernbereich in einen anderen Bereich, die Aufrechterhaltung Verhältnis
Frage
Ich versuche, eine Reihe von Zahlen in ein anderes zu konvertieren, die Aufrechterhaltung Verhältnis. Mathe ist nicht meine Stärke.
Ich habe eine Bilddatei in den Punktwert -16.000,00-16000,00 reichen kann, obwohl der typische Bereich viel weniger sein kann. Was ich tun möchte, ist diese Werte in die Integerbereich komprimieren 0-100, wobei 0 der Wert des kleinsten Punkt ist, und 100 ist der Wert der größten. Alle Punkte dazwischen ein relatives Verhältnis halten sollte, auch wenn einige Genauigkeit verloren geht möchte ich dies in Python tun, sondern auch ein allgemeiner Algorithmus sollte ausreichen. Ich würde es vorziehen, einen Algorithmus, wo die min / max oder entweder Bereich kann eingestellt werden (dh könnte der zweite Bereich von -50 bis 800 anstelle von 0 bis 100 sein).
Lösung
NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
oder ein wenig mehr lesbar:
OldRange = (OldMax - OldMin)
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
Oder wenn Sie wollen für den Fall zu schützen, wo der alte Bereich ist 0 ( OldMin = OldMax ):
OldRange = (OldMax - OldMin)
if (OldRange == 0)
NewValue = NewMin
else
{
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
}
Beachten Sie, dass wir in diesem Fall gezwungen sind, eine der möglichen neuen Bereichswerte willkürlich auszuwählen. Je nach Kontext kann vernünftige Entscheidungen sein: NewMin
( siehe Beispiel ), NewMax
oder (NewMin + NewMax) / 2
Andere Tipps
Das ist eine einfache lineare Konvertierung.
new_value = ( (old_value - old_min) / (old_max - old_min) ) * (new_max - new_min) + new_min
So 10000 auf der Skala von -16.000-16.000 auf eine neue Skala von 0 bis 100 Ausbeuten Umwandlung:
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
Eigentlich gibt es einige Fälle, dass oben genannte Antworten brechen. Wie falsch Eingabewert, falsch Eingangsbereich, negativ Ein- / Ausgangsbereiche.
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
Es ist eine Bedingung, wenn alle Werte, die Sie sind gleich einchecken, wo Code des @ jerryjvl zurückkehren würde NaN.
if (OldMin != OldMax && NewMin != NewMax):
return (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
else:
return (NewMax + NewMin) / 2
Ich habe nicht graben die BNF für diese, aber die Arduino-Dokumentation hatte ein großartiges Beispiel für die Funktion und es ist Zusammenbruch. Ich konnte dies durch einfaches Hinzufügen einer def Umbenennung in Python verwenden, um neu zuordnen (Ursache Karte ist eine integrierte) und die Art Entfernen wirft und geschweiften Klammern (dh nur entfernen Sie alle ‚Longs).
Original
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;
}
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
In der Auflistung von PenguinTD zur Verfügung gestellt, die ich nicht verstehe, warum die Bereiche umgekehrt sind, funktioniert es ohne die Bereiche umkehren zu müssen. Linearbereichsumwandlung wird auf die lineare Gleichung Y=Xm+n
basiert, wobei m
n
und werden aus den angegebenen Bereichen abgeleitet. Anstatt auf die Bereiche wie min
und max
zu beziehen, wäre es besser, sie zu beziehen, wie 1 und 2. So ist die Formel wäre:
Y = (((X - x1) * (y2 - y1)) / (x2 - x1)) + y1
Wo Y=y1
wenn X=x1
und Y=y2
wenn X=x2
. x1
, x2
, y1
& y2
kann jeden positive
oder negative
Wert angegeben werden. Definieren Sie den Ausdruck in einem Makro macht es nützlich, es kann dann mit irgendwelchen Argumenten Namen verwendet werden.
#define RangeConv(X, x1, x2, y1, y2) (((float)((X - x1) * (y2 - y1)) / (x2 - x1)) + y1)
Der float
Guss würde Gleitkomma-Division in dem Fall sicherzustellen, in dem alle Argumente integer
Werte.
Je nach Anwendung kann es nicht notwendig sein, die Bereiche x1=x2
und y1==y2
zu überprüfen.
PHP-Port
Gefunden PenguinTD Lösung hilfreich, damit ich es zu PHP portiert. Helfen Sie sich selbst!
/**
* =====================================
* Remap Range
* =====================================
* - Convert one range to another. (including value)
*
* @param int $intValue The value in the old range you wish to convert
* @param int $oMin The minimum of the old range
* @param int $oMax The maximum of the old range
* @param int $nMin The minimum of the new range
* @param int $nMax The maximum of the new range
*
* @return float $fResult The old value converted to the new range
*/
function remapRange($intValue, $oMin, $oMax, $nMin, $nMax) {
// Range check
if ($oMin == $oMax) {
echo 'Warning: Zero input range';
return false;
}
if ($nMin == $nMax) {
echo 'Warning: Zero output range';
return false;
}
// Check reversed input range
$bReverseInput = false;
$intOldMin = min($oMin, $oMax);
$intOldMax = max($oMin, $oMax);
if ($intOldMin != $oMin) {
$bReverseInput = true;
}
// Check reversed output range
$bReverseOutput = false;
$intNewMin = min($nMin, $nMax);
$intNewMax = max($nMin, $nMax);
if ($intNewMin != $nMin) {
$bReverseOutput = true;
}
$fRatio = ($intValue - $intOldMin) * ($intNewMax - $intNewMin) / ($intOldMax - $intOldMin);
if ($bReverseInput) {
$fRatio = ($intOldMax - $intValue) * ($intNewMax - $intNewMin) / ($intOldMax - $intOldMin);
}
$fResult = $fRatio + $intNewMin;
if ($bReverseOutput) {
$fResult = $intNewMax - $fRatio;
}
return $fResult;
}
habe ich diese Lösung in einem Problem, das ich in js wurde die Lösung, so dass ich dachte, ich würde die Übersetzung teilen. Danke für die Erklärung und Lösung.
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;
}
C ++ Variante
fand ich PenguinTD Solution nützlich, so dass ich portierte es zu C ++, wenn jemand sie braucht:
float remap (float x, float omin, schweben OMAX, schweben nMin, float nMax) {
//range check if( oMin == oMax) { //std::cout<< "Warning: Zero input range"; return -1; } if( nMin == nMax){ //std::cout<<"Warning: Zero output range"; return -1; } //check reversed input range bool reverseInput = false; float oldMin = min( oMin, oMax ); float oldMax = max( oMin, oMax ); if (oldMin == oMin) reverseInput = true; //check reversed output range bool reverseOutput = false; float newMin = min( nMin, nMax ); float newMax = max( nMin, nMax ); if (newMin == nMin) reverseOutput = true; float portion = (x-oldMin)*(newMax-newMin)/(oldMax-oldMin); if (reverseInput) portion = (oldMax-x)*(newMax-newMin)/(oldMax-oldMin); float result = portion + newMin; if (reverseOutput) result = newMax - portion; return result; }
Hier einige kurze Python-Funktionen für Ihre Kopieren und Einfügen von Leichtigkeit, einschließlich einer Funktion eine ganze Liste zu skalieren.
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]
, die verwendet werden können, etwa so:
scale_list([1,3,4,5], 0, 100)
[0,0, 50,0, 75,0, 100,0]
In meinem Fall wollte ich eine logarithmische Kurve skalieren, etwa so:
scale_list([math.log(i+1) for i in range(5)], 0, 50)
[0.0, 21,533827903669653, 34,130309724299266, 43,06765580733931, 50,0]
Short-cut / vereinfachte Vorschlag
NewRange/OldRange = Handy multiplicand or HM
Convert OldValue in OldRange to NewValue in NewRange =
(OldValue - OldMin x HM) + NewMin
wayne
ich persönlich die Hilfsklasse verwenden, die Generika (Swift 3 kompatibel)
unterstütztstruct Rescale<Type : BinaryFloatingPoint> {
typealias RescaleDomain = (lowerBound: Type, upperBound: Type)
var fromDomain: RescaleDomain
var toDomain: RescaleDomain
init(from: RescaleDomain, to: RescaleDomain) {
self.fromDomain = from
self.toDomain = to
}
func interpolate(_ x: Type ) -> Type {
return self.toDomain.lowerBound * (1 - x) + self.toDomain.upperBound * x;
}
func uninterpolate(_ x: Type) -> Type {
let b = (self.fromDomain.upperBound - self.fromDomain.lowerBound) != 0 ? self.fromDomain.upperBound - self.fromDomain.lowerBound : 1 / self.fromDomain.upperBound;
return (x - self.fromDomain.lowerBound) / b
}
func rescale(_ x: Type ) -> Type {
return interpolate( uninterpolate(x) )
}
}
Dieses Beispiel wandelt einen Song aktuelle Position in einen Winkelbereich von 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;
}
Hier ist eine Javascript-Version, die eine Funktion gibt, die die Neuskalierung für vorbestimmte Quell- und Zielbereiche der Fall ist, die Berechnungsmenge zu minimieren, die jedes Mal durchgeführt werden muss.
// 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;
}
}
Hier ist ein Beispiel dieser Funktion mit 0-1 in -0x80000000, 0x7FFFFFFF
maßstablet normTo32Fn = makeRangeMapper(0, 1, -0x80000000, 0x7FFFFFFF);
let fs = normTo32Fn(0.5);
let fs2 = normTo32Fn(0);
Liste Verständnis einzeiler Lösung
color_array_new = [int((((x - min(node_sizes)) * 99) / (max(node_sizes) - min(node_sizes))) + 1) for x in node_sizes]
Längere Version
def colour_specter(waste_amount):
color_array = []
OldRange = max(waste_amount) - min(waste_amount)
NewRange = 99
for number_value in waste_amount:
NewValue = int((((number_value - min(waste_amount)) * NewRange) / OldRange) + 1)
color_array.append(NewValue)
print(color_array)
return color_array