web-dev-qa-db-fra.com

Comment interpoler des données dans une plage dans Google Sheets

J'ai un tableau avec des données:

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

Les données sont entièrement non linéaires. X est garanti pour être trié.

Maintenant, quelle que soit la valeur donnée, j'aimerais une interpolation linéaire entre les nombres (par exemple, 3 => 50, 4 => 55, 5 => 60). Une interpolation bilinéaire serait encore plus agréable, mais je garde mes attentes basses.

7
EboMike

Ce script fera la même chose (plus un peu plus).

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;
}

A expliqué

Au début du script, il existe une petite erreur de traitement. Après cela, il trouvera la première entrée la plus basse par rapport à la valeur saisie. Une fois trouvé, il fera des calculs et présentera le résultat.

Remarque

Si la valeur sélectionnée est égale à 20, le script renvoie 150 comme où la formule donne #DIV/0.

Capture d'écran

enter image description here

Formule

Utilisez la formule suivante pour prendre en compte toutes les valeurs

=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))

Exemple

Ajoutez le script sous Outils> Editeur de script et appuyez sur le bouton Enregistrer (aucune authentification requise).

J'ai créé un exemple de fichier pour vous: Comment interpoler des données dans une plage dans Google Sheets

8
Jacob Jan Tuinstra

J'ai trouvé un moyen de le faire - il y a peut-être un meilleur moyen, mais voici ce que j'ai proposé:

En supposant que les données sont en A1: B10 et que $ C $ 1 contient la clé à rechercher:

=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))

En détail:

PREVISION effectue une interpolation linéaire, mais suppose une ligne droite. Nous devons donc trouver les deux valeurs qui entourent la valeur que nous recherchons.

Nous utilisons donc MATCH pour trouver le premier nombre égal ou supérieur à ce que nous recherchons.

FORECAST attend une plage de données. Nous utilisons donc OFFSET pour créer une référence à une plage de données. MATCH est un indexé, nous devons donc en soustraire un en premier. Nous créons une gamme large et double. Cette valeur est garantie pour inclure $ C $ 1, notre valeur de recherche.

9
EboMike

Ceci est une petite modification de script de Jacob Jan Tuinstra , lui permettant de prendre soit un tableau, soit une valeur comme troisième argument, afin que la fonction interpolée puisse être calculée à plusieurs endroits à la fois. La seule différence est quelques lignes ajoutées au début; c'est un moyen rapide de transformer pratiquement n'importe quelle fonction personnalisée en une fonction personnalisée qui accepte un tableau.

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;
}
1
user135384