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.
Ce script fera la même chose (plus un peu plus).
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;
}
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.
Si la valeur sélectionnée est égale à 20, le script renvoie 150 comme où la formule donne #DIV/0
.
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))
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
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.
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;
}