Como interpolar dados em um intervalo no Planilhas Google

9

Eu tenho uma matriz com dados:

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

Os dados são totalmente não lineares. X é garantido para ser classificado.

Agora, para um determinado valor, eu gostaria de ter uma interpolação linear entre os números (por exemplo, 3 => 50, 4 => 55, 5 => 60). Uma interpolação bilinear seria ainda melhor, mas estou mantendo minhas expectativas baixas.

EboMike
fonte

Respostas:

9

Este script fará o mesmo (mais um pouco mais).

Código

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

Explicado

No início do script, há um pequeno tratamento de erros. Depois disso, ele encontrará a primeira entrada mais baixa em comparação com o valor de entrada. Uma vez encontrado, ele faz algumas contas e apresenta o resultado.

Nota

Se o valor selecionado for igual a 20, o script retornará 150 como onde a fórmula produz #DIV/0.

Captura de tela

insira a descrição da imagem aqui

Fórmula

Use a seguinte fórmula para levar em consideração todos os valores

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

Exemplo

Adicione o script em Ferramentas> Editor de scripts e pressione o botão Salvar (não é necessária autenticação).

Criei um arquivo de exemplo para você: como interpolar dados em um intervalo no Planilhas Google

Jacob Jan Tuinstra
fonte
2
Obrigado Jacob! Para ser sincero, eu quase gosto mais da minha versão porque ela também funciona em dispositivos móveis (o aplicativo Android Sheets nativo e a versão móvel do aplicativo da Web não têm suporte a scripts), mas sua função é definitivamente mais limpa e elegante . Então, eu estou escolhendo sua resposta.
EboMike
@EboMike Olhei para o meu código e notei um erro. Revisei o código e criei uma fórmula para que você possa usá-lo em seu aplicativo móvel.
Jacob Jan Tuinstra
2
E é por isso que é uma pena que você não possa votar novamente mais de uma vez :) Obrigado Jacob.
EboMike
10

Eu encontrei uma maneira de fazer isso - pode haver uma maneira melhor, mas é isso que eu criei:

Supondo que os dados estejam em A1: B10 e $ C $ 1 contém a chave a ser procurada:

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

Em detalhe:

PREVISÃO faz uma interpolação linear, mas assume uma linha reta. Portanto, precisamos encontrar os dois valores que incluem o valor que estamos procurando.

Então, usamos MATCH para encontrar o primeiro número igual ou superior ao que estamos procurando.

PREVISÃO espera um intervalo de dados, portanto usamos OFFSET para criar uma referência a um intervalo de dados. MATCH é um indexado, então precisamos subtrair um primeiro. Criamos um intervalo de uma largura e duas de altura. Esse valor é garantido para incluir $ C $ 1, nosso valor de pesquisa.

EboMike
fonte
+1; boa fórmula !! A escolha x=20resultará em #DIV/0.
Jacob Jan Tuinstra
1

Essa é uma pequena modificação do script de Jacob Jan Tuinstra , permitindo que ele use uma matriz ou um valor como terceiro argumento, para que a função interpolada possa ser calculada em vários locais ao mesmo tempo. A única diferença são algumas linhas adicionadas no início; Essa é uma maneira rápida de transformar praticamente qualquer função personalizada em uma função personalizada que aceite uma matriz.

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
fonte