So interpolieren Sie Daten in einem Bereich in Google Sheets

9

Ich habe ein Array mit Daten:

   X      Y
   3     50
   5     60
   9    120
  11    130
  18     90
  20    150

Die Daten sind vollständig nicht linear. X wird garantiert sortiert.

Für einen bestimmten Wert möchte ich nun eine lineare Interpolation zwischen den Zahlen (z. B. 3 => 50, 4 => 55, 5 => 60). Eine bilineare Interpolation wäre noch schöner, aber ich halte meine Erwartungen niedrig.

EboMike
quelle

Antworten:

9

Dieses Skript macht dasselbe (plus ein bisschen mehr).

Code

function myInterpolation(x, y, value) {
  if(value > Math.max.apply(Math, x) || value < Math.min.apply(Math, x)) {
    throw "value can't be interpolated !!";
    return;
  }

  var check = 0, index;
  for(var i = 0, iLen = x.length; i < iLen; i++) {
    if(x[i][0] == value) {
      return y[i][0];
    } else {      
      if(x[i][0] < value && ((x[i][0] - check) < (value - check))) {
        check = x[i][0];
        index = i;
      }
    }
  }

  var xValue, yValue, xDiff, yDiff, xInt;
  yValue = y[index][0];
  xDiff = x[index+1][0] - check;
  yDiff = y[index+1][0] - yValue;
  xInt = value - check; 

  return (xInt * (yDiff / xDiff)) + yValue;
}

Erklärt

Am Anfang des Skripts gibt es eine kleine Fehlerbehandlung. Danach wird der erste niedrigste Eintrag im Vergleich zum Eingabewert gefunden. Sobald es gefunden wurde, wird es einige Berechnungen durchführen und das Ergebnis präsentieren.

Hinweis

Wenn der ausgewählte Wert gleich 20 ist, gibt das Skript 150 zurück, wenn die Formel ergibt #DIV/0.

Bildschirmfoto

Geben Sie hier die Bildbeschreibung ein

Formel

Verwenden Sie die folgende Formel, um alle Werte zu berücksichtigen

=IF(
   ISNA(
     MATCH(C2,A2:A7,0)),
   FORECAST(
     $C$2,
     OFFSET(B$2,MATCH($C$2,A$2:A$7,1)-1,0,2,1),
     OFFSET(A$2,MATCH($C$2,A$2:A$7,1)-1,0,2,1)), 
   INDEX(
     B2:B7,
     MATCH(C2,A2:A7,0)
     ,0)
 )

 copy / paste
 =IF(ISNA(MATCH(C2, A2:A7, 0)), FORECAST($C$2,OFFSET(B$2,MATCH($C$2,A$2:A$7,1)-1,0,2,1),OFFSET(A$2,MATCH($C$2,A$2:A$7,1)-1,0,2,1)), INDEX(B2:B7, MATCH(C2, A2:A7, 0), 0))

Beispiel

Fügen Sie das Skript unter Extras> Skripteditor hinzu und klicken Sie auf die Schaltfläche Speichern (keine Authentifizierung erforderlich).

Ich habe eine Beispieldatei für Sie erstellt: So interpolieren Sie Daten in einem Bereich in Google Sheets

Jacob Jan Tuinstra
quelle
2
Danke Jacob! Um ehrlich zu sein, mag ich meine Version fast besser, weil sie auch auf Mobilgeräten funktioniert (die native Android Sheets-App und die mobile Version der Web-App haben keine Skriptunterstützung), aber Ihre Funktion ist definitiv sauberer und eleganter . Also wähle ich deine Antwort.
EboMike
@EboMike Ich habe mir meinen Code angesehen und einen Fehler festgestellt. Ich habe den Code überarbeitet und eine Formel entwickelt, damit Sie sie in Ihrer mobilen App verwenden können.
Jacob Jan Tuinstra
2
Und deshalb ist es bedauerlich, dass Sie eine Antwort nicht mehr als einmal positiv bewerten können :) Danke Jacob.
EboMike
10

Ich habe einen Weg gefunden, es zu tun - es gibt vielleicht einen besseren Weg, aber das habe ich mir ausgedacht:

Angenommen, die Daten befinden sich in A1: B10 und $ C $ 1 enthält den zu suchenden Schlüssel:

=FORECAST($C$1,
    OFFSET(B$1,MATCH($C$1,A$1:A$10,1)-1,0,2,1),
    OFFSET(A$1,MATCH($C$1,A$1:A$10,1)-1,0,2,1))

Im Detail:

FORECAST führt eine lineare Interpolation durch, nimmt jedoch eine gerade Linie an. Wir müssen also die beiden Werte finden, die den gesuchten Wert einschließen.

Also verwenden wir MATCH, um die erste Zahl zu finden, die gleich oder höher ist als die, nach der wir suchen.

FORECAST erwartet einen Datenbereich, daher verwenden wir OFFSET, um einen Verweis auf einen Datenbereich zu erstellen. MATCH ist einindiziert, daher müssen wir zuerst einen subtrahieren. Wir schaffen einen Bereich, der eins breit und zwei hoch ist. Dieser Wert schließt garantiert $ C $ 1, unseren Suchwert, ein.

EboMike
quelle
+1; schöne Formel !! Die Auswahl x=20führt zu #DIV/0.
Jacob Jan Tuinstra
1

Dies ist eine kleine Modifikation des Skripts von Jacob Jan Tuinstra , die es ermöglicht, entweder ein Array oder einen Wert als drittes Argument zu verwenden, sodass die interpolierte Funktion an vielen Stellen gleichzeitig berechnet werden kann. Der einzige Unterschied besteht darin, dass am Anfang einige Zeilen hinzugefügt werden. Dies ist eine schnelle Möglichkeit, so ziemlich jede benutzerdefinierte Funktion in eine benutzerdefinierte Funktion umzuwandeln, die ein Array akzeptiert.

function myInterpolation(x, y, value) {
  if (value.map) {
    return value.map(function(v) {
      return myInterpolation(x, y, v);
    });
  }
  //  the rest stays the same

  if (value > Math.max.apply(Math, x) || value < Math.min.apply(Math, x)) {
    throw "value can't be interpolated !!";
    return;
  }

  var check = 0, index;
  for(var i = 0, iLen = x.length; i < iLen; i++) {
    if(x[i][0] == value) {
      return y[i][0];
    } else {      
      if(x[i][0] < value && ((x[i][0] - check) < (value - check))) {
        check = x[i][0];
        index = i;
      }
    }
  }

  var xValue, yValue, xDiff, yDiff, xInt;
  yValue = y[index][0];
  xDiff = x[index+1][0] - check;
  yDiff = y[index+1][0] - yValue;
  xInt = value - check; 

  return (xInt * (yDiff / xDiff)) + yValue;
}
user135384
quelle